Idempotency

Use a stable Idempotency-Key for writes that create durable request receipts, and follow each endpoint's documented retry behavior.

POST /notes, POST /contacts, POST /customers, POST /suppliers, parent-scoped customer location/address and document creates, supplier ship-from creates, product creates, product-family creates, Cost Book updates, Cost Book corrections and batches, and Price Book updates require Idempotency-Key. Repeating the same route plus the same key and same request body returns the original record or ordered batch result. Reusing the same key with a different intended update returns a conflict.

Tag vocabulary and assignment changes use the requested state itself for safe repeats. POST /tags, PATCH /tags/{id}, and POST or DELETE /tag-assignments require neither Idempotency-Key nor If-Match; their changed fields show whether a repeat altered the saved grouping.

Certificate and COA retries

Certificate filing and lot COA assignment use the saved dates and document for safe repeats. POST /certification-records, PATCH /certification-records/{recordId}, and PUT /lots/{id}/coa do not require Idempotency-Key; an identical request returns unchanged. Changed certificate PATCH requests use the record's current updatedAt as If-Match; a COA replacement uses the returned COA version. See Certification Intelligence and Lots for the complete retry rules.

Key format

Build the key from stable source facts.

<source-system>:<source-event-id>:<target-type>:<target-id>:<action>

Examples:

gmail:thread-18f0:customer:customer-id:create-note
gmail:thread-18f0:customer:customer-id:create-contact:jane@example.com
call:recording-77:supplier:supplier-id:create-note
crm:lead-1842:customer:create-profile
crm:site-742:customer:customer-id:create-location
intake:doc-913:create-product
intake:doc-913:create-product-family
intake:file-482:purchase-order:purchase-order-id:attach
quote:2026-0819-line-2:price-book:customer-id:update
cost-review:2026-0901:cost-book:entry-id:correct
cost-review:2026-0901:cost-book:approved-batch-4
Warning

Do not use timestamps or random ids unless the source event is genuinely unique. A random key per retry disables replay protection.

Note replay

curl "$SHELFCYCLE_API_BASE_URL/notes" \
  -X POST \
  -H "Authorization: Bearer $SHELFCYCLE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: gmail:thread-18f0:customer:customer-id:create-note" \
  -d '{ "primarySubject": { "type": "customer", "id": "customer-id" }, "noteType": "EMAIL", "title": "Inbound thread", "body": "Approved summary." }'

First successful request:

{
  "data": {
    "id": "note-id",
    "type": "note",
    "idempotencyStatus": "created"
  }
}

Same key and same body:

{
  "data": {
    "id": "note-id",
    "type": "note",
    "idempotencyStatus": "replayed"
  }
}

Same key and different body:

{
  "error": {
    "type": "conflict_error",
    "code": "idempotency_key_reused",
    "message": "The Idempotency-Key was reused with a different request body.",
    "requestId": "request-id"
  }
}

Contact, profile, child-record, and product replay

POST /contacts, POST /customers, POST /suppliers, parent-scoped child creates, POST /products, and POST /product-families follow the same rule. A duplicate created through a matching idempotency key replays. A different key whose identity fields match an existing record can return 409 duplicate_contact, 409 duplicate_customer, 409 duplicate_supplier, 409 duplicate_customer_location, 409 duplicate_customer_address, 409 duplicate_supplier_ship_from_location, 409 duplicate_product, or 409 duplicate_family.

Price Book review and replay

Price Book uses the same stable key from POST /price-book-entries?dryRun=true through the reviewed execution. Add the preview's expectedAffectedEntryIds and expectedPlanToken to the execution body. If the execution response is lost, replay that exact execute request with the same key and body to recover the original saved entry.

If ShelfCycle reports that the reviewed plan is no longer current, run a new preview and review its affected entries before applying it. Keep the original key only for an identical replay of the original intended update.

Cost Book corrections and batch replay

Cost Book POST, PATCH, and batch requests use a stable Idempotency-Key. Keep the key and body unchanged from preview through execution. A correction replay returns the original replacement entry. A completed batch replay returns the same ordered item results.

If a batch is interrupted, repeat the identical request with the same key. Completed items are returned from the saved receipt and only pending items continue. Each item also needs a stable, unique clientItemId so the ordered results remain tied to the caller's source rows.

Attached-document replay

Product, customer, supplier, and purchase-order document routes use the same replay rule. A newly uploaded file attachment returns data.integrity with the verified checksum, size, content type, and verification time. Replaying the exact route, key, and body returns the same stored integrity receipt without depending on a new file check.

Keep that receipt with the source event so a workflow can reconcile a lost response without creating another attachment. See Attached documents for the complete response.

Retry rule

On network failure or 429 rate_limited, retry the same idempotent request with the same key and same body. Price Book execute retries must also keep the reviewed plan fields unchanged. Cost Book batch retries must keep item order and every clientItemId unchanged. If a caller changes the intended update, treat it as a new source event and choose a new stable key.