Skip to main content
Your agent proposes an action with 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

The SDK uses camelCase field names (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.
The call returns as soon as the card is queued. The decision arrives later, so poll 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:
Use a new UUID for every new action, including a re-ask after a Deny or an expiry.

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_title and, 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.
Write the title so the decision is clear without the chat context: say what happens, to what, and for how much. A person can decide several waiting cards in one biometric confirmation; those results share a 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 with data.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.
Each entry in violations[] has a type, a JSONPath path into your payload, and a severity of block or warn. Only block entries cause the rejection.
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 status of approved is a signal to go and verify, not permission to act. Execute only after your own code has verified resolution_jwt and checked verdict === "approve". See Proof of Resolution.
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.
Only a 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.