> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.trygrant.com/credit-packs-guide/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. > **Note** > > 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" ``` **`Response`** ```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. **`Response`** ```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. > API documentation for Grant — billing infrastructure for usage-based pricing