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

# Paying as an agent

> Buy a permanent link with no account, over MPP or x402.

<Warning>
  **Not enabled yet.** Neither payment rail is configured on `api.kealinks.com`
  today, so `GET /api/pricing` returns empty `protocols` and `prices`, and an
  unauthenticated `POST /api/links` returns `401`, not the `402` described below.
  That is deliberate: we would rather refuse you outright than quote a price
  nothing can pay.

  Everything on this page is implemented and tested — it is waiting on payment
  provisioning, not on code. **`protocols` in `/api/pricing` is the authoritative
  answer** to whether a deployment can take your money. Read it first, and treat
  an empty array as "not yet".
</Warning>

You do not need to sign up, verify an email, or have a human present. Ask for a
link, get a price, pay it, get the link.

<Card title="One payment, one permanent link" icon="link">
  **\$2.00.** One-time. It buys one code that never stops resolving — including
  after you have stopped paying us anything at all, which for a one-time purchase
  is immediately. There is no renewal and nothing to cancel.
</Card>

## Discover the price first

```bash theme={null}
curl https://api.kealinks.com/api/pricing
```

```json theme={null}
{
  "protocols": ["mpp", "x402"],
  "prices": [
    {
      "product": "permanent_link",
      "amount": "2.00",
      "currency": "usd",
      "description": "One permanent short link and dynamic QR code. Repointable, and it never stops resolving — including after you stop paying us anything."
    }
  ],
  "subscription": "For a human account with custom domains, analytics and teammates, see POST /api/billing/checkout — A$19/month for 100 new links per billing cycle, or A$49/month with no per-cycle cap."
}
```

This is the authoritative price. Read it rather than hard-coding the number from
this page — and note `protocols`, which tells you which of the two rails below
this deployment actually speaks.

## The flow

<Steps>
  <Step title="Ask, without credentials">
    ```bash theme={null}
    curl -i -X POST https://api.kealinks.com/api/links \
      -H "Content-Type: application/json" \
      -d '{"destination": "https://example.com/thing"}'
    ```
  </Step>

  <Step title="Get a 402 carrying both offers">
    ```http theme={null}
    HTTP/1.1 402 Payment Required
    WWW-Authenticate: Payment id="8f3...", realm="api.kealinks.com",
      method="stripe", intent="charge", request="eyJhbW91bnQiOiIyMDAi...",
      expires="2026-08-21T12:05:00.000Z"
    PAYMENT-REQUIRED: eyJ4NDAyVmVyc2lvbiI6Miwi...
    Accept-Payment: mpp, x402
    Content-Type: application/json
    ```

    ```json theme={null}
    {
      "error": "Payment required. This buys one permanent link — a code that never stops resolving, including after you stop paying us anything. Pay one of the challenges on this response and retry the same request.",
      "price": "2.00",
      "currency": "usd",
      "pay": ["mpp", "x402"],
      "docs": "https://docs.kealinks.com/agent-payments"
    }
    ```
  </Step>

  <Step title="Pay whichever you support, and retry the same request">
    Send the identical body again with your payment credential attached.
  </Step>

  <Step title="Get the link, a receipt, and a key">
    ```json theme={null}
    {
      "id": "lnk_2YgQk1p8fT3mN7wCxRvBdLsHjZa",
      "slug": "m4rq7bd",
      "destination": "https://example.com/thing",
      "host": null,
      "status": 1,
      "short_url": "https://kea.link/m4rq7bd",
      "api_key": "klk_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
      "receipt": "pi_3Q..."
    }
    ```
  </Step>
</Steps>

<Warning>
  **`api_key` is shown exactly once**, on the response to the payment that
  created your account. Store it. The link resolves forever whether or not you
  keep the key — but without it you can never repoint the code, and repointing is
  the reason to use a dynamic code at all.

  It appears only on the *first* purchase of a new machine account. Later
  purchases by the same payer top up the same account and return no key.
</Warning>

## MPP (Stripe + Tempo)

[MPP](https://mpp.dev) settles to a card via a Shared Payment Token, or in
stablecoin. Send the credential in the `Authorization` header:

```http theme={null}
POST /api/links HTTP/1.1
Authorization: Payment eyJjaGFsbGVuZ2UiOnsiaWQiOiI4ZjMi...
Content-Type: application/json

{"destination": "https://example.com/thing"}
```

The credential is base64url JSON:

```json theme={null}
{
  "challenge": { "id": "8f3...", "realm": "api.kealinks.com", "method": "stripe", "intent": "charge", "request": { "amount": "200", "currency": "usd", "...": "..." } },
  "payload": { "spt": "spt_..." },
  "source": "did:pkh:eip155:1:0x..."
}
```

Echo the challenge back **unmodified**. Its `id` is an HMAC over its own
parameters, so an edited amount, recipient or expiry produces an id we cannot
re-derive and the payment is refused with a `400`.

On success you get `Payment-Receipt`, base64url JSON:

```json theme={null}
{ "method": "stripe", "status": "success", "reference": "pi_3Q...", "timestamp": "2026-08-21T12:00:03.000Z" }
```

Most clients handle all of this for you:

```bash theme={null}
npx @stripe/link-cli mpp pay https://api.kealinks.com/api/links \
  -X POST -d '{"destination":"https://example.com/thing"}'
```

## x402

[x402 v2](https://x402.org) settles stablecoin on-chain — USDC on Base by
default. Decode `PAYMENT-REQUIRED` for the requirements:

```json theme={null}
{
  "x402Version": 2,
  "accepts": [
    {
      "scheme": "exact",
      "network": "eip155:8453",
      "amount": "2000000",
      "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "payTo": "0x...",
      "maxTimeoutSeconds": 300,
      "extra": { "name": "USD Coin", "version": "2" }
    }
  ],
  "resource": {
    "url": "https://api.kealinks.com/api/links",
    "serviceName": "kealink",
    "description": "One permanent short link and dynamic QR code. Resolves forever."
  }
}
```

`amount` is atomic units: `2000000` is \$2.00 of a six-decimal USDC. Sign an
EIP-3009 or Permit2 authorisation and retry with `PAYMENT-SIGNATURE`:

```http theme={null}
POST /api/links HTTP/1.1
PAYMENT-SIGNATURE: eyJ4NDAyVmVyc2lvbiI6MiwiYWNjZXB0ZWQi...
```

You get `PAYMENT-RESPONSE` back with the settlement, including the transaction
hash.

<Note>
  We compare the `accepted` block you echo against the requirements we compute
  fresh for your request, and forward only ours to the facilitator. A payment for
  the wrong amount, asset or recipient is refused with a `400` before anything is
  settled. Fetch a new `402` rather than adjusting the numbers yourself.
</Note>

## Topping up an account you already have

Send both schemes in one `Authorization` header, or an `Authorization: Bearer`
alongside `PAYMENT-SIGNATURE`. The credit lands on the account the key belongs to
and no new key is issued.

```http theme={null}
Authorization: Bearer klk_XXXXXXXX, Payment eyJjaGFsbGVuZ2Ui...
```

A key that does not resolve is refused outright rather than ignored — your credit
will never silently land on a stranger's account because you mistyped it.

## Rules worth knowing before you build

<AccordionGroup>
  <Accordion title="A payment credential is spendable exactly once">
    Replaying one returns `409`. Permanent links cannot be un-issued, so a double
    spend is not something we could correct afterwards. For MPP the key is the
    challenge id; for x402 it is the transfer authorisation nonce.
  </Accordion>

  <Accordion title="Challenges expire after five minutes">
    An expired one returns `402`. Retry with no credential to get a fresh
    challenge — do not edit the `expires` field, which is covered by the HMAC.
  </Accordion>

  <Accordion title="A machine account gets exactly what it paid for">
    No free links on top. The free tier's cost of entry is a verified email
    address, and a machine account has never had one. When your credits are spent,
    `POST /api/links` returns `402` telling you to buy another.
  </Accordion>

  <Accordion title="Your paid link starts quarantined, like every other link">
    Paying does not buy trust, and it does not have to: a quarantined link
    resolves normally. See [Quarantine](/quarantine).
  </Accordion>

  <Accordion title="A failed payment creates nothing">
    If settlement fails the claim is released, so you can retry with a working
    instrument. No link, no account, no charge.
  </Accordion>
</AccordionGroup>
