Agent API
Embed secure handoff through REST.
Use Authorization: Bearer sl_agent_... and call create / finalize / revoke / logs / audit context within purpose-bound Agent Token constraints.
Authentication and availability
Authorization header
Authorization: Bearer sl_agent_agt_xxxxxxxxxxxxxxxx_yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyAvailable on Business and above.
On Business and above, the same handoff can also be posted from the web app into Slack workspace channels or DMs.
The raw token secret is shown only once at issuance time.
Each token can be constrained by scope, purpose, allowed use, recipient type, recipient domain, IP, expiry, and max file size. For URL shares, the destination domain is also captured in the audit context.
If the organization has TOTP enabled, issuance, viewing, and revocation require an extra confirmation step.
Sending-side API flow
This is the primary use case today. Your own AI acts as the sender and completes file registration, transfer finalization, revoke, and audit append entirely through the API.
Even when Slack is used as the delivery path for share links, revoke, audit, and workspace-level posting policy remain on the same Sealith foundation. The Agent API and Slack delivery are just different entry points.
Receiving-side API flow
If the receiving company also has a Sealith account, this API becomes the next workflow for routing received materials into its own AI. Start with /api/agent/receive, then create a new handoff later if that company needs to send onward as its own sender.
Fastest smoke test
For sender-side validation, call create once. For receiver-side validation, call receive once. That covers token validity, scope, recipient-domain rules, and encrypted-file or URL metadata handoff.
Operationally, issue one Agent Token per AI employee. The token becomes the employee ID card; purpose, scope, allowedUse, recipientType, and expiry become its job description.
cURL example: file delivery
curl -X POST https://www.sealith.com/api/agent/transfers \
-H "Authorization: Bearer sl_agent_..." \
-H "Content-Type: application/json" \
-d '{
"purpose": "contract_review",
"jobId": "job_20260423_001",
"transfer": {
"fileName": "nda.pdf",
"fileSizeBytes": 524288,
"mimeType": "application/pdf",
"recipients": [{ "email": "legal@example.com", "name": "法務担当" }],
"message": "レビューをお願いします。",
"salt": "base64url-salt",
"ivFile": "base64url-file-iv",
"ivWrap": "base64url-wrap-iv",
"passcodeHash": "argon2id-passcode-hash",
"systemAccessiblePasscode": "kms-wrapped-passcode",
"expiresAt": "2026-04-30T12:00:00.000Z",
"maxDownloads": 3,
"passcodeDeliveryMode": "B",
"sensitivityLevel": "confidential"
}
}'cURL example: URL delivery
curl -X POST https://www.sealith.com/api/agent/transfers \
-H "Authorization: Bearer sl_agent_..." \
-H "Content-Type: application/json" \
-d '{
"purpose": "dd_link_review",
"jobId": "job_20260423_002",
"transfer": {
"resourceType": "url",
"title": "DD資料共有リンク",
"targetUrl": "https://drive.google.com/file/d/xxx/view",
"targetDomain": "drive.google.com",
"recipients": [{ "email": "legal@example.com", "name": "法務担当" }],
"message": "リンク先の資料確認をお願いします。",
"passcodeHash": "argon2id-passcode-hash",
"systemAccessiblePasscode": "kms-wrapped-passcode",
"expiresAt": "2026-04-30T12:00:00.000Z",
"maxDownloads": 3,
"passcodeDeliveryMode": "B",
"sensitivityLevel": "confidential"
}
}'cURL example: external action
Use an authenticated owner/admin session. This records the action; it does not execute payment or contract operations.
curl -X POST https://www.sealith.com/api/external-actions \
-H "Content-Type: application/json" \
-b "sealith_session=..." \
-d '{
"actionType": "payment",
"title": "仕入先への年額ライセンス支払い",
"purpose": "invoice_payment_review",
"jobId": "job_20260616_001",
"deliveryChannel": "payment_agent",
"externalSystem": "stripe",
"counterpartyName": "Example Vendor Inc.",
"amount": 120000,
"currency": "JPY",
"status": "proposed",
"aiProvider": "anthropic",
"aiClient": "claude_code"
}'POST /api/agent/transfers
scope: transfers:createCreates an encrypted file handoff or an audited URL handoff. The REST Agent API still returns uploadUrl for file uploads, while MCP adds higher-level abstractions such as inline small files and upload sessions. The web UI can also create short secure-text handoffs as resourceType=text. If passcodeDeliveryMode=B, the response also includes the scheduled passcode send time according to the organization's policy.
Request
{
"purpose": "contract_review",
"jobId": "job_20260423_001",
"aiProvider": "anthropic",
"aiClient": "claude_code",
"aiModel": "claude-sonnet-4",
"transfer": {
"fileName": "nda.pdf",
"fileSizeBytes": 524288,
"mimeType": "application/pdf",
"recipients": [
{ "email": "legal@example.com", "name": "法務担当" }
],
"message": "レビューをお願いします。",
"salt": "base64url-salt",
"ivFile": "base64url-file-iv",
"ivWrap": "base64url-wrap-iv",
"passcodeHash": "argon2id-passcode-hash",
"senderAccessiblePasscode": null,
"systemAccessiblePasscode": "kms-wrapped-passcode",
"expiresAt": "2026-04-30T12:00:00.000Z",
"maxDownloads": 3,
"passcodeDeliveryMode": "B",
"sensitivityLevel": "confidential"
}
}Response
{
"transferId": "tr_xxxxxxxxxxxxxxxx",
"uploadUrl": "https://storage.example.com/...",
"expiresIn": 300,
"shareUrlPath": "/r/tr_xxxxxxxxxxxxxxxx",
"passcodeScheduledSendAt": "2026-04-23T06:10:00.000Z"
}POST /api/agent/transfers (resourceType=url)
scope: transfers:createCreates a handoff that delivers a shared URL from Google Drive, Box, and similar services with a passcode and audit trail. Sealith protects the handoff and auditing of the URL, while permission control for the destination remains on the external service. MCP can treat creation and notification as a single step.
Request
{
"purpose": "dd_link_review",
"jobId": "job_20260423_002",
"aiProvider": "openai",
"aiClient": "chatgpt_connector",
"transfer": {
"resourceType": "url",
"title": "DD資料共有リンク",
"targetUrl": "https://drive.google.com/file/d/xxx/view",
"targetDomain": "drive.google.com",
"recipients": [
{ "email": "legal@example.com", "name": "法務担当" }
],
"message": "リンク先の資料確認をお願いします。",
"passcodeHash": "argon2id-passcode-hash",
"senderAccessiblePasscode": null,
"systemAccessiblePasscode": "kms-wrapped-passcode",
"expiresAt": "2026-04-30T12:00:00.000Z",
"maxDownloads": 3,
"passcodeDeliveryMode": "B",
"sensitivityLevel": "confidential"
}
}Response
{
"transferId": "tr_xxxxxxxxxxxxxxxx",
"uploadUrl": null,
"expiresIn": 300,
"shareUrlPath": "/r/tr_xxxxxxxxxxxxxxxx",
"passcodeScheduledSendAt": "2026-04-23T06:10:00.000Z"
}GET /api/agent/transfers/:id
scope: transfers:readReturns the current status of an existing handoff. Use it to inspect recipient-by-recipient notification state, passcodeScheduledSendAt, download counts, or external link transition counts.
Request
GET /api/agent/transfers/tr_xxxxxxxxxxxxxxxxResponse
{
"transfer": {
"id": "tr_xxxxxxxxxxxxxxxx",
"fileName": "nda.pdf",
"fileSizeBytes": 524288,
"mimeType": "application/pdf",
"recipients": [
{
"email": "legal@example.com",
"name": "法務担当",
"notifiedUrlAt": "2026-04-23T06:00:00.000Z",
"notifiedPasscodeAt": null,
"firstAccessedAt": null,
"downloadCount": 0
}
],
"status": "active",
"expiresAt": "2026-04-30T12:00:00.000Z",
"maxDownloads": 3,
"totalDownloadCount": 0,
"passcodeDeliveryMode": "B",
"passcodeScheduledSendAt": "2026-04-23T06:10:00.000Z",
"createdAt": "2026-04-23T06:00:00.000Z"
}
}POST /api/agent/transfers/:id/finalize
scope: transfers:finalizeActivates the handoff after upload and sends the URL notice to recipients. In standard mode, the follow-up passcode notification is scheduled at the same time.
Request
{
"shareUrl": "https://www.sealith.com/r/tr_xxxxxxxxxxxxxxxx"
}Response
{
"ok": true
}POST /api/agent/transfers/:id/revoke
scope: transfers:revokeRevokes the handoff. If there is a pending passcode notification, it is cancelled at the same time.
Request
{}Response
{
"ok": true
}GET /api/agent/transfers/:id/logs
scope: logs:readReturns audit log events associated with the handoff, including eventType, purpose, jobId, tokenId, and metadata.
Request
GET /api/agent/transfers/tr_xxxxxxxxxxxxxxxx/logsResponse
{
"logs": [
{
"id": "log_xxxxx",
"sequence": 12,
"eventHash": "9db4...",
"previousHash": "f0ab...",
"canonicalPayloadHash": "3b81...",
"hashAlgorithm": "sha256",
"eventTime": "2026-04-23T06:12:10.000Z",
"eventType": "agent_audit_context_appended",
"actorType": "agent",
"actorId": "contract-review-agent",
"actorName": "契約レビューエージェント",
"actorEmail": null,
"tokenId": "agt_xxxxx",
"purpose": "contract_review",
"jobId": "job_20260423_001",
"scope": "audit:append",
"success": true,
"errorCode": null,
"metadata": {
"note": "要確認条項を抽出しました。",
"result": "needs_human_review"
},
"createdAt": "2026-04-23T06:12:10.000Z"
}
]
}POST /api/agent/audit-context
scope: audit:appendAppends an audit entry that records what the AI concluded through purpose / jobId / aiProvider / aiClient / note / result. aiModel remains optional when available.
Request
{
"transferId": "tr_xxxxxxxxxxxxxxxx",
"purpose": "contract_review",
"jobId": "job_20260423_001",
"aiProvider": "anthropic",
"aiClient": "claude_code",
"aiModel": "claude-sonnet-4",
"note": "要確認条項を抽出しました。",
"result": "needs_human_review",
"metadata": {
"model": "gpt-5.4",
"reviewCount": 4
}
}Response
{
"ok": true
}POST /api/external-actions
scope: owner/admin sessionRecords non-file actions such as payment, contract, CRM update, procurement, and system update as audit events. This endpoint uses an authenticated owner/admin session, not an Agent Token. It does not execute the action; it records permission, result, amount, counterparty, and AI identity from another system.
Request
{
"actionType": "payment",
"title": "仕入先への年額ライセンス支払い",
"description": "AIが請求書を照合し、支払い候補として起票しました。",
"purpose": "invoice_payment_review",
"jobId": "job_20260616_001",
"deliveryChannel": "payment_agent",
"externalSystem": "stripe",
"counterpartyName": "Example Vendor Inc.",
"amount": 120000,
"currency": "JPY",
"status": "proposed",
"aiProvider": "anthropic",
"aiClient": "claude_code",
"aiModel": "claude-sonnet-4",
"metadata": {
"invoiceId": "inv_001",
"approvalPolicy": "amount_over_100000"
}
}Response
{
"externalAction": {
"id": "exa_xxxxxxxxxxxxxxxxxx",
"approvalRequired": true,
"approvalRequestId": "apr_xxxxxxxxxxxxxxxxxx",
"approvalReasons": [
"金銭移動または決済に近い外部アクション",
"金額が100,000以上",
"外部組織・外部取引先が関与"
]
}
}POST /api/agent/receive
scope: transfers:readEndpoint for AI to receive a handoff created by a human sender. For file and text resources, it returns decryption parameters and a signed download URL. For URL resources, it returns targetUrl and targetDomain. Text handoffs are returned as encrypted text/plain payloads that the receiver can decode after decryption.
Request
{
"transferId": "tr_xxxxxxxxxxxxxxxx",
"passcode": "A2b!C3d@E4f#G5h$",
"purpose": "contract_review",
"jobId": "job_20260423_001",
"aiProvider": "anthropic",
"aiClient": "claude_app",
"recipientEmail": "legal@example.com"
}Response
{
"resourceType": "file",
"signedUrl": "https://storage.example.com/...",
"fileName": "nda.pdf",
"fileSizeBytes": 524288,
"mimeType": "application/pdf",
"ciphertext": {
"expiresIn": 300
},
"crypto": {
"salt": "base64url-salt",
"ivFile": "base64url-file-iv",
"ivWrap": "base64url-wrap-iv"
},
"metadata": {
"senderEmail": "owner@example.com",
"senderDisplayName": "営業担当",
"message": "レビューをお願いします。"
}
}POST /api/agent/receive (resourceType=text)
scope: transfers:readWhen AI receives a secure-text handoff created from the web UI, the response returns resourceType=text and a text/plain MIME type. Sealith does not store the plaintext body in Firestore or audit logs; the encrypted payload follows the same R2 storage, retention, and revoke rules as file handoffs.
Request
{
"transferId": "tr_xxxxxxxxxxxxxxxx",
"passcode": "A2b!C3d@E4f#G5h$",
"purpose": "credential_review",
"jobId": "job_20260520_001",
"aiProvider": "openai",
"aiClient": "chatgpt_connector",
"recipientEmail": "ops@example.com"
}Response
{
"resourceType": "text",
"signedUrl": "https://storage.example.com/...",
"fileName": "Production SFTP credentials.txt",
"fileSizeBytes": 2048,
"mimeType": "text/plain;charset=utf-8",
"ciphertext": {
"expiresIn": 300
},
"crypto": {
"salt": "base64url-salt",
"ivFile": "base64url-file-iv",
"ivWrap": "base64url-wrap-iv"
},
"metadata": {
"senderEmail": "owner@example.com",
"senderDisplayName": "情シス担当",
"message": "本番接続情報です。"
}
}POST /api/agent/receive (resourceType=url)
scope: transfers:readWhen receiving a URL share, this returns the link information that the AI should follow into the external service. Sealith handles handoff and auditing, but does not proxy the destination service's own access control.
Request
{
"transferId": "tr_xxxxxxxxxxxxxxxx",
"passcode": "A2b!C3d@E4f#G5h$",
"purpose": "dd_link_review",
"jobId": "job_20260423_002",
"aiProvider": "openai",
"aiClient": "chatgpt_connector",
"recipientEmail": "legal@example.com"
}Response
{
"resourceType": "url",
"link": {
"targetUrl": "https://drive.google.com/file/d/xxx/view",
"targetDomain": "drive.google.com",
"title": "DD資料共有リンク"
},
"metadata": {
"senderEmail": "owner@example.com",
"senderDisplayName": "営業担当",
"message": "リンク先の資料確認をお願いします。"
}
}GET /api/agent/transfers
scope: transfers:readLists and searches handoffs created by this token. Filter by q, status, resourceType, recipientEmail, dateFrom / dateTo, and limit so you can find the right transfer without remembering the transfer ID.
Request
GET /api/agent/transfers?status=active&q=契約書&limit=20Response
{
"transfers": [
{
"id": "tr_xxxxxxxxxxxxxxxx",
"resourceType": "file",
"fileName": "nda.pdf",
"title": "nda.pdf",
"status": "active",
"recipients": [
{
"email": "legal@example.com",
"name": "法務担当",
"firstAccessedAt": null,
"downloadCount": 0
}
],
"totalDownloadCount": 0,
"maxDownloads": 3,
"expiresAt": "2026-04-30T12:00:00.000Z",
"purpose": "contract_review",
"jobId": "job_20260423_001",
"sensitivityLevel": "confidential",
"createdAt": "2026-04-23T06:00:00.000Z"
}
],
"total": 1
}POST /api/agent/transfers/bulk
scope: transfers:revokeBulk-revokes handoffs created by this token. Up to 20 items per call. If reason is set, it is written into the audit log. Use this for project closure, offboarding, or mass cleanup after misdelivery.
Request
{
"action": "revoke",
"transferIds": [
"tr_xxxxxxxxxxxxxxxx",
"tr_yyyyyyyyyyyyyyyy"
],
"reason": "プロジェクト終了のため"
}Response
{
"ok": true,
"revokedCount": 2
}GET /api/agent/org/usage
scope: transfers:readReturns organization plan limits and current-month usage. Use it to inspect remaining transfer quota, max file size, retention limits, and similar limits before large operations.
Request
GET /api/agent/org/usageResponse
{
"plan": "business",
"limits": {
"maxMonthlyTransfers": 2000,
"maxFileSizeMB": 5120,
"maxRecipients": 10,
"maxRetentionDays": 1095
},
"usage": {
"currentMonthTransfers": 47,
"remainingMonthlyTransfers": 1953,
"resetAt": "2026-05-01T00:00:00.000Z"
},
"capabilities": {
"mcp": true,
"agentTokens": true,
"archive": true,
"openNotification": true,
"auditCsvExport": true
}
}GET /api/agent/org/audit/verify
scope: logs:readVerifies the SHA-256 hash chain across the organization's audit log entries (up to 1000 events). If ok is false, failures includes the sequence number and reason for each integrity issue. Use it for compliance evidence and customer-facing audit reporting.
Request
GET /api/agent/org/audit/verifyResponse
{
"ok": true,
"checked": 128,
"verified": 125,
"legacy": 3,
"failures": [],
"latestHash": "9db4c2f3...",
"summary": "Audit chain intact. 125 events verified, 3 pre-hash legacy events skipped."
}Error codes
| HTTP | error | Meaning |
|---|---|---|
| 401 | agent_unauthorized | The Authorization header is missing or not in Bearer format. |
| 401 | invalid_agent_token | The token format is invalid, the token does not exist, or the secret does not match. |
| 401 | agent_token_revoked | The issued token has already been revoked. |
| 401 | agent_token_expired | The token has expired. |
| 401 | agent_scope_denied | The token does not include the required scope. |
| 401 | agent_ip_denied | The request came from an IP address outside the configured allowlist. |
| 400 | invalid_request | The JSON body or required fields do not match the schema. The response returns issues. |
| 400 | file_size_exceeds_agent_policy | The file exceeds the max file size configured on this token. This occurs on file handoffs. |
| 400 | max_file_size_exceeds_plan | The max file size configured on the Agent Token exceeds the organization's plan limit. |
| 400 | file_size_exceeds_plan | The file exceeds the organization's plan file-size limit. |
| 400 | retention_exceeds_plan | expiresAt exceeds the organization's retention limit. Business supports up to 3 years, while Enterprise can be unlimited by admin policy. The maxDays field tells you the current ceiling. |
| 400 | recipient_email_required | This is a multi-recipient receive_handoff call. recipientEmail is required so Sealith knows which recipient the AI is receiving as. |
| 400 | share_url_required | finalize was called without shareUrl. |
| 429 | agent_rate_limited | The Agent API minute-level rate limit has been reached. Wait briefly and retry. |
| 403 | purpose_not_allowed | The supplied purpose is not included in allowedPurposes. |
| 403 | allowed_use_not_allowed | The supplied allowedUse is not included in allowedUses. The response includes allowedUses permitted by this token. |
| 403 | recipient_type_not_allowed | The supplied recipientType is not included in allowedRecipientTypes. The response includes allowedRecipientTypes permitted by this token. |
| 403 | recipient_domain_not_allowed | At least one recipient is outside the allowedRecipientDomains policy. |
| 403 | mode_b_not_allowed | Mode B is disabled by the organization's policy. |
| 403 | monthly_transfer_limit_reached | The organization has reached its monthly transfer limit. |
| 403 | ai_handoff_limit_reached | The monthly AI handoff limit has been reached. |
| 403 | ai_audit_append_limit_reached | The monthly AI audit append limit has been reached. |
| 403 | feature_not_available_on_plan | The Agent API is unavailable below Business. |
| 403 | agent_token_limit_reached | This plan has reached its Agent Token issuance limit. |
| 403 | forbidden | You are trying to access a transfer created by another organization or token. |
| 404 | not_found | The target transfer does not exist. |
| 404 | recipient_not_found | The supplied recipientEmail is not part of this transfer. |
| 409 | invalid_status | The transfer is no longer in draft when finalize was called. |
| 503 | service_not_configured | Email or another external integration is missing required environment configuration. |
Field notes
purpose drives both the audit log and token constraints.
jobId, aiProvider, and aiClient are required on AI-triggered calls so teams can tie the handoff back to a concrete workflow and runtime.
passcodeDeliveryMode takes A or B. Mode B requires systemAccessiblePasscode.
sensitivityLevel is one of public / internal / confidential / restricted.
shareUrlPath comes back from create. Build the final public URL by joining it with your own base URL, then pass that value to finalize.
/api/agent/receive accepts transferId and passcode, then returns encryption parameters and a short-lived download URL for the AI to continue into decryption.