> ## Documentation Index
> Fetch the complete documentation index at: https://docs.brandfetch.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Pay per request

> Use the Brand API and the Brand Context API without an account, one x402 or MPP payment at a time

The [Brand API](/brand-api/overview) and the [Brand Context API](/brand-context-api/overview) accept three kinds of credential: an API key, an [x402](https://x402.org) payment for the one request, or an [MPP](https://mpp.dev) payment for the one request. An agent that can pay and has no Brandfetch account sends the request bare, receives a `402 Payment Required` that prices it, pays it, retries, and gets the data with a receipt. Nothing to sign up for, nothing to store between requests.

Payments are made in USDC on Base (`eip155:8453`) with the x402 `exact` scheme: your wallet signs a transfer authorization for the exact amount, a facilitator verifies it before the request is served, and the transfer is settled on-chain before the response is returned — which is why the response carries the receipt. Your wallet needs USDC; gas is paid by the facilitator.

## Prices

| Route                                                                                    | Price per request                  | Charged for                                                                        |
| ---------------------------------------------------------------------------------------- | ---------------------------------- | ---------------------------------------------------------------------------------- |
| `GET /v2/brands/*` — the [Brand API](/reference/brand-api-domain), every identifier type | \$0.10                             | `200`, `304` and `404` responses, the same outcomes a subscription credit pays for |
| `GET /v2/context/*` — the [Brand Context API](/reference/brand-context-api)              | \$0.10                             | `200` responses only                                                               |
| `POST /v2/agents/access?usd=N` — [standing access](#standing-access)                     | $N, whole dollars from $1 to \$500 | A settled payment, even if the response carrying the key fails                     |

On the two data routes, any other outcome, an error on our side or a rate limit for instance, is not settled and costs nothing. The Brand Search API is free and has no price. The HEAD prefetch and transaction routes take API keys only.

## The flow

<Steps>
  <Step title="Ask, and receive the price">
    Send the request without an `Authorization` header. The answer is a `402` whose `PAYMENT-REQUIRED` header is the challenge, base64-encoded JSON, and whose body says the same in prose for whoever is reading. The challenge is issued for this one request and is valid for five minutes.

    ```bash theme={null}
    curl -si https://api.brandfetch.io/v2/brands/nike.com
    ```

    ```http theme={null}
    HTTP/2 402
    content-type: application/json
    cache-control: no-store
    payment-required: eyJ4NDAyVmVyc2lvbiI6MiwiZXJyb3IiOiJQYXltZW50IHJlcXVpcmVkIiwicmVzb3VyY2UiOn...
    www-authenticate: Payment id="qB3wErTyU7iOpAsD9fGhJk", realm="api.brandfetch.io", method="tempo", intent="charge", request="eyJhbW91bnQiOi..."

    {
      "message": "Payment required. Either authenticate with a Brandfetch API key (Authorization: Bearer <key>) or pay for this request with x402: sign the payment described in the PAYMENT-REQUIRED header and retry with a PAYMENT-SIGNATURE header.",
      "pricing": { "route": "GET /v2/brands/*", "price": "$0.10" },
      "resource": "https://api.brandfetch.io/v2/brands/nike.com",
      "standingAccess": "For many requests, POST /v2/agents/access (paid the same way) provisions an API key preloaded with prepaid credits.",
      "documentation": "https://docs.brandfetch.com/agents/pay-per-request"
    }
    ```

    The `www-authenticate` header beside it quotes the same request over MPP; [Paying with MPP](#paying-with-mpp) covers that lane.

    Decoded, the `PAYMENT-REQUIRED` header lists the ways to pay. There is one: the exact amount in USDC's six decimals, on Base, to Brandfetch's receiving address.

    ```json Decoded PAYMENT-REQUIRED theme={null}
    {
      "x402Version": 2,
      "error": "Payment required",
      "resource": { "url": "https://api.brandfetch.io/v2/brands/nike.com" },
      "accepts": [
        {
          "scheme": "exact",
          "network": "eip155:8453",
          "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
          "amount": "100000",
          "payTo": "0x…",
          "maxTimeoutSeconds": 300
        }
      ]
    }
    ```
  </Step>

  <Step title="Sign the payment and retry">
    An x402 client library turns the challenge into a signed payment and repeats the request with it in a `PAYMENT-SIGNATURE` header. Both examples below do the whole round trip: the bare request, the signature, the retry.

    <CodeGroup>
      ```typescript TypeScript theme={null}
      import { wrapFetchWithPaymentFromConfig, decodePaymentResponseHeader } from "@x402/fetch";
      import { ExactEvmScheme } from "@x402/evm";
      import { privateKeyToAccount } from "viem/accounts";

      const account = privateKeyToAccount(process.env.WALLET_PRIVATE_KEY as `0x${string}`);
      const fetchWithPayment = wrapFetchWithPaymentFromConfig(fetch, {
        schemes: [{ network: "eip155:*", client: new ExactEvmScheme(account) }],
      });

      const response = await fetchWithPayment("https://api.brandfetch.io/v2/brands/nike.com");
      const brand = await response.json();
      const receipt = decodePaymentResponseHeader(response.headers.get("PAYMENT-RESPONSE")!);
      console.log(brand.name, receipt.transaction);
      ```

      ```python Python theme={null}
      # pip install "x402[evm,httpx]"
      import os

      import httpx
      from eth_account import Account
      from x402 import x402ClientSync
      from x402.http.utils import (
          decode_payment_required_header,
          decode_payment_response_header,
          encode_payment_signature_header,
      )
      from x402.mechanisms.evm.exact.client import ExactEvmScheme

      account = Account.from_key(os.environ["WALLET_PRIVATE_KEY"])
      url = "https://api.brandfetch.io/v2/brands/nike.com"

      with httpx.Client() as http:
          challenge = http.get(url)  # 402
          required = decode_payment_required_header(challenge.headers["payment-required"])
          client = x402ClientSync()
          for option in required.accepts:
              client.register(option.network, ExactEvmScheme(account))
          payment = encode_payment_signature_header(client.create_payment_payload(required))

          paid = http.get(url, headers={"PAYMENT-SIGNATURE": payment})
          brand = paid.json()
          receipt = decode_payment_response_header(paid.headers["payment-response"])
      ```
    </CodeGroup>

    Each signature is a fresh authorization with its own nonce. Sign once per request: a signature that has been settled cannot buy a second request, and presenting it again is refused with a `402`.
  </Step>

  <Step title="Read the data and the receipt">
    The paid response is the same JSON an API key would receive, plus a `PAYMENT-RESPONSE` header carrying the settlement receipt, base64-encoded.

    ```json Decoded PAYMENT-RESPONSE theme={null}
    {
      "success": true,
      "transaction": "0x13fb6ca9025e84ce4f03512459a15dc58cb9e0554a3462301558419b05022a7f",
      "network": "eip155:8453",
      "payer": "0x7848b5a4b1552993820b46693832ed3006e86b65"
    }
    ```

    Paid requests are attributed to the paying wallet, not to any account, so there is no quota: the `x-api-key-quota` header is absent and there is nothing to run out of.
  </Step>
</Steps>

## Paying with MPP

The same two routes also take [MPP](https://mpp.dev) payments — the Machine Payments Protocol Stripe and Tempo co-authored — settled through Stripe. The unpaid `402` carries one `WWW-Authenticate: Payment …` challenge per method next to `PAYMENT-REQUIRED`, and an MPP client answers with an `Authorization: Payment …` credential instead of a `PAYMENT-SIGNATURE` header.

```http theme={null}
HTTP/2 402
payment-required: eyJ4NDAyVmVyc2lvbiI6Miw...
www-authenticate: Payment id="qB3wErTyU7iOpAsD9fGhJk", realm="api.brandfetch.io", method="tempo", intent="charge", request="eyJhbW91bnQiOi..."
```

* **Methods.** USDC.e on Tempo from a cent, so every per-request price qualifies. Cards via Stripe shared payment tokens start at \$0.50, above these prices, so they do not appear on the per-request routes — they do on [standing access](#standing-access).
* **Clients.** `npx mppx@latest` (the reference CLI), the [Tempo CLI](https://tempo.xyz/developers/docs/cli) (`tempo request <url>`), or the `mppx` TypeScript client. Each reads the challenge, pays, and retries with the credential.
* **Receipt.** A paid response carries `Payment-Receipt` (base64url JSON: `method`, `reference`, `status`, `timestamp`) and `Cache-Control: private`.
* **Same rules.** You are charged only for the outcomes listed under [Prices](#prices); a refused or unsettled credential is answered with a `402` carrying fresh challenges for both protocols and a `reason`, and nothing is charged. A credential pays for one request: presented again for another, it is refused as `credential_spent`; presented twice at once, the second is refused as `credential_in_use` — retry that exact request in a moment. [Standing access](#standing-access) is sold over MPP too.
* **Lost a paid response?** Retry the exact request with the same credential within two minutes: it is served from the payment already taken and not charged again. After that window a used credential is refused like any other. A [standing access](#standing-access) purchase is different: its key is returned once, and a failed purchase response is [recovered its own way](#buying-standing-access).

Both examples below do the whole round trip: the bare request, the credential, the retry.

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { Fetch, tempo } from "mppx/client";
  import { privateKeyToAccount } from "viem/accounts";

  const account = privateKeyToAccount(process.env.WALLET_PRIVATE_KEY as `0x${string}`);
  const fetch = Fetch.from({ methods: [tempo({ account })] });

  const response = await fetch("https://api.brandfetch.io/v2/brands/nike.com");
  const brand = await response.json();
  console.log(brand.name, response.headers.get("Payment-Receipt"));
  ```

  ```bash CLI theme={null}
  export MPPX_PRIVATE_KEY=0x…
  npx mppx@latest https://api.brandfetch.io/v2/brands/nike.com --protocol mpp
  ```
</CodeGroup>

## When something goes wrong

Every refusal below charges nothing and withholds the resource.

| Response                                                                                                         | Meaning                                                                                                                                                                                      | What to do                                                                                                                                                                                                                                                 |
| ---------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `402` with a `reason` and the message "The payment was not accepted"                                             | The facilitator refused to verify the payment: insufficient USDC, a mismatched amount, network or recipient, an expired challenge, or a signature that was already used                      | Fix the cause, request a fresh challenge and sign again                                                                                                                                                                                                    |
| `402` with a `reason` and the message "The payment could not be settled"                                         | Verification passed but the on-chain settlement failed, occasionally a transient failure at the facilitator                                                                                  | Sign a fresh payment and retry once                                                                                                                                                                                                                        |
| `402` with `reason: credential_spent`                                                                            | The MPP credential already paid for a request. Each one pays for exactly one                                                                                                                 | Answer a fresh `WWW-Authenticate: Payment` challenge and retry                                                                                                                                                                                             |
| `402` with `reason: credential_in_use`                                                                           | Another request of yours is settling the same credential                                                                                                                                     | Retry that exact request in a moment to receive what it paid for                                                                                                                                                                                           |
| `402` with `reason: credential_malformed`                                                                        | The `Authorization: Payment …` credential could not be read                                                                                                                                  | Answer a fresh challenge and retry                                                                                                                                                                                                                         |
| `402` with `reason: nonce_already_used`, `transaction_rejected`, `transaction_reverted` or `transaction_expired` | The Tempo transaction in the MPP credential cannot complete: the network refused it for good, it reverted, or its validity window closed before it was included. The transfer did not happen | Fix the cause (for `nonce_already_used`, sign with a fresh nonce), answer one of the fresh challenges the response carries and retry. Paying in parallel from one wallet: give each payment its own nonce                                                  |
| `402` with `reason: challenge_invalid`                                                                           | The MPP credential does not answer a challenge this API issued                                                                                                                               | Answer one of the fresh challenges the response carries and retry. On a retry of a standing-access purchase you already paid for, see [Buying standing access](#buying-standing-access) instead                                                            |
| `503` with `Retry-After`                                                                                         | The payment service could not be reached                                                                                                                                                     | Retry after the interval                                                                                                                                                                                                                                   |
| `503` with `Retry-After`, after an MPP credential was sent                                                       | The payment service could not be reached, or whether the payment went through is not known yet, so the request was not served                                                                | Retry the exact request with the same credential after the interval. Do not sign a new payment for it: a payment that did go through is not charged twice                                                                                                  |
| `403`                                                                                                            | An `Authorization: Bearer` header was sent and its API key is invalid                                                                                                                        | A request that carries a bearer key is authenticated with it, and a `PAYMENT-SIGNATURE` header alongside it is ignored. Drop the header to pay with x402 instead. `Authorization: Payment …`, the MPP credential, is not affected: it is read as a payment |

If a Brand API or Brand Context API request itself fails, a `500` for instance, the payment is not settled: the authorization you signed simply lapses.

### Buying standing access

A purchase is settled before its key is issued, so some of its failures follow a payment that was taken. None of these answers carries a key, and apart from a refused settlement none asks for a new payment; each says what to do instead. The `409` answers, the `500` answers that name a payment and `503` `payment_outcome_unknown` carry the payment's `paymentReference`.

| Response                                                                           | Meaning                                                                                                                                                     | What to do                                                                                                                                                                                                                                    |
| ---------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `402` telling you to retry this exact request once before signing a new payment    | The settlement was refused                                                                                                                                  | Retry the exact request once: if another attempt settled the same payment, the retry is answered from it. Refused the same way again, the payment was not taken: send the request without a payment for a fresh challenge, and sign a new one |
| `402` with `reason: challenge_invalid`, on a retry of an MPP purchase you paid for | The challenge that credential answered is no longer honoured, so the key cannot be returned. The purchase is complete: its credits are on your organization | Do not answer the fresh challenges to recover the key. A Tempo wallet pays again with `rotateKey=true` for a working key; for a card purchase, contact support                                                                                |
| `409` with `reason: payment_in_progress` and `Retry-After`                         | Another request carrying the same payment is completing the purchase, and its response carries the key                                                      | Wait for that response. If it does not arrive, retry the exact request after the interval. Do not pay again                                                                                                                                   |
| `409` with `reason: credential_already_delivered`                                  | The key was returned with the response that completed the purchase, and is not returned again. The credits are on the organization the body names           | Use the key you stored. To replace a lost one, pay again from the same wallet with `rotateKey=true`. A card purchase cannot be recovered: make a new purchase                                                                                 |
| `409` with `reason: credential_replaced`                                           | A later rotation replaced the key this payment bought, so it no longer works. The organization's credits, these included, are intact                        | Pay again from the same wallet with `rotateKey=true` for a working key. For a card purchase, contact support with the `paymentReference`                                                                                                      |
| `500` telling you to retry this exact request to receive your credential           | The purchase did not finish, possibly after the payment was taken                                                                                           | Retry the exact request at once. The first request carrying the payment that succeeds within three minutes of the payment receives the key; no later one does                                                                                 |
| `500` telling you not to pay again                                                 | The payment may have been taken, but its key can no longer be delivered automatically, for instance because those three minutes have passed                 | Do not pay again: contact support with the `paymentReference`                                                                                                                                                                                 |
| `500` without a `paymentReference`                                                 | An unexpected error                                                                                                                                         | Retry the exact request: a payment is never charged twice, and the retry's answer says what happened to it. Do not sign a new payment for it                                                                                                  |
| `503` with `reason: payment_outcome_unknown` and `Retry-After`                     | Whether the payment went through is not known yet                                                                                                           | Retry the exact request after the interval. Do not sign a new payment for it                                                                                                                                                                  |

## Standing access

One payment per request suits a handful of calls. For more, buy standing access once and use an ordinary API key from then on:

<Steps>
  <Step title="Read the offer">
    `GET https://api.brandfetch.io/v2/agents/access` needs no credential and describes the deal: 20 prepaid credits per dollar, from $1 to $500 in whole dollars, one credit per Brand API or Brand Context API request, and the steps to pay. The full shape is in the [reference](/reference/agents-access-offer).
  </Step>

  <Step title="Pay for it">
    `POST https://api.brandfetch.io/v2/agents/access?usd=5` without a payment answers a `402` quoting $5 both ways: the x402 challenge in `PAYMENT-REQUIRED`, the MPP challenges in `WWW-Authenticate` — here a card (through a Stripe shared payment token) is on offer beside USDC.e on Tempo, because $1 and up clears Stripe's card minimum. The same request with the signed x402 payment in `PAYMENT-SIGNATURE`, or with the MPP credential in `Authorization: Payment …`, completes the purchase. Its response carries `Cache-Control: private` and the settlement receipt: `PAYMENT-RESPONSE` for x402, `Payment-Receipt` for MPP. The clients above handle it the same way as a brand request.

    ```json 201 Created theme={null}
    {
      "organization": { "id": "xig9b54wddtihs0dktyhau0i", "urn": "urn:brandfetch:organization:xig9b54wddtihs0dktyhau0i" },
      "apiKey": { "id": "…", "key": "…", "name": "Agent Key" },
      "apiClient": { "clientId": "…" },
      "mcp": { "url": "https://mcp.brandfetch.io/mcp", "token": "bf1.…" },
      "credits": { "granted": 100, "balance": 100, "creditsPerUsd": 20, "usdPaid": 5, "deduplicated": false },
      "usage": {
        "authorization": "Bearer …",
        "note": "Every metered response carries x-api-key-quota (credits remaining). A 403 means the balance is spent — top up."
      },
      "topUp": {
        "method": "POST",
        "url": "https://api.brandfetch.io/v2/agents/access",
        "note": "This key is returned once, in this response: store it. Pay again from the same wallet to add credits to this key. Add rotateKey=true to replace the key while doing so, which is also how to recover a lost key."
      },
      "documentation": "https://docs.brandfetch.com/agents/overview"
    }
    ```

    Store the key and the MCP token: they are returned once, in this response, and never again, not even to a repeat of the same request. The first purchase from a wallet — an x402 wallet on Base or a Tempo wallet over MPP — answers `201` and creates its organization; later ones answer `200` and add credits to the same key. A card names no wallet, so every card purchase answers `201` with its own organization and key, and cannot be topped up: keep the key. A card purchase carries the `topUp` block too, with a note saying exactly that: pay from an x402 or Tempo wallet instead to add credits to the key that wallet owns.
  </Step>

  <Step title="Use the key">
    Send `Authorization: Bearer <key>` like any API key. Every metered response carries `x-api-key-quota`, the credits remaining; a `403` means the balance is spent. Pay again from the same wallet to top the key up, and add `rotateKey=true` to replace the key while doing so. The response carries the new key, returned once like any other, holding the combined balance; the wallet's earlier keys stop working once the new key has been returned, even if your client never receives that response. If the rotation is answered with an error instead of the new key, the old one keeps working. If you never saw its response at all, retry the exact request: a `409` `credential_already_delivered` means the rotation completed and the earlier keys no longer work, so pay again from the same wallet with `rotateKey=true` for a new one. The `mcp.token` connects the [MCP server](/mcp/overview) to the same organization: send it as a bearer token.
  </Step>
</Steps>

A payment is never charged twice, and the key it bought is never returned twice: presenting a payment again proves nothing about who sent it (an x402 signature is public on-chain once settled), so a request carrying a payment whose key was delivered is answered `409` `credential_already_delivered` without it. If the purchase is answered with a `500` that says to retry, or with no response at all, retry the exact request at once: the first retry to succeed within three minutes of the payment receives the key, unless the key was already returned in a response your client lost, which is answered `409` `credential_already_delivered`. A retry that receives the key does so with `credits.deduplicated: true` if the failed attempt had already granted the credits, and without the settlement receipt header. The credits are granted even when the key can no longer be returned: any retry carrying the payment completes the purchase. [Buying standing access](#buying-standing-access) lists every answer and what to do; the complete contract is in the [reference](/reference/agents-access-purchase).
