1
Set up and pair your items
Before any taps, each item needs a collection, its own unit, and a paired chip - a one-time setup you run during fulfillment, not at tap time. The Set up your catalog guide covers it end to end: create the collection, create a unit per item, and pair the encoded chip (which issues the unit and assigns its serial).Two things to carry into the verify flow below:
- On every tap, the chip’s tap URL carries the
chip_idand a fresh one-timee. Theeyou supplied at pairing comes from encoding and is consumed then - it is not the tape. - A chip is permanently bound to its unit. A chip can also be paired the first time it is tapped, through a hosted pairing screen - see Pairing a chip, including how to route unpaired taps to your own system.
2
The user taps
When a user taps the NFC chip on the item, the chip generates a fresh one-time The format of this URL is fixed by the chip’s encoding. Your job is to extract
e value and opens a URL. That URL carries both the chip_id and the new e as parameters - for example:chip_id and e from it (or from the query parameters your app receives when the user is redirected to your domain) and forward them to your backend immediately.The e value is a credential. Treat it accordingly:- Do not log it.
- Do not store it at rest.
- Pass it to the verify endpoint promptly - it is single-use and has a short validity window.
chip_id and e to your own server, which makes the verify call using your API key. If you have no server to run, the same call can be made from the page with a publishable key instead - see Host your own verify page.Reading the tap in a browser is non-trivial. Endstate ships no browser NFC
SDK - the tag is standard NFC. Web NFC (
NDEFReader) works only on Android
Chrome (secure context + user gesture); desktop needs a USB/PC-SC reader
driven over WebUSB/WebHID; iOS Safari has no in-browser tap path. The
tag’s payload is just a URL - read the NDEF record, extract the URI, then pull
chip_id + e from it.A raw tap URL is often a short Endstate URL that 302-redirects to the
destination, with the params on the redirect target. If you resolve a tap URL
server-side, follow the redirect and read the params off the
Location
header - fetch(url, { redirect: "manual" }).3
Verify the tap
Your backend calls
Here is what each field tells you:
POST /v1/taps with the chip_id and the e value - plus the c value whenever the tap URL includes one. This is the core verification call. A successful response is non-replayable proof that the physical chip was tapped moments ago.Response
Response
string
The unique tap record ID. Log it alongside the
X-Request-Id response header
for support requests. It is the same id that GET /v1/taps returns for this
tap.integer
The total number of successful verifications for this chip, including this
one. A value of
1 means this is the first successful tap. Higher values mean
the item has been verified before. Your application decides what a high count
means - Endstate records the count but does not set policy on it.object
The digital record for the verified item, including any
name, external_id,
and attributes you set when creating it. Issuance status and serial number
are nested under unit.collection.token - status: "active" and a serial
value confirm the unit is fully issued. Use this data to render an item detail
view.object
Contains a short-lived
token string (end_sess_...) that proves this
specific chip was just tapped. Valid for 600 seconds by default. Pass the
token string to a browser or mobile client. See the next step.string | null
The canonical page to send the user to after a successful tap, or
null if
your account has no verified domain configured. When present, you can redirect
the user here directly; the URL already carries the context needed to display
the correct item.4
Hand the session token to your client
The
This tells the client exactly which chip was tapped, which unit it belongs to, and when the session expires. The client can use this to confirm scope without a second round-trip to your server.The default session lifetime is 600 seconds. If your user flow needs more or less time, pass
session_token from the verify response is designed to cross the server-client boundary safely. Your API key (end_sk_...) must never leave your server - but the session token can.After verifying the tap server-side, pass the token string from the session_token object to your browser or mobile client. The client can then call GET /v1/session-tokens/current using that token string as its bearer credential:Response
Response
ttl (integer, 60 to 3600) in the verify request body. ttl requires a secret key - a browser using a publishable key always gets the default.See Session tokens for the full security model and use cases.Handle failures
Branch onerror.code - never on HTTP status or message. The three codes specific to chip verification are:
422
The
e value is malformed or does not match this chip.Do not retry with the same e. Have the user tap again to produce a
fresh one.410
This
e was already used in a prior verify call.Do not retry. A replay means either a duplicate request from your code or
an attempted tap replay - investigate before proceeding.404
No chip with this
chip_id exists in your organization.The chip_id in the tap URL does not match any paired chip. Check that
pairing completed successfully.The session token also authorizes claiming a unit on behalf of the user
who tapped - handing it to a recipient. See Claims for the
full flow, execution modes, and status polling.
Next steps
Claim a unit
Transfer ownership of the verified unit to a recipient, authorized by the
session token.
Session tokens
Understand the credential you just received and how to use it on a client.

