> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.trygrant.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.trygrant.com/_mcp/server.

# Credit packs

A credit pack lets a customer buy more credits for an existing subscription. Each pack belongs to a plan and defines how much one block of credits costs. A completed purchase adds a credit grant to the subscription.

## How credit packs work

A pack has four main parts:

| Field                   | Purpose                                                                                 |
| ----------------------- | --------------------------------------------------------------------------------------- |
| `pricing_unit`          | The unit the customer buys, such as API credits or tokens                               |
| `money_minor`           | The price in the plan currency's smallest unit, such as cents                           |
| `unit_amount`           | The number of credits sold for `money_minor`                                            |
| `expiration_interval_*` | How long purchased credits remain valid; both fields are `null` when they do not expire |

For example, `money_minor: "100"` and `unit_amount: "2500"` means the customer pays \$1.00 for 2,500 credits when the plan uses USD.

Grant calculates the purchase total from the selected credit quantity and rounds the result to the plan currency's smallest unit.

## Before you begin

In the [Grant dashboard](https://www.trygrant.com/dashboard):

1. Create the pricing unit that the pack will grant.
2. Add the pricing unit to a billing plan.
3. Create a credit pack on that plan and set its price and optional expiry.
4. Make sure the customer has an `active`, `trialing`, or `past_due` subscription to the same plan.

Use the pack's `id` in API calls. Pack codes are labels for people and are not accepted in place of `credit_pack_id`.

## 1. List a plan's credit packs

Use the plan ID to find every pack available for that plan.

```bash
curl https://api.trygrant.com/v1/plans/plan_123/credit-packs \
  -H "Authorization: Bearer ak_live_YOUR_API_KEY"
```

```json title="Response"
{
  "success": true,
  "credit_packs": [
    {
      "id": "credit_pack_123",
      "plan_id": "plan_123",
      "code": "100-pack",
      "pricing_unit_id": "pricing_unit_123",
      "pricing_unit": {
        "id": "pricing_unit_123",
        "code": "credits",
        "name": "Credits"
      },
      "money_minor": "100",
      "unit_amount": "2500",
      "expiration_interval_count": 3,
      "expiration_interval_unit": "month"
    }
  ],
  "request_id": "req_abc123"
}
```

See [List credit packs](/api-reference/grant-events-api/credit-packs/list) for the full response.

## 2. Retrieve one pack

Fetch a pack by ID when you need to show its price or confirm its expiry rules.

```bash
curl https://api.trygrant.com/v1/credit-packs/credit_pack_123 \
  -H "Authorization: Bearer ak_live_YOUR_API_KEY"
```

See [Retrieve a credit pack](/api-reference/grant-events-api/credit-packs/get).

## 3. Create a checkout link

Credit packs are bought through a hosted checkout page. Create a link for the customer's subscription, then send its URL to that customer. Each link expires 24 hours after creation and completes after one purchase.

### Set the quantity

Pass `quantity` when you know how many credits the customer will buy. The value is a number of pricing units, not a number of pack bundles.

```bash
curl -X POST https://api.trygrant.com/v1/credit-pack-checkout-links \
  -H "Authorization: Bearer ak_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "subscription_id": "subscription_123",
    "credit_pack_id": "credit_pack_123",
    "quantity": 5000,
    "success_url": "https://example.com/billing/success",
    "back_url": "https://example.com/billing"
  }'
```

The hosted page shows the fixed credit amount and its total price. The pack must belong to the subscription's plan.

### Let the customer choose

Omit `quantity`, or pass `null`, to let the customer choose a purchase amount on the hosted page. Grant shows how many credits that amount buys at the pack's rate.

```bash
curl -X POST https://api.trygrant.com/v1/credit-pack-checkout-links \
  -H "Authorization: Bearer ak_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "subscription_id": "subscription_123",
    "credit_pack_id": "credit_pack_123"
  }'
```

### Use the returned URL

The response includes the hosted checkout URL and its expiry time.

```json title="Response"
{
  "success": true,
  "credit_pack_checkout_link": {
    "id": "checkout_link_123",
    "subscription_id": "subscription_123",
    "credit_pack_id": "credit_pack_123",
    "quantity": "5000",
    "url": "https://www.trygrant.com/purchase/opaque-token",
    "token_expiration": "2026-08-07T12:00:00.000Z",
    "success_url": "https://example.com/billing/success",
    "back_url": "https://example.com/billing",
    "status": "pending",
    "created_at": "2026-08-06T12:00:00.000Z"
  },
  "request_id": "req_abc123"
}
```

Send `credit_pack_checkout_link.url` to the customer tied to the subscription. Do not put the URL in public pages, logs, or analytics events because it contains the checkout token.

See [Create a credit pack checkout link](/api-reference/grant-events-api/credit-packs/create-checkout-link) for the full request and response.

### Redirect the customer

Both redirect fields are optional and must use HTTP or HTTPS:

* `success_url` sends the customer back to your app after Grant confirms the purchase.
* `back_url` sets the destination of the back action on the hosted page.

Do not treat the browser redirect as proof of payment. Read the customer's [credit balances](/api-reference/grant-events-api/customers/list-balances) from your server when your app needs the current balance.

### What happens after payment

1. Grant attaches the payment method to the customer.
2. Grant creates, finalizes, and charges a one-time invoice.
3. Grant adds a credit grant to the subscription for the purchased quantity.
4. The link changes to `completed`. A later visit shows that it has already been used.
5. If `success_url` is set, the hosted page sends the customer there.

If a payment fails, the customer can try again while the link remains valid. Create a new link after it expires.

## Good practices

* Store `credit_pack_id` with your own product or purchase option so you do not need to match on display text.
* Read `money_minor` and `unit_amount` as strings to avoid losing precision in languages with limited integer sizes.
* Show the pricing unit and expiry before sending a customer to checkout.
* Create links only from your server, after it has chosen the subscription and `credit_pack_id`.
* Use HTTPS redirect URLs in production.
* Treat the checkout URL as a secret until it expires or completes.