# Credit grants tools

> MCP tools for Credit grants: credit_grants_create, credit_grants_list.

- `credit_grants_create`: Grant promo or adjustment credits
- `credit_grants_list`: List a wallet's credit grants

## `credit_grants_create`

**Grant credits.** Operation [`credit_grants.create`](https://ownrecord.io/docs/reference/credit-grants-create.md) · Brand level · permission `wallets:write` · risk tier `financial` · since M6

Grants credits to a wallet without a payment, with a reason:

- `promo`: promotional credits, spent before any other and never refundable;
- `adjustment`: a goodwill credit, spent with purchased credits.

In the ledger the credits are a cost (`promo_expense`); unused promo and adjustment credits that expire reverse
it. `expiresAt` (optional) is when unused credits expire. A closed wallet takes no grants (`wallet_closed`); a
frozen one does.

Financial tier: a sign-in in the last 15 minutes for people, and an approval policy may require a second person
above an amount. Dry-run it first. Emits `wallet.credited`.

Annotations: `readOnlyHint: false` · `destructiveHint: false` · `idempotentHint: true` · `openWorldHint: false`

### Arguments

| Argument          | Type                         | Required | Description                                                                                                                                                                                              |
| ----------------- | ---------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`              | ID (`wal_…`)                 | yes      | The wallet (`wal_…`).                                                                                                                                                                                    |
| `source`          | one of `promo`, `adjustment` | yes      | `promo`: promotional credits (spent first, never refundable). `adjustment`: a goodwill credit spent with purchased credits.                                                                              |
| `amount`          | object                       | yes      | The credits to grant, in the wallet's currency.                                                                                                                                                          |
| `reason`          | string                       | yes      | Why the credits are granted; shown on the grant, in the ledger and in the audit log. (1–500 characters)                                                                                                  |
| `expiresAt`       | date-time (ISO 8601)         | no       | When unused credits expire (ISO 8601, in the future); they never expire without it.                                                                                                                      |
| `entity_id`       | ID (`ent_…`)                 | no       | Optional: the brand's legal entity (ent\_…); `brand_id` alone is enough.                                                                                                                                 |
| `brand_id`        | ID (`brd_…`)                 | no       | The brand to act on (brd\_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand.                                                                 |
| `idempotency_key` | string                       | no       | A unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's `idempotency_key`. (1–255 characters) |
| `dry_run`         | boolean                      | no       | true: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default `false`)                                                                                 |

- **Brand:** pass `brand_id` with an organization or entity key; a brand key acts on its own brand.
- **Idempotency:** the result returns the `idempotency_key` used, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours).
- **Dry run:** supported. `dry_run: true` checks permissions and rules and computes the result, then rolls everything back.

### Errors

- [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed): The amount isn't positive, the reason is missing or too long, `source` isn't `promo` or `adjustment`, or `expiresAt` isn't in the future.
- [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found): This brand has no such wallet in this mode (wallets belong to one brand and one mode).
- [`wallet_currency_mismatch`](https://ownrecord.io/docs/reference/errors.md#wallet_currency_mismatch): The amount isn't in the wallet's currency.
- [`wallet_closed`](https://ownrecord.io/docs/reference/errors.md#wallet_closed): The wallet is closed: reopen it before granting credits.
- [`idempotency_key_reused`](https://ownrecord.io/docs/reference/errors.md#idempotency_key_reused): The idempotency key was used before for another request.
- [`version_conflict`](https://ownrecord.io/docs/reference/errors.md#version_conflict): The wallet changed at the same moment (another reservation, capture or grant); retry.
- [`approval_required`](https://ownrecord.io/docs/reference/errors.md#approval_required): The organization's approval policy needs a second person for this; nothing changed yet.
- [`approval_rejected`](https://ownrecord.io/docs/reference/errors.md#approval_rejected): The same request was sent again after it was rejected.
- [`approval_expired`](https://ownrecord.io/docs/reference/errors.md#approval_expired): The same request was sent again after its approval request expired.
- [`stale_approval`](https://ownrecord.io/docs/reference/errors.md#stale_approval): The approved request could no longer run as requested.
- [`fresh_auth_required`](https://ownrecord.io/docs/reference/errors.md#fresh_auth_required): Your last sign-in is older than 15 minutes.
- [`scope_required`](https://ownrecord.io/docs/reference/errors.md#scope_required): The request names no brand (an org or entity key without `Ownrecord-Brand`).
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): You can't change this brand's wallets (`wallets:write`: owners, admins and support).
- [`livemode_not_allowed`](https://ownrecord.io/docs/reference/errors.md#livemode_not_allowed): You have no live-mode access, so you can't use live wallets.

### Example

**€5 of welcome credits for a month**

Arguments:

```json
{
  "id": "wal_01m4ty7w2a5qx7mhd9k8w6s0b1",
  "source": "promo",
  "amount": {
    "amount": "5000000",
    "currency": "EUR"
  },
  "reason": "Welcome credits",
  "expiresAt": "2026-11-01T00:00:00Z",
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
```

Result `output`:

```json
{
  "id": "grant_01m4ty7w2a5qx7mhd9k8w6s0b3",
  "object": "credit_grant",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "livemode": false,
  "walletId": "wal_01m4ty7w2a5qx7mhd9k8w6s0b1",
  "source": "promo",
  "amount": {
    "amount": "5000000",
    "currency": "EUR"
  },
  "remaining": {
    "amount": "5000000",
    "currency": "EUR"
  },
  "priority": 1,
  "expiresAt": "2026-11-01T00:00:00.000Z",
  "expired": false,
  "reason": "Welcome credits",
  "paymentId": null,
  "invoiceId": null,
  "createdAt": "2026-10-16T10:15:00.000Z"
}
```

## `credit_grants_list`

**List a wallet's credit grants.** Operation [`credit_grants.list`](https://ownrecord.io/docs/reference/credit-grants-list.md) · Brand level · permission `wallets:read` · risk tier `read` · since M6

Lists the credits behind a wallet's balance, newest first: purchases (top-ups and credit packs), subscription
credits, promo and adjustment grants and refund reversals. `remaining` is what is left of each grant (credits
held by open reservations count as left); `expiresAt` is when unused credits expire.

Credits are spent promo first, then subscription credits, then purchased ones, soonest expiry first within each
(spec §17.1, `priority`).

Annotations: `readOnlyHint: true` · `destructiveHint: false` · `idempotentHint: true` · `openWorldHint: false`

### Arguments

| Argument         | Type           | Required | Description                                                                                                                              |
| ---------------- | -------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `id`             | ID (`wal_…`)   | yes      | The wallet (`wal_…`).                                                                                                                    |
| `limit`          | integer        | no       | (1–100)                                                                                                                                  |
| `starting_after` | ID (`grant_…`) | no       | –                                                                                                                                        |
| `entity_id`      | ID (`ent_…`)   | no       | Optional: the brand's legal entity (ent\_…); `brand_id` alone is enough.                                                                 |
| `brand_id`       | ID (`brd_…`)   | no       | The brand to act on (brd\_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand. |

- **Brand:** pass `brand_id` with an organization or entity key; a brand key acts on its own brand.
- **Read-only:** changes nothing; `idempotency_key` is ignored.

### Errors

- [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed): `id` isn't a wallet ID, or a pagination value is invalid.
- [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found): This brand has no such wallet in this mode (wallets belong to one brand and one mode).
- [`scope_required`](https://ownrecord.io/docs/reference/errors.md#scope_required): The request names no brand (an org or entity key without `Ownrecord-Brand`).
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): You can't read this brand's wallets (`wallets:read`).
- [`livemode_not_allowed`](https://ownrecord.io/docs/reference/errors.md#livemode_not_allowed): You have no live-mode access, so you can't use live wallets.

### Example

**A promo grant and a purchase**

Arguments:

```json
{
  "id": "wal_01m4ty7w2a5qx7mhd9k8w6s0b1",
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz"
}
```

Result `output`:

```json
{
  "object": "list",
  "data": [
    {
      "id": "grant_01m4ty7w2a5qx7mhd9k8w6s0b3",
      "object": "credit_grant",
      "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
      "livemode": false,
      "walletId": "wal_01m4ty7w2a5qx7mhd9k8w6s0b1",
      "source": "promo",
      "amount": {
        "amount": "5000000",
        "currency": "EUR"
      },
      "remaining": {
        "amount": "5000000",
        "currency": "EUR"
      },
      "priority": 1,
      "expiresAt": "2026-11-01T00:00:00.000Z",
      "expired": false,
      "reason": "Welcome credits",
      "paymentId": null,
      "invoiceId": null,
      "createdAt": "2026-10-16T10:15:00.000Z"
    },
    {
      "id": "grant_01m4ty7w2a5qx7mhd9k8w6s0b2",
      "object": "credit_grant",
      "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
      "livemode": false,
      "walletId": "wal_01m4ty7w2a5qx7mhd9k8w6s0b1",
      "source": "purchase",
      "amount": {
        "amount": "80000000",
        "currency": "EUR"
      },
      "remaining": {
        "amount": "80000000",
        "currency": "EUR"
      },
      "priority": 3,
      "expiresAt": null,
      "expired": false,
      "reason": null,
      "paymentId": "pay_01m4ty7w2a5qx7mhd9k8w6s0b5",
      "invoiceId": null,
      "createdAt": "2026-10-14T09:00:00.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}
```
