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

# Grants

> Add credits to metered entitlements via direct creation or paid purchase

<Info>
  Grants require Standard Billing (`billingVersion: 1`) and an active metered entitlement. See
  [Metered Entitlements](/platform/billing/metered-entitlements) for how entitlements are provisioned
  automatically via subscription, and [Billing Versions](/platform/billing/billing-versions) for
  details on the two billing models.
</Info>

Grants let you add credits to a customer's metered entitlement outside the normal subscription cycle. Use them for mid-cycle top-ups, promotional credits, support adjustments, or self-serve credit purchases.

There are two ways to create a grant:

|                  | Direct Create                                   | Purchase                                      |
| ---------------- | ----------------------------------------------- | --------------------------------------------- |
| **Use case**     | Promos, comps, support credits, backend scripts | Customer-initiated self-serve top-ups         |
| **Payment**      | None — credits are applied immediately          | Customer pays via hosted checkout             |
| **Grant timing** | Immediate (or scheduled via `effectiveAt`)      | Created automatically after payment completes |
| **Endpoint**     | `POST /v1/entitlements/{id}/grants`             | `POST /v1/entitlements/{id}/grants/purchase`  |

## Prerequisites

Before creating or purchasing a grant, you need:

* A customer with an **active v1 subscription**
* A **metered entitlement** on that subscription (the `entitlementId`)

You can retrieve the entitlement ID from `GET /v1/entitlements` or from the subscription's entitlement list.

## Creating a Grant (Direct)

Use direct creation when you want to credit a customer's balance without requiring payment — promotional credits, support adjustments, or backend automation.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.paygentic.io/v1/entitlements/ent_abc123/grants" \
    -H "Authorization: Bearer sk_test_YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "amount": 500,
      "idempotencyKey": "promo-500-march-2026"
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    'https://api.paygentic.io/v1/entitlements/ent_abc123/grants',
    {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer sk_test_YOUR_API_KEY',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        amount: 500,
        idempotencyKey: 'promo-500-march-2026',
      }),
    }
  );

  const grant = await response.json();
  ```

  ```typescript TypeScript SDK theme={null}
  import { Paygentic } from "@paygentic/sdk";

  const client = new Paygentic({ bearerAuth: "sk_test_YOUR_API_KEY" });

  const grant = await client.entitlements.grants.create({
    entitlementId: "ent_abc123",
    createGrantRequest: {
      amount: 500,
      idempotencyKey: "promo-500-march-2026",
    },
  });
  ```

  ```python Python SDK theme={null}
  from paygentic_sdk import Paygentic

  client = Paygentic(bearer_auth="sk_test_YOUR_API_KEY")

  grant = client.entitlements.grants.create(
      entitlement_id="ent_abc123",
      amount=500,
      idempotency_key="promo-500-march-2026",
  )
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "object": "grant",
  "id": "grt_x7k9m2",
  "entitlementId": "ent_abc123",
  "amount": 500,
  "effectiveAt": "2026-03-14T10:30:00Z",
  "expiresAt": null,
  "voidedAt": null,
  "createdAt": "2026-03-14T10:30:00Z"
}
```

### Request fields

| Field            | Type     | Required | Description                                                                           |
| ---------------- | -------- | -------- | ------------------------------------------------------------------------------------- |
| `amount`         | number   | Yes      | Credits to grant. Must be greater than 0.                                             |
| `idempotencyKey` | string   | Yes      | Unique key per entitlement to prevent duplicate grants. Max 255 characters.           |
| `effectiveAt`    | datetime | No       | When the grant becomes effective. Defaults to the entitlement's current period start. |
| `expiresAt`      | datetime | No       | When the grant expires. If omitted, the grant does not expire.                        |

<Note>
  The `idempotencyKey` is scoped to the entitlement. Retrying a request with the same key returns the existing grant without creating a duplicate. If you retry with the same key but different parameters (for example, a different `amount`), the API returns a `409 Conflict`.
</Note>

## Purchasing a Grant

Use grant purchases when a customer should pay for additional credits — self-serve top-up flows, credit packs, or on-demand capacity.

The purchase endpoint creates an ad-hoc invoice with a payment session. Redirect the customer to the returned payment URL — once they complete payment, the grant is created automatically.

To react to payment completion programmatically, subscribe to the [`invoice.paid.v0` webhook](/platform/developers/webhooks#invoice-events). The payload includes the original `invoiceId` along with the created `grantId`, so you can correlate the purchase response with downstream fulfilment without an extra fetch.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.paygentic.io/v1/entitlements/ent_abc123/grants/purchase" \
    -H "Authorization: Bearer sk_test_YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "amount": 1000,
      "price": "5.00",
      "idempotencyKey": "topup-1000-march-2026",
      "successUrl": "https://example.com/credits/success",
      "cancelUrl": "https://example.com/credits"
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    'https://api.paygentic.io/v1/entitlements/ent_abc123/grants/purchase',
    {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer sk_test_YOUR_API_KEY',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        amount: 1000,
        price: '5.00',
        idempotencyKey: 'topup-1000-march-2026',
        successUrl: 'https://example.com/credits/success',
        cancelUrl: 'https://example.com/credits',
      }),
    }
  );

  const purchase = await response.json();
  // Redirect customer to purchase.paymentSessions[0].url
  ```

  ```typescript TypeScript SDK theme={null}
  import { Paygentic } from "@paygentic/sdk";

  const client = new Paygentic({ bearerAuth: "sk_test_YOUR_API_KEY" });

  const purchase = await client.entitlements.grants.purchase({
    entitlementId: "ent_abc123",
    purchaseGrantRequest: {
      amount: 1000,
      price: "5.00",
      idempotencyKey: "topup-1000-march-2026",
      successUrl: "https://example.com/credits/success",
      cancelUrl: "https://example.com/credits",
    },
  });
  // Redirect customer to purchase.paymentSessions[0].url
  ```

  ```python Python SDK theme={null}
  from paygentic_sdk import Paygentic

  client = Paygentic(bearer_auth="sk_test_YOUR_API_KEY")

  purchase = client.entitlements.grants.purchase(
      entitlement_id="ent_abc123",
      amount=1000,
      price="5.00",
      idempotency_key="topup-1000-march-2026",
      success_url="https://example.com/credits/success",
      cancel_url="https://example.com/credits",
  )
  # Redirect customer to purchase.payment_sessions[0].url
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "object": "grant_purchase",
  "invoiceId": "inv_a1b2c3d4",
  "entitlementId": "ent_abc123",
  "grantAmount": 1000,
  "price": "5.00",
  "currency": "usd",
  "paymentSessions": [
    {
      "url": "https://platform.paygentic.io/portal/pay/ps_abc123",
      "expiresAt": "2026-03-15T10:30:00Z",
      "amount": 500
    }
  ]
}
```

### Request fields

| Field              | Type     | Required | Description                                                                                                                                                                                           |
| ------------------ | -------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `amount`           | number   | Yes      | Credits to grant upon payment completion. Must be greater than 0.                                                                                                                                     |
| `price`            | string   | Yes      | Price in decimal format (e.g., `"5.00"`). Minimum `"0.50"`.                                                                                                                                           |
| `idempotencyKey`   | string   | Yes      | Unique key for deduplication. Retrying with the same key returns the existing invoice. If you retry with the same key but different parameters, the API returns a `409 Conflict`. Max 255 characters. |
| `effectiveAt`      | datetime | No       | When the grant becomes effective. Defaults to the entitlement's current period start.                                                                                                                 |
| `expiresAt`        | datetime | No       | When the grant expires. If omitted, the grant does not expire.                                                                                                                                        |
| `successUrl`       | string   | No       | URL to redirect the customer to after successful payment.                                                                                                                                             |
| `cancelUrl`        | string   | No       | URL to redirect the customer to if they cancel payment.                                                                                                                                               |
| `paymentExpiresAt` | datetime | No       | When the payment session expires. Uses the default expiry if omitted.                                                                                                                                 |

<Note>
  The currency is always the merchant's default currency. The `amount` in the payment session is in the currency's minor unit (e.g., cents for USD), so a price of `"5.00"` appears as `500`.
</Note>

### What happens if payment expires

If the customer does not complete payment before the session expires, Paygentic automatically cancels the invoice. No grant is created and no charge is made.

## Managing Grants

### List grants

Retrieve all grants for an entitlement. Active grants are returned by default.

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://api.paygentic.io/v1/entitlements/ent_abc123/grants" \
    -H "Authorization: Bearer sk_test_YOUR_API_KEY"
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    'https://api.paygentic.io/v1/entitlements/ent_abc123/grants',
    { headers: { 'Authorization': 'Bearer sk_test_YOUR_API_KEY' } }
  );
  const { data } = await response.json();
  ```

  ```typescript TypeScript SDK theme={null}
  import { Paygentic } from "@paygentic/sdk";

  const client = new Paygentic({ bearerAuth: "sk_test_YOUR_API_KEY" });

  const { data } = await client.entitlements.grants.list({
    entitlementId: "ent_abc123",
  });
  ```

  ```python Python SDK theme={null}
  from paygentic_sdk import Paygentic

  client = Paygentic(bearer_auth="sk_test_YOUR_API_KEY")

  result = client.entitlements.grants.list(entitlement_id="ent_abc123")
  ```
</CodeGroup>

Pass `includeVoided=true` to include voided grants in the response:

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://api.paygentic.io/v1/entitlements/ent_abc123/grants?includeVoided=true" \
    -H "Authorization: Bearer sk_test_YOUR_API_KEY"
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    'https://api.paygentic.io/v1/entitlements/ent_abc123/grants?includeVoided=true',
    { headers: { 'Authorization': 'Bearer sk_test_YOUR_API_KEY' } }
  );
  const { data } = await response.json();
  ```

  ```typescript TypeScript SDK theme={null}
  import { Paygentic } from "@paygentic/sdk";

  const client = new Paygentic({ bearerAuth: "sk_test_YOUR_API_KEY" });

  const { data } = await client.entitlements.grants.list({
    entitlementId: "ent_abc123",
    includeVoided: true,
  });
  ```

  ```python Python SDK theme={null}
  from paygentic_sdk import Paygentic

  client = Paygentic(bearer_auth="sk_test_YOUR_API_KEY")

  result = client.entitlements.grants.list(
      entitlement_id="ent_abc123",
      include_voided=True,
  )
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "object": "list",
  "data": [
    {
      "object": "grant",
      "id": "grt_x7k9m2",
      "entitlementId": "ent_abc123",
      "amount": 500,
      "effectiveAt": "2026-03-14T10:30:00Z",
      "expiresAt": null,
      "voidedAt": null,
      "createdAt": "2026-03-14T10:30:00Z"
    }
  ],
  "pagination": {
    "total": 1,
    "limit": 20,
    "offset": 0
  }
}
```

### Get a grant

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://api.paygentic.io/v1/entitlements/ent_abc123/grants/grt_x7k9m2" \
    -H "Authorization: Bearer sk_test_YOUR_API_KEY"
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    'https://api.paygentic.io/v1/entitlements/ent_abc123/grants/grt_x7k9m2',
    { headers: { 'Authorization': 'Bearer sk_test_YOUR_API_KEY' } }
  );
  const grant = await response.json();
  ```

  ```typescript TypeScript SDK theme={null}
  import { Paygentic } from "@paygentic/sdk";

  const client = new Paygentic({ bearerAuth: "sk_test_YOUR_API_KEY" });

  const grant = await client.entitlements.grants.get({
    entitlementId: "ent_abc123",
    grantId: "grt_x7k9m2",
  });
  ```

  ```python Python SDK theme={null}
  from paygentic_sdk import Paygentic

  client = Paygentic(bearer_auth="sk_test_YOUR_API_KEY")

  grant = client.entitlements.grants.get(
      entitlement_id="ent_abc123",
      grant_id="grt_x7k9m2",
  )
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "object": "grant",
  "id": "grt_x7k9m2",
  "entitlementId": "ent_abc123",
  "amount": 500,
  "effectiveAt": "2026-03-14T10:30:00Z",
  "expiresAt": null,
  "voidedAt": null,
  "createdAt": "2026-03-14T10:30:00Z"
}
```

### Void a grant

Voiding removes the grant's credits from the customer's balance. This operation is idempotent — voiding an already-voided grant returns the grant without error.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X DELETE "https://api.paygentic.io/v1/entitlements/ent_abc123/grants/grt_x7k9m2" \
    -H "Authorization: Bearer sk_test_YOUR_API_KEY"
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    'https://api.paygentic.io/v1/entitlements/ent_abc123/grants/grt_x7k9m2',
    {
      method: 'DELETE',
      headers: { 'Authorization': 'Bearer sk_test_YOUR_API_KEY' },
    }
  );
  const grant = await response.json();
  ```

  ```typescript TypeScript SDK theme={null}
  import { Paygentic } from "@paygentic/sdk";

  const client = new Paygentic({ bearerAuth: "sk_test_YOUR_API_KEY" });

  const grant = await client.entitlements.grants.void({
    entitlementId: "ent_abc123",
    grantId: "grt_x7k9m2",
  });
  ```

  ```python Python SDK theme={null}
  from paygentic_sdk import Paygentic

  client = Paygentic(bearer_auth="sk_test_YOUR_API_KEY")

  grant = client.entitlements.grants.void(
      entitlement_id="ent_abc123",
      grant_id="grt_x7k9m2",
  )
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "object": "grant",
  "id": "grt_x7k9m2",
  "entitlementId": "ent_abc123",
  "amount": 500,
  "effectiveAt": "2026-03-14T10:30:00Z",
  "expiresAt": null,
  "voidedAt": "2026-03-15T09:00:00Z",
  "createdAt": "2026-03-14T10:30:00Z"
}
```

## Grant Object

| Field           | Type             | Description                                                  |
| --------------- | ---------------- | ------------------------------------------------------------ |
| `object`        | string           | Always `"grant"`.                                            |
| `id`            | string           | Unique identifier (`grt_` prefix).                           |
| `entitlementId` | string           | The entitlement this grant belongs to.                       |
| `amount`        | number           | The number of credits granted.                               |
| `effectiveAt`   | datetime         | When the grant becomes effective.                            |
| `expiresAt`     | datetime \| null | When the grant expires. `null` means no expiration.          |
| `voidedAt`      | datetime \| null | When the grant was voided. `null` means the grant is active. |
| `createdAt`     | datetime         | When the grant was created.                                  |

## Next Steps

* [Metered Entitlements](/platform/billing/metered-entitlements) — Grant lifecycle, reset behavior, rollover rules, and balance checking
* [Features](/platform/pricing/features) — Feature types and how entitlements are provisioned automatically
* [Usage Events](/platform/billing/usage-events) — Send consumption data that depletes grant balances
