Draft — Not yet published. This specification is in active development and is not ready for review or critique. Stay tuned for formal announcements.

Payment Brokers

How to implement a payment servicer that processes transactions and writes attestation proofs.

What is a Broker?

A broker (or payment servicer) facilitates payment between payers and recipients on ATProtocol and acts as a witness to the exchange.

A broker is whatever facilitates the exchange of value. One broker might process Stripe transactions. Another might handle peer-to-peer cash. Another might simply witness a virtual high-five. The role is to facilitate and witness the exchange between payer and recipient, then write network.attested.payment.proof records and expose XRPC endpoints for payment initiation and verification.

Recipients publish an ordered list of broker DIDs with #AttestedNetwork service endpoints in their DID document. When a payer wants to pay a recipient, the app resolves the recipient's DID document, finds the broker endpoints, and initiates the payment flow through one of them.

Key principle: Brokers are untrusted intermediaries. The attestation proof they write is independently verifiable by anyone — the CID-based proof chain means you can confirm a payment without trusting the broker's word.

Responsibilities

DID Document Setup

Brokers must configure an #AttestedNetwork service endpoint in their DID document so recipients can discover and reference them.

When a recipient adds your broker to their supported servicers list, they reference your DID. Apps then resolve your DID document, find the #AttestedNetwork service entry, and use its serviceEndpoint as the base URL for all XRPC calls.

Add the following service entry to your DID document:

DID Document Service Entry
{
  "id": "#AttestedNetwork",
  "type": "AttestedNetworkServicer",
  "serviceEndpoint": "https://pay.example.com"
}

Note: The serviceEndpoint URL must be HTTPS and should point to the root of your XRPC service. All three payment methods (initiate, status, lookup) will be called against this base URL.

XRPC Methods to Implement

Brokers must implement three XRPC methods that apps use to initiate payments, check status, and look up verified payment records.

Procedure · POST
network.attested.payment.initiate

Initiate a new payment flow. Called by an app on behalf of a payer using inter-service auth. Returns an opaque token and a URL where the payer completes the payment in a browser.

Input

FieldTypeDescription
product string Identifier for the product or subscription being purchased. Defined by the recipient.

Output

FieldTypeDescription
token string Opaque token used to track this payment session. Pass to status to poll for completion.
url string URL where the payer completes the payment flow in a browser (e.g. a Stripe Checkout page).
Query · GET
network.attested.payment.status

Check the status of a payment initiated with a token from initiate. When completed, includes a strong reference to the proof record.

Parameters

FieldTypeDescription
token string The opaque token returned from initiate.

Output

FieldTypeDescription
status string One of "pending", "completed", or "failed".
ref com.atproto.repo.strongRef optional When status is "completed", a strong reference (URI + CID) to the network.attested.payment.proof record in the broker's repository.
Query · GET
network.attested.payment.lookup

Look up verified payment records between a payer and recipient. Used by apps to check whether a payer has an active payment for a given recipient.

Parameters

FieldTypeDescription
payer did DID of the payer.
recipient did DID of the recipient.
paymentType string optional Filter by payment collection. Must be a full NSID: network.attested.payment.oneTime, network.attested.payment.recurring, or network.attested.payment.scheduled.
brokers array(did) optional, repeating List of broker DIDs. When provided, only returns payments that have at least one validating signature from an identity in this list.
entitlements array(at-uri) optional, repeating List of entitlement AT-URIs. When provided, only returns payments whose entitlements array contains one or more of the given references.

Output

FieldTypeDescription
payments array(union) Array of verified payment records matching the query. Each element is a union of network.attested.payment.oneTime, network.attested.payment.recurring, or network.attested.payment.scheduled.

Auth model: The initiate method uses ATProtocol inter-service auth — the calling app presents a signed service token on behalf of the payer. The status and lookup methods can be called with standard auth or unauthenticated, depending on your privacy requirements.

Writing Attestation Proofs

When a payment completes, the broker writes the payment record and a corresponding attestation proof. This is the core of the system.

Steps

  1. Write the payment record (oneTime, recurring, or scheduled) to the payer's repository using inter-service auth.
  2. Compute the attestation CID per the badge.blue spec: strip signatures from the record, add a $sig field containing the payer's repository DID, DAG-CBOR serialize, SHA-256 hash, produce a CIDv1.
  3. Write a network.attested.payment.proof record to the broker's own repository containing the CID and an optional status.
  4. Update the payment record's signatures array in the payer's repo with a com.atproto.repo.strongRef pointing to the proof record.
Proof Record Example
{
  "$type": "network.attested.payment.proof",
  "cid": "bafyreig5..."
}

Payment Flow

The following diagram shows the complete flow from payment completion through proof writing:

sequenceDiagram
    participant PP as Payment Processor
    participant B as Broker
    participant PR as Payer's Repo
    participant BR as Broker's Repo

    PP->>B: Payment webhook (success)
    B->>PR: Write payment record
    PR-->>B: Record AT-URI + CID
    B->>B: Compute attestation CID
    B->>BR: Write proof record
    BR-->>B: Proof AT-URI + CID
    B->>PR: Update signatures array with strongRef
    PR-->>B: Confirmed
      

Private Payments

For payments that should not be publicly visible, brokers manage Permissioned Data Spaces on behalf of the payer.

When a payment is marked as private, the broker additionally creates a permissioned space in the payer's repository and ensures that only the relevant parties — the payer, the recipient, and the broker itself — have read access to the payment record.

The attestation mechanics are identical to public payments. The proof record is still written to the broker's repository and the CID chain is still independently verifiable. The only difference is that the underlying payment record lives inside a permissioned space rather than being publicly readable.

Implementation note: The broker must have write access to the payer's permissioned data space collection. This is granted via the same inter-service auth mechanism used for writing payment records. Ensure your access control logic correctly scopes permissions to only the records your broker manages.

Invalidation

When support ends — whether through cancellation, failed retries, or refund — the broker should invalidate the attestation proof.

Guidance, not requirements. The following invalidation and retry processes are suggested patterns, not enforced rules. Brokers are free to implement whatever process they believe to be appropriate for their use case and their users.

To invalidate a payment, the broker deletes or updates its network.attested.payment.proof record and notifies the recipient. Apps that verify payments will see the proof is missing or marked invalid and treat the payment as no longer active.

Recurring Payment Retries

For recurring payments, a failed charge does not immediately invalidate the attestation. The broker should follow this retry schedule:

Grace period: During the 8-day retry window, the existing proof record remains valid. The payer's access should not be interrupted while retries are in progress. Only after the grace period expires and all retries have failed should the broker invalidate the proof.