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
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.
Field Type Required Description counterparty_didstring Yes DID of the counterparty agent (did:web:...)
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"
}'
{
"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..."
}
Status Code Description 400 MUTUAL_SIGN_NO_AGENTAction has no associated agent and cannot be signed 400 MUTUAL_SIGN_NO_DID_KEYAgent DID keypair not found -- ensure DID is provisioned 404 NOT_FOUNDAction does not exist or does not belong to this organization 409 MUTUAL_SIGN_ALREADY_REQUESTEDMutual signing has already been requested for this action
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.
curl https://api.airaproof.com/api/v1/actions/act_01J9E.../mutual-sign/pending
{
"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"
}
Status Code Description 404 NOT_FOUNDNo pending mutual signing request exists for this action
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:
The action exists and is pending mutual signing
The signing request has not expired
The counterparty DID matches the one specified in the request
The counterparty signature is valid against their DID public key
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.
Field Type Required Description didstring Yes Counterparty DID signaturestring Yes Ed25519 signature (base64url-encoded, prefixed with ed25519:) signed_payload_hashstring Yes SHA-256 hash of the signed payload (sha256:...)
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..."
}'
{
"action_uuid" : "act_01J9E..." ,
"status" : "completed" ,
"combined_receipt_hash" : "sha256:f1e2d3c4b5a6..." ,
"sealed_at" : "2026-06-05T14:30:00Z" ,
"request_id" : "req_01J9F..."
}
Status Code Description 400 MUTUAL_SIGN_NOT_PENDINGAction mutual signing is not in pending status 400 MUTUAL_SIGN_PAYLOAD_MISMATCHSigned payload hash does not match the action payload 400 MUTUAL_SIGN_INVALID_SIGNATURECounterparty signature verification failed 400 DID_NO_VERIFICATION_METHODDID document has no verification methods 400 DID_UNSUPPORTED_KEY_FORMATUnsupported multibase encoding in DID document 403 MUTUAL_SIGN_DID_MISMATCHCounterparty DID does not match the signing request 404 NOT_FOUNDAction does not exist 410 MUTUAL_SIGN_EXPIREDMutual signing request has expired
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.
curl https://api.airaproof.com/api/v1/actions/act_01J9E.../mutual-sign/receipt
{
"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"
}
Status Code Description 400 MUTUAL_SIGN_NOT_COMPLETEDMutual signing is not completed for this action 404 NOT_FOUNDAction does not exist
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.
Field Type Required Description reasonstring No Optional rejection reason (default: "")
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"
}'
{
"action_uuid" : "act_01J9E..." ,
"status" : "rejected" ,
"reason" : "Payload does not match agreed terms" ,
"request_id" : "req_01J9G..."
}
Status Code Description 400 MUTUAL_SIGN_NOT_PENDINGAction mutual signing is not in pending status 404 NOT_FOUNDAction does not exist
Field Type Description action_uuidstring The action UUID statusstring Signing status: pending counterparty_didstring DID of the counterparty agent payload_hashstring SHA-256 hash of the JCS-canonicalized payload (sha256:...) initiator_signaturestring Initiator's Ed25519 signature (ed25519:...) expires_atstring When the signing request expires (ISO 8601) requested_atstring When the signing was requested (ISO 8601) request_idstring Request ID for tracing
Field Type Description action_uuidstring The action UUID statusstring Signing status: pending initiator_didstring | null DID of the initiator agent counterparty_didstring DID of the counterparty agent payloadobject The canonical payload that both parties sign payload_hashstring SHA-256 hash of the JCS-canonicalized payload initiator_signaturestring Initiator's Ed25519 signature expires_atstring When the signing request expires (ISO 8601) requested_atstring When the signing was requested (ISO 8601)
Field Type Description action_uuidstring The action UUID statusstring Signing status: completed combined_receipt_hashstring SHA-256 hash of the canonical payload and both signatures sealed_atstring | null When the receipt was sealed (ISO 8601) request_idstring Request ID for tracing
Field Type Description action_uuidstring The action UUID statusstring Signing status: completed initiator_didstring | null DID of the initiator agent counterparty_didstring DID of the counterparty agent payloadobject The canonical payload that both parties signed payload_hashstring SHA-256 hash of the JCS-canonicalized payload initiator_signaturestring Initiator's Ed25519 signature counterparty_signaturestring Counterparty's Ed25519 signature counterparty_signed_atstring | null When the counterparty signed (ISO 8601) combined_receipt_hashstring SHA-256 hash of the canonical payload and both signatures sealed_atstring | null When the receipt was sealed (ISO 8601)
Field Type Description action_uuidstring The action UUID statusstring Signing status: rejected reasonstring Rejection reason request_idstring Request ID for tracing
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.
Field Type Description action_uuidstring The action UUID org_uuidstring The organization UUID agent_idstring The agent that performed the action action_typestring Type of action (e.g. transaction, decision) action_details_hashstring SHA-256 hash of the action details instruction_hashstring SHA-256 hash of the instruction model_idstring Model ID used for the action created_atstring When the action was created (ISO 8601)