opaque_id. You store that id against your own user record and use it for every later proposal.
The opaque_id looks like OP_QDhs65484684. It is pairwise: it identifies this human to your agent only. It is not a global user id, it carries no personal data, and it does not work with any other agent, including another agent of your own.
These two operations are not part of the generated API reference or the TypeScript SDK. Call them over HTTP as shown here. Both authenticate with your agent key, and both use the standard envelope: HTTP 200 with the payload at
data.data, or a handler error at data.error.1. Start the link
POST https://api.botshield.ai/operations/agent/bind-session
string
Optional. How your agent is named on the user’s link screen, 1–80 characters. Defaults to the agent name you registered.
string
Optional, 1–256 characters. Your own reference for this person, the same value you send as
partner_user_id to BotShield Gate. If that person has verified with you before, BotShield can also notify their phone about the link request. The response is identical whether or not a match exists.Response
string
Always
pending.string
Six characters from digits and uppercase letters. The letters I, L, O, and U are never used, so a code read aloud cannot be mistaken for another.
string
A link that opens the BotShield app on the link screen with the code filled in. Show it as a link on mobile, or render it as a QR code on desktop. BotShield returns the URL, not an image, so you control the presentation.
string
ISO 8601 time, 10 minutes after the request.
string
The name the user will see.
2. Show the code to the user
Show both the code and theclaim_url. The person opens the BotShield app, goes to Account → BotShield Agent → Link with an agent, enters the code (or opens the link, or scans your QR), and confirms with their biometric.
3. Wait for the link
GET https://api.botshield.ai/operations/agent/check-binding
string
required
The code returned by
bind-session.number
Optional long-poll hold, 0–25. With a value above 0, BotShield re-checks every 2 seconds and answers as soon as the status leaves
pending, or when the hold ends. Omit it, or send 0, for a single immediate check.Response (linked)
Response (still waiting)
Statuses
opaque_id is returned only with bound.
Long-poll guidance
- Set your HTTP client timeout above 25 seconds; 30–35 seconds works well. A shorter timeout cuts off a healthy long-poll.
- One call with
wait_seconds=25covers most people picking up their phone. If it returnspending, call again. - Prefer long-polling to tight loops. Without
wait_seconds, leave a few seconds between checks. - Stop when
expires_athas passed.
Link once, then remember
Linking happens once per human and agent, not once per conversation.- Store the
opaque_idon your own user record and reuse it for every proposal. Remembering the link is your job:bind-sessionalways issues a fresh code and has no “already linked” answer. - If a person who is already linked completes the ceremony again with the same agent, you get their existing active
opaque_idback. A second link never creates a second id for the same pair. - Each of your agents has its own links. A development agent and a production agent are different agents, so link separately in each.
- Links belong to the agent, not to its key. When you rotate the agent’s key, every stored
opaque_idkeeps working with the new key.
When a person disconnects your agent
People manage their links in the BotShield app under Linked Agents, where Disconnect ends the link with your agent. You are not notified. The next time you propose an action to thatopaque_id, the call returns:
opaque_id and run the link again. A disconnected person is free to link again later, and doing so requires a fresh biometric confirmation.
Errors
Always check
data.error before you read data.data. See Errors.
Next steps
Propose an action
Use the
opaque_id to ask for a Confirm or Deny.Hosted MCP server
The same ceremony as the
bind_session and check_binding tools, with the same long-poll wait.Privacy boundary
Why you receive an opaque id and never an identity.
Test it in the Sandbox
Run the link from the Console with a development agent.
