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_yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy

Available 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:create

Creates 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:create

Creates 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:read

Returns 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_xxxxxxxxxxxxxxxx

Response

{
  "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:finalize

Activates 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:revoke

Revokes 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:read

Returns audit log events associated with the handoff, including eventType, purpose, jobId, tokenId, and metadata.

Request

GET /api/agent/transfers/tr_xxxxxxxxxxxxxxxx/logs

Response

{
  "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:append

Appends 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 session

Records 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:read

Endpoint 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:read

When 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:read

When 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:read

Lists 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=20

Response

{
  "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:revoke

Bulk-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:read

Returns 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/usage

Response

{
  "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:read

Verifies 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/verify

Response

{
  "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

HTTPerrorMeaning
401agent_unauthorizedThe Authorization header is missing or not in Bearer format.
401invalid_agent_tokenThe token format is invalid, the token does not exist, or the secret does not match.
401agent_token_revokedThe issued token has already been revoked.
401agent_token_expiredThe token has expired.
401agent_scope_deniedThe token does not include the required scope.
401agent_ip_deniedThe request came from an IP address outside the configured allowlist.
400invalid_requestThe JSON body or required fields do not match the schema. The response returns issues.
400file_size_exceeds_agent_policyThe file exceeds the max file size configured on this token. This occurs on file handoffs.
400max_file_size_exceeds_planThe max file size configured on the Agent Token exceeds the organization's plan limit.
400file_size_exceeds_planThe file exceeds the organization's plan file-size limit.
400retention_exceeds_planexpiresAt 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.
400recipient_email_requiredThis is a multi-recipient receive_handoff call. recipientEmail is required so Sealith knows which recipient the AI is receiving as.
400share_url_requiredfinalize was called without shareUrl.
429agent_rate_limitedThe Agent API minute-level rate limit has been reached. Wait briefly and retry.
403purpose_not_allowedThe supplied purpose is not included in allowedPurposes.
403allowed_use_not_allowedThe supplied allowedUse is not included in allowedUses. The response includes allowedUses permitted by this token.
403recipient_type_not_allowedThe supplied recipientType is not included in allowedRecipientTypes. The response includes allowedRecipientTypes permitted by this token.
403recipient_domain_not_allowedAt least one recipient is outside the allowedRecipientDomains policy.
403mode_b_not_allowedMode B is disabled by the organization's policy.
403monthly_transfer_limit_reachedThe organization has reached its monthly transfer limit.
403ai_handoff_limit_reachedThe monthly AI handoff limit has been reached.
403ai_audit_append_limit_reachedThe monthly AI audit append limit has been reached.
403feature_not_available_on_planThe Agent API is unavailable below Business.
403agent_token_limit_reachedThis plan has reached its Agent Token issuance limit.
403forbiddenYou are trying to access a transfer created by another organization or token.
404not_foundThe target transfer does not exist.
404recipient_not_foundThe supplied recipientEmail is not part of this transfer.
409invalid_statusThe transfer is no longer in draft when finalize was called.
503service_not_configuredEmail 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.

Agent API