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
- Accept payment initiation requests via XRPC from apps acting on behalf of payers
- Facilitate the actual exchange (Stripe transaction, peer-to-peer cash, or any other mechanism)
- Write payment records to the payer's repository via inter-service auth
- Compute attestation CIDs and write proof records to the broker's own repository
- Expose status and lookup endpoints so apps can verify payment state
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:
{ "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.
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
| Field | Type | Description |
|---|---|---|
| product | string | Identifier for the product or subscription being purchased. Defined by the recipient. |
Output
| Field | Type | Description |
|---|---|---|
| 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). |
Check the status of a payment initiated with a token from initiate. When completed, includes a strong reference to the proof record.
Parameters
| Field | Type | Description |
|---|---|---|
| token | string | The opaque token returned from initiate. |
Output
| Field | Type | Description |
|---|---|---|
| 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. |
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
| Field | Type | Description |
|---|---|---|
| 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
| Field | Type | Description |
|---|---|---|
| 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
- Write the payment record (
oneTime,recurring, orscheduled) to the payer's repository using inter-service auth. - Compute the attestation CID per the badge.blue spec: strip signatures from the record, add a
$sigfield containing the payer's repository DID, DAG-CBOR serialize, SHA-256 hash, produce a CIDv1. - Write a
network.attested.payment.proofrecord to the broker's own repository containing the CID and an optionalstatus. - Update the payment record's
signaturesarray in the payer's repo with acom.atproto.repo.strongRefpointing to the proof record.
{ "$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:
- Day 1: First retry attempt after the initial charge failure.
- Day 3: Second retry attempt.
- Day 7: Third and final retry attempt.
- Day 8 (grace period expires): If all retries have failed, the broker deletes the proof record and notifies the recipient that the payment is no longer active.
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.