Issued before execution
A receipt is created at authorization time, before the action runs. Infrastructure verifies the receipt at execution time. No receipt, no action.
The complete format for the AuthorityReceipt primitive — the signed artifact that proves an AI action was authorized before it happened.
Spec v1
Every action authorized through Permission Protocol produces an AuthorityReceipt — a signed document that any enforcement point can verify independently. This page defines the complete field schema, signature algorithm, verification API, and lifecycle rules.
The primitive that separates authorization from execution.
A receipt is created at authorization time, before the action runs. Infrastructure verifies the receipt at execution time. No receipt, no action.
Every receipt is signed with an Ed25519 key controlled by the issuing Permission Protocol authority. The signature is verifiable offline or via the API.
The receipt ID travels with the action — in CI environment variables, API headers, database columns. Any enforcement point can independently resolve and verify it.
A complete authority receipt issued for a production deployment.
{
"receipt_id": "pp_r_8f91c2a4b3d7e1",
"version": "1",
"actor": "deploy-bot",
"action": "deploy",
"resource": "billing-service:production",
"approved_by": "sarah.kim",
"policy": "production-deploy",
"context": {
"pull_request": 184,
"commit_sha": "a3f9c2b1",
"environment": "production"
},
"timestamp": "2026-03-03T10:14:22Z",
"expires_at": null,
"authority_issuer": "permissionprotocol.com",
"organization_id": "org_acme_corp",
"shareable": true,
"signature": "pp_sig_MEQCIBx4r..."
}// GET /v1/receipts/pp_r_8f91c2a4b3d7e1/verify
{
"verified": true,
"receipt_id": "pp_r_8f91c2a4b3d7e1",
"action": "deploy",
"resource": "billing-service:production",
"approved_by": "sarah.kim",
"timestamp": "2026-03-03T10:14:22Z",
"expires_at": null,
"reason": null
}
// When not verified:
{
"verified": false,
"reason": "expired" | "invalid_signature"
| "not_found" | "revoked"
}Complete schema for the AuthorityReceipt object.
receipt_idrequiredstringGlobally unique identifier for this receipt. Format: pp_r_<base58>. Stable across verification calls and suitable for use as a foreign key in audit logs.
versionrequiredstringReceipt schema version. Current value: "1". Increment is a breaking change; consumers must handle unknown versions gracefully.
actorrequiredstringIdentifier of the AI agent or system that requested the action. Typically a service account name, agent ID, or bot username.
actionrequiredstringThe action that was authorized. Recommended values: "deploy", "merge", "delete", "transfer", "access", "execute". Custom values are permitted.
resourcerequiredstringThe target of the authorized action. Use colon-separated namespace:resource:environment notation where applicable. Example: billing-service:production.
approved_byrequiredstring | nullUsername or identity of the human approver. null when authorization was issued by a policy engine with no human-in-the-loop.
policystring | nullThe named policy under which the action was evaluated. null when no explicit policy is configured. Policies are defined in your Permission Protocol dashboard.
contextobject | nullCaller-supplied key-value metadata attached to the receipt at issuance. Common keys: pull_request, commit_sha, environment, run_id. Not interpreted by Permission Protocol.
timestamprequiredstring (ISO 8601)UTC timestamp of receipt issuance in ISO 8601 format. Example: 2026-03-03T10:14:22Z. Set by Permission Protocol at authorization time; not caller-controlled.
expires_atstring (ISO 8601) | nullOptional expiry time after which the receipt is no longer valid for enforcement. Null means the receipt does not expire. Verification will return verified: false after this time.
authority_issuerrequiredstringDomain of the Permission Protocol instance that issued the receipt. Default: "permissionprotocol.com". Self-hosted deployments use their configured domain.
organization_idrequiredstringYour Permission Protocol organization identifier. Scopes the receipt to your tenant.
shareablerequiredbooleanWhen true, the receipt proof page at /r/:receipt_id is publicly viewable without authentication. When false, viewing requires an authenticated session in the issuing organization.
signaturerequiredstringEd25519 signature over the canonical receipt payload (all fields except signature, sorted alphabetically, JSON-serialized with no whitespace). Format: pp_sig_<base64url>.
How receipts are signed and how enforcement points verify them.
Receipts are signed using Ed25519. The canonical payload is all fields except signature, sorted alphabetically by key, JSON-serialized with no whitespace. The signing key is rotated quarterly.
The current signing public key is published at /.well-known/pp-jwks.json on the issuing authority domain. The SDK handles key rotation automatically. Self-hosted deployments publish their own JWKS endpoint.
Enforcement points must treat any non-verified: true response as a denied action — including network errors, timeouts, and unknown reasons. The authority layer is fail-closed by design.
import { verify } from "permission-protocol";
// At your enforcement point
const result = await verify(receipt_id);
if (!result.verified) {
throw new Error(`Action blocked: ${result.reason}`);
}
// Proceed with the authorized action
await deploy(result.resource);from permission_protocol import verify
result = verify(receipt_id)
if not result.verified:
raise PermissionDenied(
f"Action blocked: {result.reason}"
)
# Proceed with the authorized action
deploy(result.resource)States a receipt moves through from issuance to enforcement.
pendingAuthorization request submitted. Waiting for human approval or policy evaluation. Action cannot proceed.
issuedReceipt has been signed and issued. The action is authorized. Enforcement points will return verified: true.
expiredThe receipt has passed its expires_at timestamp. Verification returns verified: false. A new authorization is required.
revokedThe receipt was explicitly revoked by an authorized admin. Verification returns verified: false. Cannot be reinstated.
Common questions about authority receipts, verification, and enforcement.
An authority receipt is a signed, portable artifact that proves a specific action was explicitly authorized before it was executed. It records who requested the action, who approved it, under which policy, and when — all bound together with a cryptographic signature that any enforcement point can verify.
An audit log records what happened after the fact. An authority receipt is issued before execution and travels with the action — it is the proof the infrastructure checks before allowing the action to proceed. The receipt exists at authorization time; the audit log references it.
Yes. When a configured policy clears an action automatically, the receipt is issued with approved_by set to null and policy set to the matched policy name. The receipt is still cryptographically signed and verifiable. Teams typically require human approval for production environments and allow policy-engine approval for staging.
Call GET /v1/receipts/:receipt_id/verify or use the SDK's verify() function. The response includes verified: true|false and a reason when false. Enforcement points should treat any non-verified receipt as a denied action and fail closed.
Verification returns verified: false with reason: 'expired'. Enforcement points fail closed. Receipts cannot be renewed; a new authorization request must be submitted.
Receipts are retained for a minimum of 7 years on paid plans to support compliance and audit requirements. The receipt ID remains stable and resolvable for the lifetime of the record.
Yes, via the context field at issuance. Permission Protocol stores the context verbatim and includes it in the receipt. Common uses: pull request number, commit SHA, deployment run ID, environment name.
Ed25519. The signing key is rotated quarterly. The current public key is available at /.well-known/pp-jwks.json on the issuing authority domain. Verification via the SDK handles key rotation automatically.