Skip to main content

Updates, deletes & concurrency

Organization entities (sectors, cost centers, job roles, groups, employees, products) support create, update, and delete. Writes use optimistic concurrency so two integrations editing the same record can never silently clobber each other.

The version token — the ETag header

Every read and write response carries the record's current version in a strong ETag response header (e.g. ETag: "4"). To update or delete a record, send that value back in an If-Match request header. The server applies the change only if the version still matches; otherwise it returns 409 and changes nothing.

The version is exposed only through the ETag header — it is never included in the response body.

# 1. Read the record; capture its ETag (use -i to see response headers)
curl -i "https://{host}/v1/sectors/sec_123" -H "Authorization: Bearer sk_…"
# → HTTP/2 200
# → ETag: "4"
# → { "data": { "id": "sec_123", "name": "Welding", … } }

# 2. Update, echoing the ETag back as If-Match
curl -X PUT "https://{host}/v1/sectors/sec_123" \
-H "Authorization: Bearer sk_…" \
-H 'If-Match: "4"' \
-H "Content-Type: application/json" \
-d '{ "name": "Welding & Cutting" }'
# → HTTP/2 200
# → ETag: "5" (the new version after your change)

If someone else updated sec_123 between your read and your write, its version is now 5, your If-Match: "4" is stale, and you get a 409. Re-read to get the fresh ETag, reapply your change on top of the fresh record, and retry.

tip

You may instead send the version in the request body as "_version": 4. The If-Match header is preferred (it's the standard HTTP mechanism and keeps the body purely your data), but both are accepted. If the version is missing on an update or delete, the request is rejected with 400.

Partial updates — no blanking

An update changes only the fields you send. Fields you omit are left exactly as they were — there is no "replace the whole record" semantics, so you cannot accidentally blank a field by leaving it out.

Delete

DELETE removes the record: it stops appearing in lists and GET-by-id then returns 404. Delete also requires the current version via If-Match, and returns 200 with the deleted record in the body (not 204):

curl -X DELETE "https://{host}/v1/sectors/sec_123" \
-H "Authorization: Bearer sk_…" \
-H 'If-Match: "5"'
# → HTTP/2 200
# → { "data": { "id": "sec_123", "name": "Welding & Cutting", … } }

Delete is blocked while the entity is still referenced

You cannot delete an entity that other records still point at — that would orphan those references. If, say, an employee still has a sectorId of the sector you're deleting (or a group still lists a product in its rules), the delete is rejected with 409 (type: urn:smartepi:error:resource_in_use) and nothing changes. Re-point or remove the dependents first, then delete. Deleting a product cascades to its own sizes and certificates, which is allowed.

Foreign keys

Any foreign key you set on a create or update must exist in your organization, or the write is rejected with 422 (see Errors). This keeps writes from ever referencing data that isn't yours.