Best practices
Guidance for building with the Records API. Endpoint pages describe what each call does; this page recommends how to combine them.
See the Get Records API for the record model.
Reference by ID, not name
record_type_id and field_id are stable; names can be renamed at any time. Discover the schema once via the List record types API, cache field IDs by name, and refresh on 404. The Query API also accepts field_name — use it only for ad-hoc queries.
Use /records/query for aggregations
For counts, sums, averages, or grouped breakdowns, call the Query API. It answers in one request with its own rate-limit budget. Only reach for the List API when you need the individual rows.
Only request what you need
- Pass
record_field_idson Get or List to return only the columns you need. - Artifacts come back as
{ id, is_artifact: true }references. On Get, Create, and Update you can passresolve_artifacts=trueto inline the contents — only do this when you need them now. List always returns references with no inline option, so fetch them lazily via Get artifact when you need the value. - Child records come back as ID stubs. Set
include_children=trueonly when you need their fields. Useparent_idson List to fetch children in one request.
Paginate deliberately
per_page defaults to 20 and caps at 500. Filter and sort server-side (filters, order_field_id), follow meta.next_page, and bound the total pages your client will walk.
Filter operator gotchas
IS_ANY_OF/IS_NONE_OFaccept up to 10 values — prefer them over repeatedEQUALrequests.CONTAINS,STARTS_WITH,ENDS_WITHneed three-plus characters and one pattern filter per request.- Values compare as strings, case-insensitively — a JSON
truematches"true". Store fields as strings if you plan to filter on them. ARTIFACTfields cannot be filtered.
Handle rate limits and retries
The Records API is rate-limited (API rate limits); record and query limits are separate. On 429, back off exponentially with jitter and a max attempts cap.
Retry safety:
POST /recordsis not idempotent — a retry after a timeout or connection drop can create a duplicate. Dedupe on a natural key, or verify with a follow-up read before retrying.PUTandDELETE /records/{id}andPOST /records/queryare safe to retry.
Use test_mode for test data
Pass test_mode: true on writes from staging or test workflows. Test records are excluded from live listings and aggregations unless you pass test_mode=true on List or Query.
Attaching records to cases from the record side
For status, comments, fields, or Cases-only reads, use the Cases API.
Configure retention explicitly
Set ttl_days, retention_column_name, max_records_limit, and on_limit_reached at creation time (see Create record type):
- Enrichment cache:
retention_column_name: "UPDATED_AT",on_limit_reached: "EVICT_OLDEST". - Audit trail:
retention_column_name: "CREATED_AT",on_limit_reached: "REJECT".
Common errors
| Status | Typical cause |
|---|---|
| 400 | Malformed request — filters not valid JSON, unknown field, disallowed operator. |
| 404 | Record, type, or field not found — or the token can't see it. Under-privileged tokens return 404, not 403. |
| 422 | Validation failure — TEXT_ENUM value not in fixed_values, updating a record whose record type isn't editable, circular parent. |
| 429 | Rate limited — back off. |
| 504 | Query API exceeded 30s — narrow filters or time range. |
Treat 404 on a resource you expect to exist as a scope check on the API key.