boxLink
Links the box to an account, so the box's watch hits draw the account's units and its limits are the account's tier's. A box belongs to at most one account.
Cost: Free. Signed by the box over method
POST, path/agent/v1/<address lowercased>/box/linkand the body{"accountId": ...}, and authorized by the account: its key inARCGATE-KEY, or the owner'sAccountRequestover the same method, path and body inACCOUNT-SIGNATURE,ACCOUNT-NONCEandACCOUNT-EXPIRY. The box's signature alone is a 401signature_required.Inputs:
address(path), the box, andaccountId(body).Returns:
address,accountId,linkedAtandkeyId, the id of the key that made the link, or null when the owner's signature did. A link made with a key sends a notice to the owner's box.Errors:
404
box_not_found: the address has no box. Create one withboxCreate.404
account_not_found: no account has that id.403
key_wrong_account: the key belongs to another account thanaccountId.409
box_linked: the box belongs to an account already. Unlink it first withboxUnlink.409
account_lapsed: the account has lapsed (its grace has ended), so no box can be linked to it.409
box_limit: the account holds as many boxes as its tier allows, or as the tier it has a downgrade scheduled to (accountTier), which the message names and the body carries asscheduledTier. Unlink one first.409
watch_limit: while the account has a downgrade scheduled (accountTier), the box holds more watches, screens or agent screens than the scheduled tier allows; the message names it and the body carriesscheduledTier. Delete what is over, then link.
Next:
accountStatus: read the account's linked boxes.boxStatus: read the box'slinkedAccount.boxUnlink: end the link.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| address | Yes | The box's address: the agent's own address (an EOA or an EIP-7702 account), any letter case. The box is keyed by it, and a signed request must be signed by it. | |
| accountId | Yes | The account's id, `acct_` and 22 base64url characters, as `accountCreate` and `accountStatus` answer it. | |
| agentSignature | No | The agent's EIP-712 signature over this request, as the AGENT-SIGNATURE, AGENT-NONCE and AGENT-EXPIRY headers carry it over HTTP. Sign the typed data `AgentRequest` with fields `address` (the box), `method`, `path`, `bodyHash`, `nonce` and `expiry`, under the domain {name: "arcgate", version: "1"} with no chainId (a wallet that can only sign with one, such as Circle's, may add the chainId of the chain this deployment serves, 5042 on Arc mainnet, and no other). The `path` is the request path with every parameter filled in and the address lowercased. The `bodyHash` is the keccak256 of the canonical JSON of the body you send (sorted keys, no whitespace), or of no bytes when there is none. Omitting it is a 401 signature_required unless an ARCGATE-KEY of the account the box is linked to is sent (over MCP, on the connection), and it is never a charge: the call is free. | |
| accountSignature | No | The account owner's EIP-712 signature over this same request, as the ACCOUNT-SIGNATURE, ACCOUNT-NONCE and ACCOUNT-EXPIRY headers carry it over HTTP: the same method, path and body the box signs, but the typed data `AccountRequest` (not `AgentRequest`) with `address` the owner's and `origin` first (the API's base URL with no trailing slash, for example `https://api.arcgate.dev`), under the same domain. A signature made for another deployment's origin is a 401 invalid_signature. Each nonce is accepted once per owner. It authorizes the call in place of an ARCGATE-KEY of the account; one of the two is needed, and omitting both is a 401 signature_required, never a charge. |