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

# Create top up checkout

> Open a checkout that adds credits to the monthly plan, and answer the link a person pays at.

Opens a Whop checkout for a top-up: credits added to the account's monthly plan, priced at that plan's own rate and never above a one-time pack of the same size. The answer is a link for a person to open and pay at, with the credits and the price: nothing is charged by this call, and the credits land on the account once that person pays. They expire 30 days after that payment, as a plan payment's own credits do, and are spent before credits that never expire. list_plans names the amounts a top-up takes, under topUp, and any other amount is refused with invalid_amount. The account needs a live monthly plan, cancelled or not: without one the call is refused with no_subscription, and create_checkout sells a one-time pack instead. Hand the link to the person you are working for rather than trying to open it yourself. Needs a key with the write scope.

`POST https://api.leadity.io/v1/billing/top-up`

- Scope: `write`
- Spends credits: no
- MCP tool: `create_top_up_checkout`

## Headers

- `Authorization`, string, required. Bearer, a space, then an API key: Bearer lk_api_... An MCP key is refused here with wrong_key_kind.
- `Content-Type`, string, required. application/json

## Body parameters

- `credits`, integer, required. How many credits to add: one of the amounts list_plans names under topUp, e.g. 5000.

## Example request

```bash cURL
curl -X POST "https://api.leadity.io/v1/billing/top-up" \
  -H "Authorization: Bearer $LEADITY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "credits": 5000
  }'
```

```javascript Node.js
const response = await fetch("https://api.leadity.io/v1/billing/top-up", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.LEADITY_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "credits": 5000
  }),
});

const data = await response.json();
console.log(data);
```

```python Python
import os

import requests

response = requests.post(
    "https://api.leadity.io/v1/billing/top-up",
    headers={
        "Authorization": f"Bearer {os.environ['LEADITY_API_KEY']}",
    },
    json={"credits": 5000},
)

print(response.json())
```

## Response

- `purchaseUrl`, string, required. The checkout link. A person opens it and pays there.
- `credits`, integer, required. The credits the top-up adds once it is paid.
- `priceCents`, integer, required. What the person pays at the link, in US cents.

## Example response

```json 200
{
  "purchaseUrl": "https://whop.com/checkout/plan_4mT8xQ2rKb7/",
  "credits": 5000,
  "priceCents": 12250
}
```

## Errors

Every refusal answers `{ error, message }` with the status below. The full list is on the [Errors](https://docs.leadity.io/errors) page.

| Code | Status | Meaning | Extra fields |
| --- | --- | --- | --- |
| `unauthorized` | 401 | The API key is missing, malformed, revoked or expired. | - |
| `wrong_key_kind` | 401 | This key opens the other surface: an API key works on the HTTP API, an MCP key on the MCP server. | - |
| `insufficient_scope` | 403 | The key does not carry the scope this operation needs. | `requiredScope`: The scope the operation needs: read, write or spend. |
| `account_suspended` | 403 | The account is suspended. | - |
| `email_not_verified` | 403 | The account's email address is not verified yet. | - |
| `invalid_body` | 400 | The request does not match the operation's schema. | `issues`: The problems found, each with path (the field as a dotted path, led by the part of the request it travels in: path, query or body, such as body.items.1) and message (what is wrong there). |
| `invalid_amount` | 400 | The credits are not an amount a top-up takes. The body carries min, max and step. | `min`: On create_top_up_checkout: the smallest top-up, in credits. `max`: On create_top_up_checkout: the largest top-up one purchase may be, in credits. `step`: Every top-up is a whole multiple of this many credits. |
| `no_subscription` | 409 | A top-up adds credits to a monthly plan, and the account has no live plan. create_checkout sells a one-time pack instead. | - |
| `unpriceable_plan` | 409 | The account's plan carries no price a top-up can be rated at. Contact Leadity support. | - |
| `checkout_failed` | 502 | Whop did not open the checkout. Try again. | - |
| `rate_limited` | 429 | Too many requests. Wait for the Retry-After seconds and try again. | `retryAfterSeconds`: The seconds to wait, the same number as the Retry-After header. |
| `try_again` | 503 | Leadity could not answer just now. Retry in a moment, with the same Idempotency-Key on a spending call. | `retryAfterSeconds`: When a request with this Idempotency-Key is still being processed: the seconds to wait before retrying with the same key, as the Retry-After header says. |
| `internal_error` | 500 | Something failed on our side. Nothing was charged twice. | `body`: On the MCP server, when Leadity answered in a shape the tool does not publish: that answer as it came. |
