Records: Create
Description
Create a record of a single record type, setting field values and an optional parent. The created record is returned in the same data / field_ids envelope as the Get record API.
Send an Idempotency-Key header to make the create safe to retry (see Idempotency).
To discover the record_type_id and field IDs to reference, use the List record types API. See the Get record API to learn more about records.
Request
HTTP Method: POST
URL: https://<tenant-domain>/api/v2/records
| Header | Required | Description |
|---|---|---|
| Idempotency-Key | No | An opaque key, at most 255 characters, that makes the create safe to retry (see Idempotency). |
The request body is a JSON object with the following fields:
| Body parameter | Required | Description |
|---|---|---|
| record_type_id | Yes* | Numeric record type ID. Provide this or record_type_name. |
| record_type_name | Yes* | Record type name or slug. An alternative to record_type_id. |
| field_values | No | An array of field values to set (see Field values). Fields you omit take their default or empty value. |
| parent_id | No | ID of the parent record to nest this record under. Omit for a top-level record. |
| test_mode | No | JSON boolean sent in the request body. When true, create the record in test mode. Defaults to false. |
*Provide at least one of record_type_id or record_type_name. If you send both, record_type_id takes precedence. If record_type_name matches more than one record type, the request fails with a 400; supply record_type_id to disambiguate.
An unknown body or query parameter returns a 400. When supplied, field_values must be an array; null returns a 400.
Field values
Each entry in field_values sets one field and takes one of field_id or field_name, never both, and each field may appear at most once:
| Key | Required | Description |
|---|---|---|
| field_id or field_name | Yes | The field to set, by numeric field_id or by field_name (its name or slug; matching is insensitive to case and separators). |
| value | Yes | The field's typed value. Send null to clear the field. |
value holds the field's typed value: a string, number, boolean, or ISO 8601 timestamp for scalar fields; a JSON object or array for JSON fields; and a (large) text string for ARTIFACT fields.
Timestamps. TIMESTAMP field values are stored in UTC. Unlike v1, v2 converts an offset you send to the equivalent UTC instant — 2026-08-13T19:08:15-04:00 is stored as 2026-08-13 23:08:15. A value without an offset is stored as the literal wall time. Send a Z-suffixed UTC timestamp to avoid ambiguity.
Example request
curl --proto '=https' --tlsv1.2 \
-X POST \
"https://<tenant-domain>/api/v2/records" \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <<CREDENTIAL.tines_api_key>>' \
-d '{
"record_type_id": 42,
"field_values": [
{ "field_name": "status", "value": "open" },
{ "field_id": 103, "value": { "event_id": 1 } }
],
"parent_id": 555
}'
Idempotency
POST /api/v2/records creates a new record on every successful call, so a blind retry after a timeout or network error can produce a duplicate. To make a retry safe, send an Idempotency-Key header with a unique value:
curl --proto '=https' --tlsv1.2 \
-X POST \
"https://<tenant-domain>/api/v2/records" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: <unique-key-per-create>' \
-H 'Authorization: Bearer <<CREDENTIAL.tines_api_key>>' \
-d '{ "record_type_id": 42, "field_values": [] }'
- Generate the key once per logical create (for example a random UUID) and reuse that same value on every retry of that write — don't mint a new key per attempt, and don't share one key across different records.
- A repeat with the same key and the same body replays the original response instead of creating a second record.
- Reusing the same key with a different body returns a
422(idempotency_key_reuse). - A retry sent while the first request is still in flight returns a
409(idempotency_in_progress); retry once the original completes. - If the record from the original request has since been deleted, a replay returns a
410(idempotency_target_deleted) instead of creating it again. - Keys are scoped to your user within the tenant, are at most 255 characters, and expire after 24 hours.
Response
A successful request returns 201 Created with a JSON object containing a data object representing the created record and a field_ids map.
Field description
| Field | Description |
|---|---|
| data | The created record object (see below). |
| field_ids | Map of each returned field's slug key to its immutable field ID, so callers can pin to the ID across renames. |
The data object contains:
| Field | Description |
|---|---|
| id | Integer ID of the record. |
| fields | Field values keyed by field slug. Scalar fields hold their typed value; TIMESTAMP fields are ISO 8601 strings; artifact-backed fields return a handle (see Artifact-backed fields). |
| relationships | record_type ({ "id" }) and parent_record ({ "id" }, or null when the record has no parent). |
| created_at | ISO 8601 creation timestamp (UTC). |
| updated_at | ISO 8601 last-updated timestamp (UTC). |
Artifact-backed fields
JSON and ARTIFACT field values are never inlined in a write response, whatever their size. Each is returned as a handle:
{ "expandable": true, "href": "/api/v2/records/<id>/fields/<field_id>" }
Follow the href with the Get record field API to retrieve the full value.
Sample response
{
"data": {
"id": 556,
"fields": {
"status": "open",
"payload": {
"expandable": true,
"href": "/api/v2/records/556/fields/103"
}
},
"relationships": {
"record_type": {
"id": 42
},
"parent_record": {
"id": 555
}
},
"created_at": "2026-07-02T00:00:00Z",
"updated_at": "2026-07-02T00:00:00Z"
},
"field_ids": {
"status": 101,
"payload": 103
}
}
Errors
Errors are returned as a JSON object with an error field, along with an appropriate HTTP status code:
{
"error": {
"type": "bad_request",
"message": "record_type_id or record_type_name is required",
"field": "record_type_id"
}
}
| Status | Meaning |
|---|---|
| 400 | Invalid request — malformed body, unknown parameter, an invalid or duplicated field reference, a blank parent_id, a non-boolean test_mode, or a blank/over-length Idempotency-Key. |
| 403 | The tenant does not have access to records, or the caller lacks permission to create records of this type. |
| 404 | Record type or parent record not found, or the calling token does not have access to it. |
| 408 | The write timed out. Retry the request (with the same Idempotency-Key if you sent one). |
| 409 | An Idempotency-Key request with the same key is still in flight (idempotency_in_progress). |
| 410 | The record created by this Idempotency-Key was deleted (idempotency_target_deleted). Do not retry with a new key unless you intend to create another record. |
| 422 | The record could not be created — for example a field value failed validation (including an impossible timestamp date), a non-JSON field received an object or array, the parent is in a different mode, or the Idempotency-Key was reused with a different body (idempotency_key_reuse). |
| 503 | Idempotency could not be verified before the create (idempotency_unavailable). Retry the request. |
The error object always carries type and message; validation errors add a field pointer, and some add a hint suggesting a correction.