Closed Beta — Aira is currently invite-only. Request access to join the early program.
Aira

Mutual Signing

Bilateral Ed25519 signing endpoints for high-stakes agent actions requiring counterparty co-signatures.

All mutual signing endpoints are scoped to a specific action: /api/v1/actions/{action_uuid}/mutual-sign/...

The Request endpoint requires a Bearer token (Authorization: Bearer aira_live_xxxxx). All other endpoints are public -- they are accessed by the counterparty and identified by their DID, not by an API key.

Base URL: https://api.airaproof.com/api/v1


Request Mutual Signing

POST /api/v1/actions/{action_uuid}/mutual-sign/request
Authorization: Bearer aira_live_xxxxx

Initiates a mutual signing request for an action. The server signs the action payload with the initiator agent's Ed25519 private key, stores the signature, and marks the action as pending. The counterparty has 24 hours to complete or reject the request before it expires.

Request Body

FieldTypeRequiredDescription
counterparty_didstringYesDID of the counterparty agent (did:web:...)

Example Request

curl -X POST https://api.airaproof.com/api/v1/actions/act_01J9E.../mutual-sign/request \
  -H "Authorization: Bearer aira_live_xxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "counterparty_did": "did:web:counterparty.example.com"
  }'

Response (201 Created)

{
  "action_uuid": "act_01J9E...",
  "status": "pending",
  "counterparty_did": "did:web:counterparty.example.com",
  "payload_hash": "sha256:a1b2c3d4e5f6...",
  "initiator_signature": "ed25519:AAAA...",
  "expires_at": "2026-06-06T12:00:00Z",
  "requested_at": "2026-06-05T12:00:00Z",
  "request_id": "req_01J9E..."
}

Error Codes

StatusCodeDescription
400MUTUAL_SIGN_NO_AGENTAction has no associated agent and cannot be signed
400MUTUAL_SIGN_NO_DID_KEYAgent DID keypair not found -- ensure DID is provisioned
404NOT_FOUNDAction does not exist or does not belong to this organization
409MUTUAL_SIGN_ALREADY_REQUESTEDMutual signing has already been requested for this action

Get Pending Signing Payload

GET /api/v1/actions/{action_uuid}/mutual-sign/pending

Returns the pending mutual signing payload for counterparty review. This is a public endpoint -- it is accessed by the counterparty without authentication, rate-limited to prevent abuse.

Example Request

curl https://api.airaproof.com/api/v1/actions/act_01J9E.../mutual-sign/pending

Response (200 OK)

{
  "action_uuid": "act_01J9E...",
  "status": "pending",
  "initiator_did": "did:web:initiator.example.com",
  "counterparty_did": "did:web:counterparty.example.com",
  "payload": {
    "action_uuid": "act_01J9E...",
    "org_uuid": "org_01J9E...",
    "agent_id": "procurement-agent",
    "action_type": "transaction",
    "action_details_hash": "sha256:...",
    "instruction_hash": "sha256:...",
    "model_id": "claude-sonnet-4-20250514",
    "created_at": "2026-06-05T10:00:00"
  },
  "payload_hash": "sha256:a1b2c3d4e5f6...",
  "initiator_signature": "ed25519:AAAA...",
  "expires_at": "2026-06-06T12:00:00Z",
  "requested_at": "2026-06-05T12:00:00Z"
}

Error Codes

StatusCodeDescription
404NOT_FOUNDNo pending mutual signing request exists for this action

Complete Mutual Signing

POST /api/v1/actions/{action_uuid}/mutual-sign/complete

Counterparty submits their Ed25519 signature to complete mutual signing. This is a public endpoint -- the counterparty is identified by their DID, not by an API key.

The server verifies:

  1. The action exists and is pending mutual signing
  2. The signing request has not expired
  3. The counterparty DID matches the one specified in the request
  4. The counterparty signature is valid against their DID public key
  5. The payload hash matches the action payload

Once verified, the server seals the receipt with a combined hash of the canonical payload and both signatures.

Request Body

FieldTypeRequiredDescription
didstringYesCounterparty DID
signaturestringYesEd25519 signature (base64url-encoded, prefixed with ed25519:)
signed_payload_hashstringYesSHA-256 hash of the signed payload (sha256:...)

Example Request

curl -X POST https://api.airaproof.com/api/v1/actions/act_01J9E.../mutual-sign/complete \
  -H "Content-Type: application/json" \
  -d '{
    "did": "did:web:counterparty.example.com",
    "signature": "ed25519:BBBB...",
    "signed_payload_hash": "sha256:a1b2c3d4e5f6..."
  }'

Response (200 OK)

{
  "action_uuid": "act_01J9E...",
  "status": "completed",
  "combined_receipt_hash": "sha256:f1e2d3c4b5a6...",
  "sealed_at": "2026-06-05T14:30:00Z",
  "request_id": "req_01J9F..."
}

Error Codes

StatusCodeDescription
400MUTUAL_SIGN_NOT_PENDINGAction mutual signing is not in pending status
400MUTUAL_SIGN_PAYLOAD_MISMATCHSigned payload hash does not match the action payload
400MUTUAL_SIGN_INVALID_SIGNATURECounterparty signature verification failed
400DID_NO_VERIFICATION_METHODDID document has no verification methods
400DID_UNSUPPORTED_KEY_FORMATUnsupported multibase encoding in DID document
403MUTUAL_SIGN_DID_MISMATCHCounterparty DID does not match the signing request
404NOT_FOUNDAction does not exist
410MUTUAL_SIGN_EXPIREDMutual signing request has expired

Get Receipt

GET /api/v1/actions/{action_uuid}/mutual-sign/receipt

Returns the co-signed receipt for a completed mutual signing. This is a public endpoint -- the receipt is verifiable by anyone.

Example Request

curl https://api.airaproof.com/api/v1/actions/act_01J9E.../mutual-sign/receipt

Response (200 OK)

{
  "action_uuid": "act_01J9E...",
  "status": "completed",
  "initiator_did": "did:web:initiator.example.com",
  "counterparty_did": "did:web:counterparty.example.com",
  "payload": {
    "action_uuid": "act_01J9E...",
    "org_uuid": "org_01J9E...",
    "agent_id": "procurement-agent",
    "action_type": "transaction",
    "action_details_hash": "sha256:...",
    "instruction_hash": "sha256:...",
    "model_id": "claude-sonnet-4-20250514",
    "created_at": "2026-06-05T10:00:00"
  },
  "payload_hash": "sha256:a1b2c3d4e5f6...",
  "initiator_signature": "ed25519:AAAA...",
  "counterparty_signature": "ed25519:BBBB...",
  "counterparty_signed_at": "2026-06-05T14:30:00Z",
  "combined_receipt_hash": "sha256:f1e2d3c4b5a6...",
  "sealed_at": "2026-06-05T14:30:00Z"
}

Error Codes

StatusCodeDescription
400MUTUAL_SIGN_NOT_COMPLETEDMutual signing is not completed for this action
404NOT_FOUNDAction does not exist

Reject Mutual Signing

POST /api/v1/actions/{action_uuid}/mutual-sign/reject

Counterparty rejects a pending mutual signing request. This is a public endpoint -- the counterparty is identified by their DID, not by an API key.

Request Body

FieldTypeRequiredDescription
reasonstringNoOptional rejection reason (default: "")

Example Request

curl -X POST https://api.airaproof.com/api/v1/actions/act_01J9E.../mutual-sign/reject \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "Payload does not match agreed terms"
  }'

Response (200 OK)

{
  "action_uuid": "act_01J9E...",
  "status": "rejected",
  "reason": "Payload does not match agreed terms",
  "request_id": "req_01J9G..."
}

Error Codes

StatusCodeDescription
400MUTUAL_SIGN_NOT_PENDINGAction mutual signing is not in pending status
404NOT_FOUNDAction does not exist

Response Objects

Request Response

FieldTypeDescription
action_uuidstringThe action UUID
statusstringSigning status: pending
counterparty_didstringDID of the counterparty agent
payload_hashstringSHA-256 hash of the JCS-canonicalized payload (sha256:...)
initiator_signaturestringInitiator's Ed25519 signature (ed25519:...)
expires_atstringWhen the signing request expires (ISO 8601)
requested_atstringWhen the signing was requested (ISO 8601)
request_idstringRequest ID for tracing

Pending Response

FieldTypeDescription
action_uuidstringThe action UUID
statusstringSigning status: pending
initiator_didstring | nullDID of the initiator agent
counterparty_didstringDID of the counterparty agent
payloadobjectThe canonical payload that both parties sign
payload_hashstringSHA-256 hash of the JCS-canonicalized payload
initiator_signaturestringInitiator's Ed25519 signature
expires_atstringWhen the signing request expires (ISO 8601)
requested_atstringWhen the signing was requested (ISO 8601)

Complete Response

FieldTypeDescription
action_uuidstringThe action UUID
statusstringSigning status: completed
combined_receipt_hashstringSHA-256 hash of the canonical payload and both signatures
sealed_atstring | nullWhen the receipt was sealed (ISO 8601)
request_idstringRequest ID for tracing

Receipt Response

FieldTypeDescription
action_uuidstringThe action UUID
statusstringSigning status: completed
initiator_didstring | nullDID of the initiator agent
counterparty_didstringDID of the counterparty agent
payloadobjectThe canonical payload that both parties signed
payload_hashstringSHA-256 hash of the JCS-canonicalized payload
initiator_signaturestringInitiator's Ed25519 signature
counterparty_signaturestringCounterparty's Ed25519 signature
counterparty_signed_atstring | nullWhen the counterparty signed (ISO 8601)
combined_receipt_hashstringSHA-256 hash of the canonical payload and both signatures
sealed_atstring | nullWhen the receipt was sealed (ISO 8601)

Reject Response

FieldTypeDescription
action_uuidstringThe action UUID
statusstringSigning status: rejected
reasonstringRejection reason
request_idstringRequest ID for tracing

Signing Payload Object

The payload is the canonical data that both parties sign. It is constructed from the action and serialized using JCS (RFC 8785) for deterministic byte representation.

FieldTypeDescription
action_uuidstringThe action UUID
org_uuidstringThe organization UUID
agent_idstringThe agent that performed the action
action_typestringType of action (e.g. transaction, decision)
action_details_hashstringSHA-256 hash of the action details
instruction_hashstringSHA-256 hash of the instruction
model_idstringModel ID used for the action
created_atstringWhen the action was created (ISO 8601)

On this page