Order matters, and the API enforces it: a collection must finish provisioning
(
active) before you can add units, and pairing a chip is what issues the
unit - it assigns the serial and flips the unit from pending to active.1
Create a collection
A collection is a product line or drop. Create it once; every unit inside it shares its serial-number namespace.
The collection is returned at the top level (as are all single-resource responses - see Response shape). Poll
POST /v1/collections returns immediately with contract.status: "deploying" - provisioning is asynchronous.Response
Response
GET /v1/collections/{collection_id} until contract.status is "active" before adding units (a short interval; give up after a reasonable timeout). Creating a unit too early returns collection.not_active.Only name is required - the collection is created on your organization’s default network, configured by Endstate at onboarding. The optional fields:string
Your own identifier for the collection, unique within your organization. The
example above sets it so a re-run can look the collection up instead of
creating a duplicate (see Re-runs and conflicts).
string
Where a tap on any of this collection’s items sends the user. See Tap
redirects.
string
A short display symbol, 1-4 characters. Derived from
name when omitted.integer
Override the default network. The value must be one of the networks enabled
for your organization (
allowed_chain_ids from Organization
settings); otherwise the API returns
validation.failed.2
Create a unit for each item
A unit is the digital record of one physical item. Create one per item with The unit starts with
POST /v1/units, using the active collection’s id.token.status: "pending" and no serial - both are set when you pair a chip in the next step.Set external_id to your own SKU or serial so you can look the unit up later (GET /v1/units?external_id=...) without storing Endstate IDs. There’s no bulk endpoint - loop the call to register every item ahead of time, before they ship.3
Pair a chip (this issues the unit)
Pairing links a specific NFC chip to a specific unit and triggers issuance. A chip is permanently bound to one unit - it cannot be re-paired (
Test chip (development). Pass Pairing returns the assigned
chip.already_paired). If a paired chip is damaged before the item ships, don’t re-pair it - replace the unit’s chip with a fresh one.Encoded chip (production). Do this during fulfillment, after the chip is encoded and before the item ships. Supply the chip_id (10 hex characters) and e (32 uppercase hex characters) from your encoding step.Response
Response
is_test: true and Endstate assigns the chip_id - no hardware needed. Generate tap values for it later with POST /v1/test-helpers/taps. See Test without hardware.chip_id at the top level (the value to use for a test chip’s taps). Issuance is asynchronous and has no failure status - poll GET /v1/units/{unit_id} until collection.token.status is "active"; the unit’s collection.token.serial is set at that point. If it stays pending well beyond a few minutes, stop polling and contact support.Re-runs and conflicts
external_id makes setup safe to re-run. If a step reports a conflict, look the existing resource up by its external_id and reuse it instead of creating a duplicate.
Branch on error.code (never the message or HTTP status):
See Errors for the full envelope.
Next steps
Verify a unit
Now that items are registered, handle the user tap and verify authenticity
end to end.
Tap redirects
Send users to your own page after a tap - per unit, per collection, or
org-wide.

