Layers
Partner APIAPI referenceOrganizationsChild credits

POST /v1/organizations/:orgId/credits/allocate

Fund a child organization from your parent wallet - idempotent money movement.

View as Markdown
POST/v1/organizations/{orgId}/credits/allocate
Phase 1stableidempotent
Auth
Bearer
Scope
org:admin

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. The transfer is recorded on both ledgers: a debit on yours, a positive allocation event on the child's (see child credit events).

Path
  • orgId
    string (org_…)required
    The child organization to fund. Must be a direct child of your org.
Body
  • credits
    integerrequired
    How many credits to move from your wallet to the child. Must be a positive integer (> 0). A value ≤ 0 is rejected with 422.
  • description
    stringoptional
    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.
  • metadata
    objectoptional
    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.
Headers
  • Idempotency-Key
    string (UUID)required
    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

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 without keeping your own mapping.

200OK - credits moved, child's post-allocation balances returned
{
  "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"
}

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.
  • 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 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

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.

Errors

StatusCodeWhen
400IDEMPOTENCY_REQUIREDNo Idempotency-Key header — it's mandatory on this money-movement route.
402BILLING_EXHAUSTEDYour parent wallet doesn't have enough balance to cover the requested credits. Top up, then retry.
404NOT_FOUND:orgId is not a direct child of your org (anti-enumeration).
409CONFLICTThe child is archived - a terminal org accepts no funding (its credits were reclaimed at archive).
409IDEMPOTENCY_CONFLICTSame Idempotency-Key reused with a different request body.
422VALIDATIONcredits is ≤ 0 or non-integer, the body is malformed, or :orgId is malformed.
503KILL_SWITCHYour key or org is suspended.

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

On this page