chip_id that identifies the chip and a one-time credential called an e value. You send those to the API, and Endstate confirms the item is authentic.
What a chip is
A chip is a physical NTAG 424 DNA NFC tag bonded to a single product. Every chip has achip_id — a 10-character hex string (e.g., ABCDEF0123) that appears in the tap URL your application receives. The chip_id is stable and public; it identifies the chip but does not prove a tap happened.
Each chip is paired to exactly one unit. Pairing is permanent on the chip’s side — a chip cannot be re-paired to a different unit. The unit’s side can still change until the item is claimed: a unit’s chip can be swapped for a new one via chip replacement, which retires the old chip rather than moving it.
Chips track scan_count: the number of times a tap has been successfully verified. This count increments each time a valid verification request completes (unless dry_run is used).
Two kinds of chips
Encoded chips are genuine NTAG 424 DNA NFC hardware. You supply the
chip_id and a valid initial e value read from the chip when pairing it to a unit.
Test chips are simulated — no physical hardware required. Create one with is_test: true and then call POST /v1/chips/{chip_id}/tap to generate a fresh e value you can use in a verify request. Test chips let you run the full verification flow in development without having NFC hardware in hand. See Testing without hardware for the complete walkthrough.
The e value
Every tap produces a fresh e value — a 32-character hex string included in the tap URL alongside the chip_id. Treat the e value as a credential:
- Single-use. Once a verify request succeeds with a given
e, that value is consumed. Submitting it again returnschip.already_scanned(HTTP 410). - Never log it. The
evalue proves a tap occurred; logging it creates a replay risk. - Short window. Pass it to the verify endpoint promptly after receiving it.
Pairing a chip
Before a chip can be verified, it must be paired to a unit — this is what links the physical hardware to its digital record.POST /v1/chips is the pairing primitive: it binds a chip’s chip_id and initial e value to a unit_id.
Build your own pairing experience
Integrate the pairing API into your existing application and call it however fits your operation:- Pre-pair during fulfillment. Read the chip’s
chip_idandeat encoding time and pair it before the product ships. This is the canonical path for a production catalog. - Pair from your own app. Read chips directly with an NFC chip reader to capture each chip’s
chip_idande, then pair them through your own interface — your staff or users never leave your application. You can also have Endstate redirect taps on an unpaired chip to your app, so a tap drops the holder straight into your pairing flow.
Use Endstate’s hosted pairing screen
If you would rather not build your own, Endstate hosts a pairing screen. Physical chips ship pre-encoded to tap to a verify URL —https://<your-domain>/verify/<chip_id>?e=<e>. When a chip that has not been paired yet is tapped, the holder is routed to that screen, which binds the chip to a unit. The pairing it creates is part of the same system you read through this API — the chip and unit then appear in GET /v1/chips and GET /v1/units.
A chip is permanently bound to one unit. However it is paired, a chip cannot
be re-paired to a different unit. If a unit’s chip is damaged before the item
is claimed, replace the unit’s chip — the old chip is
retired, never reused.
After a chip is paired
Tapping a paired chip redirects the user to your verified domain — theredirect_url returned by the verify call. That is where you run your verified experience.
Replacing a chip
Until a unit is claimed, you can replace its chip — pair a new chip and retire the current one. Use this when a chip is damaged or fails QA after pairing but before the item reaches its owner.- The replacement chip must already exist in your organization and be unpaired. This call never creates a chip — an unknown
new_chip_idreturnschip.not_found, and a chip that is already paired (to this unit or any other) returnschip.already_paired. - The unit must be issued and not yet claimed. An unissued unit returns
unit.not_minted; once the unit is claimed its chip is permanently locked and replacement returnschip_replacement.locked. - One replacement can be open per unit at a time — a second attempt while one is settling returns
chip_replacement.in_progress. - Endstate performs the swap for you. Replacement is asynchronous; there is no client-broadcast mode. Requires an API key.
GET /v1/units/{unit_id}/chip-replacements/{replacement_id} until the replacement settles:
Once
confirmed, the new chip verifies for the unit and appears in the unit’s chips; the retired chip is detached from it.
What verification does
Verification is the act of confirming a physical product is authentic by validating the tap’se value. The flow:
- A user taps the product. The tap URL delivers
chip_idandeto your application. - Your server calls
POST /v1/chips/{chip_id}with theevalue in the request body. - Endstate validates the credential against the chip, confirms the item is authentic, increments
scan_count, and returns the unit’s metadata plus a session token.
Verify a tap
Request
Request fields
The one-time credential from the tap URL. Must be 32 hex characters.
Single-use — submitting a previously used
e returns chip.already_scanned.When
true, Endstate validates the e value but does not record a scan or
issue a session token. Use this to confirm a tap is valid before committing
it. Defaults to false.Lifetime of the issued session token in seconds. Accepted range:
60–3600.
Defaults to 600 (10 minutes). Has no effect when dry_run is true.Response
Response fields
The unique ID of this scan record (UUIDv4).
null when dry_run is true —
no scan record is created.An object containing
token (the end_sess_... string), expires_at (ISO
8601 expiry timestamp), and scope (chip_id, unit_id, organization_id).
The token string proves this chip was just tapped — pass it to GET /v1/session-tokens/current from a client to
confirm its scope without exposing your API key. null when dry_run is
true.The chip that was tapped.
The unit this chip is paired to, including its metadata and issuance status.
The canonical verified-domain URL for this chip
(
https://<your-verified-domain>/verify/<chip_id>), or null if your
organization has no verified domain. You can redirect users here after a
successful tap. Despite the shared name, this is not the tap
redirect you configure on units and collections —
that one controls where Endstate’s hosted tap flow sends the user before
verification.Echoes the
dry_run request flag. When true, no scan was recorded and no
session token was issued — id and session_token are null.Error codes
Chip endpoints
For full request/response schemas, see the API reference.
Next steps
Session tokens
Understand what the session token proves and how to introspect it from a
client.
Verify a unit
Step-by-step guide to the full tap-to-verification flow.
Testing without hardware
Use test chips to run the full verification flow without NFC hardware.
API reference
Complete endpoint reference for chips and all other resources.

