POST /agentlink/inquire, waits for the decision with GET /agentlink/check-status, and can withdraw it with POST /agentlink/cancel. All three authenticate with your agent key and are available in the TypeScript SDK as client.actions.*. You need the human’s opaque_id from Link a human.
Set up the client
requestId, opaqueId, summaryTitle) and returns the API envelope untouched: check result.data.error first, then read result.data.data.
Propose the action
POST https://api.botshield.ai/operations/agentlink/inquire
string (UUID)
required
A UUID you generate. It is the idempotency key, the id you poll and cancel with, and the
jti of the resulting proof. Sending the same request_id again does not create a second card; see Idempotency.string
required
The
OP_… id your agent holds for this human. It is resolved against your agent’s own links only.object
required
What the human is asked to decide.
summary_detail is optional, but if you send it, both label and value are required.integer
default:"600"
How long the human has to answer. Minimum 60, maximum 86400 (24 hours). Values outside the range are rejected; they are not clamped.
object
Optional. An Adaptive Card shown when the human expands the card for more detail. See Add detail with an Adaptive Card.
user_email is deprecated and will be removed. Identify the human with opaque_id.Response
string
queued for a new proposal. On an idempotent replay, the card’s current status.string
BotShield’s id for the card. It also appears in webhook payloads.
string
ISO 8601 time at which the proposal expires. Present on a new proposal only.
boolean
true when this request_id was already proposed by your agent. No new card was created.check-status or listen for webhooks. BotShield also emits agents_ask.card.proposed at this point.
Idempotency
request_id is unique per agent. If a network error leaves you unsure whether a proposal landed, send the same body again with the same request_id. You get back the existing card:
What the user sees
The human gets a push notification and a card in the BotShield app showing:- your agent’s display name, as registered in the Console;
- the
summary_titleand, if sent, the one detail row; - the expanded Adaptive Card body, if you sent one, when they tap the card;
- Confirm and Deny controls, followed by a passkey confirmation with their device biometric.
ceremony_id.
Add detail with an Adaptive Card
adaptive_card_payload takes Adaptive Card JSON. BotShield validates and screens it before anything reaches the user’s phone, and rejects the whole proposal if it fails.
Errors
Handler errors arrive as HTTP 200 withdata.error. Check it before reading data.data.
A schema problem in the request itself, such as a
request_id that is not a UUID or a 130-character title, returns HTTP 400 with an input validation body instead of the envelope. See Errors.
violations[] has a type, a JSONPath path into your payload, and a severity of block or warn. Only block entries cause the rejection.
Violation types
Violation types
Structure:
payload_too_large, payload_not_object, wrong_root_type, unsupported_version, unknown_element_type, disallowed_property, globally_disallowed_property, disallowed_action_type, reserved_action_id_required, reserved_action_id_conflict, image_remote_url_disallowed, fact_too_long, too_many_facts, too_many_elements, malformed_fact, malformed_element.Content: credit_card, ssn, bank_account, embedded_url, email_unlabeled, phone_unlabeled, api_key_or_token, toxic_language, prompt_injection, social_engineering, off_topic_content, deceptive_pricing.Identity: identity_mismatch.Wait for the decision
GET https://api.botshield.ai/operations/agentlink/check-status
string (UUID)
required
The
request_id you proposed with.number
Optional long-poll hold, 0–25. While the card is
queued, BotShield re-checks every 2 seconds and answers as soon as it reaches a final status, or when the hold ends. Omit it, or send 0, for a single immediate check.Response (confirmed)
Other fields:
resolved_at is the time of the final status (null while queued). ceremony_id identifies the biometric confirmation and is shared by cards decided together. delivered and callback_attempts are reserved; ignore them.
A request_id your agent never proposed returns data.error with statusCode 404 and the message request_id not found for this agent.
Long-poll guidance. Set your HTTP timeout above 25 seconds; 30–35 seconds works well. One held call replaces a dozen short polls, which matters in agent hosts that run one turn at a time. If you would rather not hold a connection, subscribe to the agents_ask.resolution.* webhooks, which carry the same signed proof.
Cancel a proposal
POST https://api.botshield.ai/operations/agentlink/cancel
Withdraw a proposal when the user changes their mind in the conversation or the action no longer applies. A cancelled proposal can no longer be confirmed.
string (UUID)
required
The proposal to withdraw.
string
Optional, up to 200 characters. Recorded for your audit trail.
queued proposal can be cancelled. Cancel is safe to repeat: if the card already has a final status, nothing changes and you get that status back with already_resolved: true. If it says approved, a valid proof exists, so decide deliberately whether to honor it. An unknown request_id returns a 404 error in data.error.
Next steps
Proof of Resolution
Verify the signed result before you execute.
Webhook events
Receive
agents_ask.* events instead of polling.TypeScript SDK
Install and configure
botshield-sdk.Hosted MCP server
Offer the same calls to an agent as tools, with
ttl_seconds and the long-poll wait built in.