PERMISSION/PROTOCOL

Authority Receipt Specification.

The complete format for the AuthorityReceipt primitive — the signed artifact that proves an AI action was authorized before it happened.

Spec v1

A portable, verifiable proof of authorization.

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.

What is an AuthorityReceipt?

The primitive that separates authorization from execution.

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.

Cryptographically signed

Every receipt is signed with an Ed25519 key controlled by the issuing Permission Protocol authority. The signature is verifiable offline or via the API.

Portable across systems

The receipt ID travels with the action — in CI environment variables, API headers, database columns. Any enforcement point can independently resolve and verify it.

Example Receipt.

A complete authority receipt issued for a production deployment.

JSON — AuthorityReceipt
{
  "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..."
}
Verification response
// 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"
}

Field Reference.

Complete schema for the AuthorityReceipt object.

FieldTypeDescription
receipt_idrequired
string

Globally unique identifier for this receipt. Format: pp_r_<base58>. Stable across verification calls and suitable for use as a foreign key in audit logs.

versionrequired
string

Receipt schema version. Current value: "1". Increment is a breaking change; consumers must handle unknown versions gracefully.

actorrequired
string

Identifier of the AI agent or system that requested the action. Typically a service account name, agent ID, or bot username.

actionrequired
string

The action that was authorized. Recommended values: "deploy", "merge", "delete", "transfer", "access", "execute". Custom values are permitted.

resourcerequired
string

The target of the authorized action. Use colon-separated namespace:resource:environment notation where applicable. Example: billing-service:production.

approved_byrequired
string | null

Username or identity of the human approver. null when authorization was issued by a policy engine with no human-in-the-loop.

policy
string | null

The named policy under which the action was evaluated. null when no explicit policy is configured. Policies are defined in your Permission Protocol dashboard.

context
object | null

Caller-supplied key-value metadata attached to the receipt at issuance. Common keys: pull_request, commit_sha, environment, run_id. Not interpreted by Permission Protocol.

timestamprequired
string (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_at
string (ISO 8601) | null

Optional 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_issuerrequired
string

Domain of the Permission Protocol instance that issued the receipt. Default: "permissionprotocol.com". Self-hosted deployments use their configured domain.

organization_idrequired
string

Your Permission Protocol organization identifier. Scopes the receipt to your tenant.

shareablerequired
boolean

When 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.

signaturerequired
string

Ed25519 signature over the canonical receipt payload (all fields except signature, sorted alphabetically, JSON-serialized with no whitespace). Format: pp_sig_<base64url>.

Signature & Verification.

How receipts are signed and how enforcement points verify them.

Signing algorithm

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.

Public key discovery

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.

Fail-closed enforcement

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.

SDK — TypeScript
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);
SDK — Python
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)

Receipt Lifecycle.

States a receipt moves through from issuance to enforcement.

pending

Authorization request submitted. Waiting for human approval or policy evaluation. Action cannot proceed.

issued

Receipt has been signed and issued. The action is authorized. Enforcement points will return verified: true.

expired

The receipt has passed its expires_at timestamp. Verification returns verified: false. A new authorization is required.

revoked

The receipt was explicitly revoked by an authorized admin. Verification returns verified: false. Cannot be reinstated.

FAQ.

Common questions about authority receipts, verification, and enforcement.

What is an authority receipt?

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.

How is this different from an audit log?

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.

Can a policy engine approve without a human?

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.

How do I verify a receipt at enforcement time?

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.

What happens when a receipt expires?

Verification returns verified: false with reason: 'expired'. Enforcement points fail closed. Receipts cannot be renewed; a new authorization request must be submitted.

Are receipts stored permanently?

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.

Can I attach custom metadata to a receipt?

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.

What signature algorithm is used?

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.