Skip to main content

Importing Data

Write records to an existing Form using the REST API or a CSV import. For the shared data model and ownership rules, start with Managing Data. To create identities first, follow Creating Members.

Before you begin​

You need the target Workspace UUID, Form's DataType ID, published field slugs, and a credential authorized to create or update its records. Configure the Form with the Forms guide or the DataTypes API.

The examples assume a synthetic Form with a text field named status. Set GRAVITYRAIL_API_KEY, GRAVITYRAIL_WORKSPACE_UUID, and GRAVITYRAIL_DATA_TYPE_ID to your test configuration. Do not send patient data until the PHI prerequisites are satisfied.

Create a record​

curl --fail-with-body --request POST \
"https://api.gravityrail.com/api/v2/w/${GRAVITYRAIL_WORKSPACE_UUID}/data-types/${GRAVITYRAIL_DATA_TYPE_ID}/records" \
--header "Authorization: Bearer ${GRAVITYRAIL_API_KEY}" \
--header "Content-Type: application/json" \
--data '{"fieldValues": {"status": "new"}}'

Use field slugs in fieldValues. The schema validates field types, required values, and validation rules. Set memberId or memberExternalId when writing for another Member; that requires the appropriate record-writing scope and access. For workspace-scoped records, omit Member ownership.

Inspect the returned record ID and values, then verify the record in the Form's entries. Use PUT /data-types/{data_type_id}/records/{record_id} to update a known record by ID.

Update by external ID​

Use the dedicated upsert endpoint when a repeated synchronization should update the same record:

curl --fail-with-body --request POST \
"https://api.gravityrail.com/api/v2/w/${GRAVITYRAIL_WORKSPACE_UUID}/data-types/${GRAVITYRAIL_DATA_TYPE_ID}/upsert/integration-record-001" \
--header "Authorization: Bearer ${GRAVITYRAIL_API_KEY}" \
--header "Content-Type: application/json" \
--data '{"fieldValues": {"status": "active"}}'

A matching external ID updates the record; no match creates one. External-ID operations require the Form's external-ID permission as well as the applicable record access. A plain record-creation request is not a general upsert substitute.

For a JSON batch, use POST /data-types/{data_type_id}/records/bulk and its explicit upsert option. The DataRecords API owns batch schemas, limits, and per-record outcomes.

Import a CSV​

For the product's upload controls, follow Import and export. For a programmatic upload, prepare headers using field names or slugs:

status,External ID
new,integration-record-001
active,integration-record-002

Then upload the file:

curl --fail-with-body --request POST \
"https://api.gravityrail.com/api/v2/w/${GRAVITYRAIL_WORKSPACE_UUID}/data-types/${GRAVITYRAIL_DATA_TYPE_ID}/import" \
--header "Authorization: Bearer ${GRAVITYRAIL_API_KEY}" \
--form "file=@records.csv"

Import begins when submitted. The response counts every data row once in outcomes — created, updated, unchanged (matched a record and changed nothing) and failed — alongside imported_count (created + updated + unchanged), total_rows and up to ten row errors. success is false when any row failed, and the response is still HTTP 200. Correct rejected rows before resubmitting; rows that already committed come back unchanged. Keep logs to counts and record IDs; row values and diagnostic response bodies can contain sensitive data.

Columns and matching​

ColumnUse
A field name or slugMap the cell to that field. A header matching multiple fields is rejected.
Record IDThe record UUID a Gravity Rail export writes. Updates that record — only a record in this Form and workspace that you can edit. A Record ID matching no such record fails the row; it never falls back to the External ID or creates a record. A Record ID repeated later in the file fails the later rows. A numeric Record ID from an older export never selects a record: the row may still update its External ID match, and otherwise fails — export again. Any other non-blank Record ID (neither a record UUID nor a whole number) fails the row. A file with two Record ID columns is rejected whole.
External IDWithout a Record ID: update the exact matching record, or create a record when it has no match. Beside a Record ID it must equal that record's External ID. Requires external-ID permission.
Member IDSet Member ownership for Member-scoped records. Writing for another Member requires records:write; workspace-scoped records reject this column's values.
Created At, Updated AtRecognized export metadata; never written.
Gravity Rail Export v1Preserve this marker on a Gravity Rail export so its encoded cells are read back correctly.

An unmarked file trims surrounding whitespace. Blank cells omit the field: creation uses applicable defaults; updates retain existing values. A marked Gravity Rail export preserves its exported cell values and reverses spreadsheet formula escaping. Re-importing an unedited export updates each row's own record and creates nothing. To add copies of exported rows, clear their Record ID (or remove the column) and clear any External ID that matches an existing record; rows with neither create new records. Keep the marker when round-tripping lists and objects.

Import limits​

Rejection scopeConditions
Whole file; no rows importedOver 10 MB, over 10,000 data rows, over 1,000 columns, unknown or ambiguous headers, repeated columns for one field, or two Record ID columns.
Individual rowInvalid field values or validation rules, a Record ID that is neither a record UUID nor a whole number, values over 5,000 characters, External IDs over 255 characters, or conflicting record identity/ownership.

A rejected row saves none of that row's values; other valid rows can succeed. Do not assume a partially successful file is an all-or-nothing transaction.

Verify a synchronization​

Read back the returned record ID or list records through the DataRecords API, and check the intended values in the Form. Repeat one synthetic upsert with the same external ID: confirm that it updates the intended record before running a larger import.

For outgoing changes, use Exporting Data. To upload file bytes, use the Files API; a file URL in a Form field does not upload its content.