# POST /v1/organizations/:orgId/credits/allocate (/docs/api/reference/organizations/credits/allocate)



<Endpoint method="POST" path="/v1/organizations/{orgId}/credits/allocate" auth="Bearer" scope="org:admin" phase="1" />

To put credits into a customer's wallet, allocate from your parent wallet to the child. You call this with your parent (`org:admin`) key. The credits move out of your prepaid balance and into the child's; the response reports how much moved and the child's **post-allocation** balances, so you don't need a follow-up read.

This is real money movement - make it [idempotent](#idempotency). The transfer is recorded on both ledgers: a debit on yours, a positive `allocation` event on the child's (see [child credit events](/docs/api/reference/organizations/credits/list-events)).

<Parameters
  title="Path"
  rows="[
  { name: 'orgId', type: 'string (org_…)', required: true, description: 'The child organization to fund. Must be a direct child of your org.' },
]"
/>

<Parameters
  title="Body"
  rows="[
  { name: 'credits', type: 'integer', required: true, description: 'How many credits to move from your wallet to the child. Must be a positive integer (> 0). A value ≤ 0 is rejected with 422.' },
  { name: 'description', type: 'string', required: false, description: 'Optional free-text note for this transfer (e.g. an invoice number or budget label), ≤ 500 chars. Recorded on the allocation event on both ledgers.' },
  { name: 'metadata', type: 'object', required: false, description: 'Optional opaque key/value pairs for your own reconciliation (Stripe-style). Merged onto the allocation ledger event and readable via GET …/credits/events. Layers never reads or indexes it; reserved system keys (direction, counterpartyOrgId, etc.) always take precedence.' },
]"
/>

<Parameters
  title="Headers"
  rows="[
  { name: 'Idempotency-Key', type: 'string (UUID)', required: true, description: 'REQUIRED on this money-movement route — a request without it is rejected with 400 IDEMPOTENCY_REQUIRED. A replay (same key + same body) returns the original result WITHOUT re-debiting your wallet; the key is enforced at both the HTTP layer and the database transaction. Reusing a key with a different body returns 409 IDEMPOTENCY_CONFLICT.' },
]"
/>

## Example [#example]

```bash
curl -X POST https://api.layers.com/v1/organizations/org_d4e5f6a7-8b9c-4d0e-9f2a-3b4c5d6e7f80/credits/allocate \
  -H "Authorization: Bearer $LAYERS_PARENT_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "credits": 5000,
    "description": "Q3 budget top-up",
    "metadata": { "invoice": "inv_2026_0142" }
  }'
```

`description` and `metadata` are optional. Both are attached to the `allocation` event on each side of the transfer, so you can reconcile a movement later from [GET …/credits/events](/docs/api/reference/organizations/credits/list-events) without keeping your own mapping.

<Response status="200" description="OK - credits moved, child's post-allocation balances returned">
  ```json
  {
    "id": "txn_7f3a2b1c-9d8e-4f0a-b1c2-3d4e5f6a7b8c",
    "organizationId": "org_d4e5f6a7-8b9c-4d0e-9f2a-3b4c5d6e7f80",
    "allocated": 5000,
    "balance": 5000,
    "available": 5000,
    "description": "Q3 budget top-up",
    "metadata": { "invoice": "inv_2026_0142" },
    "created": "2026-06-03T18:14:02.187000+00:00"
  }
  ```
</Response>

### Field notes [#field-notes]

* `id` is the **transfer id** (`txn_`-prefixed) — the parent-ledger row this allocation wrote. It's your stable reconciliation handle and matches the `transferId` on the `allocation` event on both ledgers; re-fetch it via [GET …/credits/events](/docs/api/reference/organizations/credits/list-events).
* `allocated` echoes the amount that moved. On an idempotent replay it's the originally-allocated amount, not a second transfer.
* `balance` and `available` are the **child's** balances after the allocation - the same two numbers [GET …/credits](/docs/api/reference/organizations/credits/get-credits) returns. `available` is net of the child's reserved (in-flight) credits, so it can be below `balance`.
* `description` and `metadata` are echoed back from the request (`metadata` defaults to `{}` when omitted). `created` is the transfer timestamp.
* Funding a **suspended** child is allowed - you can pre-fund a paused customer ahead of resuming them. Funding an **archived** child is not (see errors).

## Idempotency [#idempotency]

Always send an `Idempotency-Key`. This call debits your wallet, so a blind retry after a timeout would fund the child twice. With the key, a replay returns the original result and moves nothing - the guard is enforced both at the HTTP layer and inside the database transaction. See [common patterns → idempotency](/docs/api/getting-started/common-patterns#idempotency).

## Errors [#errors]

| Status | Code                   | When                                                                                                   |
| ------ | ---------------------- | ------------------------------------------------------------------------------------------------------ |
| 400    | `IDEMPOTENCY_REQUIRED` | No `Idempotency-Key` header — it's mandatory on this money-movement route.                             |
| 402    | `BILLING_EXHAUSTED`    | Your parent wallet doesn't have enough balance to cover the requested `credits`. Top up, then retry.   |
| 404    | `NOT_FOUND`            | `:orgId` is not a direct child of your org (anti-enumeration).                                         |
| 409    | `CONFLICT`             | The child is **archived** - a terminal org accepts no funding (its credits were reclaimed at archive). |
| 409    | `IDEMPOTENCY_CONFLICT` | Same `Idempotency-Key` reused with a different request body.                                           |
| 422    | `VALIDATION`           | `credits` is ≤ 0 or non-integer, the body is malformed, or `:orgId` is malformed.                      |
| 503    | `KILL_SWITCH`          | Your key or org is suspended.                                                                          |

## Archiving reclaims unspent credits [#archiving-reclaims-unspent-credits]

When you archive a child (`DELETE /v1/organizations/:orgId`), its **unspent, non-reserved** credits are reclaimed to your parent wallet, and the archive response reports the amount as `reclaimedCredits`. Archive is terminal: once archived, a child can't be funded again - the allocate call above returns `409 CONFLICT`. Reserved credits backing in-flight work are not reclaimed mid-flight.

## See also [#see-also]

* [Child wallet](/docs/api/reference/organizations/credits/get-credits) - confirm the new balance.
* [Child credit events](/docs/api/reference/organizations/credits/list-events) - the `allocation` event this creates.
* [GET /v1/credits](/docs/api/reference/credits/get-credits) - your own wallet, debited by each allocation.
