Layers
Partner APIAPI referenceCredits

GET /v1/credits/events

Per-event credit ledger — every charge, refund, grant, and purchase on the calling org. Filter by project for attribution.

View as Markdown
GET/v1/credits/events
Phase 1stable
Auth
Bearer

Returns one row per wallet movement. Use this to attribute spend by project, reconcile your own counter against ours, or build a credit-usage dashboard.

GET /v1/credits gives you the wallet snapshot; /v1/credits/events gives you the audit trail. They complement each other — the snapshot is the answer to "how much do I have right now?", events are the answer to "what happened?"

Query parameters

  • projectId
    stringoptional
    Filter to events attributed to one project. `null`-projectId events (grants, purchases, admin adjustments) are excluded when this filter is set.
  • eventType
    stringoptional
    Filter to one event type. See "Event types" below.
    One of: usage, refund, grant, purchase, adjustment, allocation
  • since
    string (ISO 8601 Z)optional
    Only events `>= since`. UTC required (Z suffix).
  • until
    string (ISO 8601 Z)optional
    Only events `<= until`. UTC required (Z suffix).
  • cursor
    stringoptional
    Opaque cursor from the previous page.
  • limit
    integeroptionaldefault: 25
    Page size, 1-100.

Example request

curl "https://api.layers.com/v1/credits/events?projectId=prj_13fd8406-387a-4472-b6a2-531860557a6e&eventType=usage" \
  -H "Authorization: Bearer $LAYERS_API_KEY"
const url = new URL("https://api.layers.com/v1/credits/events");
url.searchParams.set("projectId", "prj_13fd8406-387a-4472-b6a2-531860557a6e");
url.searchParams.set("eventType", "usage");
const res = await fetch(url, {
  headers: { Authorization: `Bearer ${process.env.LAYERS_API_KEY}` },
});
const { items, nextCursor } = await res.json();
import os, requests
res = requests.get(
    "https://api.layers.com/v1/credits/events",
    params={"projectId": "prj_…", "eventType": "usage"},
    headers={"Authorization": f"Bearer {os.environ['LAYERS_API_KEY']}"},
)
data = res.json()

Response

200OK
{
  "items": [
    {
      "eventId": "a962df6d-2ea8-4dff-8a68-d49b1dc74d33",
      "projectId": "prj_13fd8406-387a-4472-b6a2-531860557a6e",
      "credits": -50,
      "eventType": "usage",
      "format": "slideshow-builder",
      "containerId": "cnt_a861adb5-3a48-48a4-a18d-c70129ebefa7",
      "workflowId": "partner-content-a861adb5-3a48-48a4-a18d-c70129ebefa7-v0",
      "balanceAfterPrepaid": 4200,
      "usageAfterPeriod": 3000,
      "createdAt": "2026-05-12T21:17:15.903Z"
    },
    {
      "eventId": "1133c79a-e49e-4e52-81e7-ac13ef77d72a",
      "projectId": null,
      "credits": 1000,
      "eventType": "grant",
      "format": null,
      "containerId": null,
      "workflowId": null,
      "balanceAfterPrepaid": null,
      "usageAfterPeriod": null,
      "createdAt": "2026-05-12T15:00:00.000Z"
    }
  ],
  "nextCursor": null
}

Event types

TypeSign of creditsWhen
usagealways negativeContent-generation charge (slideshow-builder, slideshow-remix, video-remix, ugc-remix). Charged synchronously when the workflow starts rendering.
refundalways positiveAutomatic refund when a paid generation fails post-charge, OR an admin-initiated reversal.
grantalways positiveFree credits granted by Layers — onboarding, promo, velocity bonus, manual admin grant.
purchasealways positivePrepaid credit pack purchased via Stripe.
adjustmenteither signAdmin manual adjustment. Direction is on the sign of credits.
allocationeither signA sub-org credit transfer between you and one of your children. On your own ledger it's negative when you fund a child (allocate) and positive when an archived child's unspent credits are reclaimed to you. metadata.direction is allocate or reclaim; metadata.counterpartyOrgId (org_-prefixed) names the child, and metadata.transferId (txn_-prefixed) matches the id the allocate response returns.

Field notes

  • credits is signed — debits negative, credits positive. Sum them for a wallet-level reconciliation.
  • projectId is null for org-level events (grants, purchases, admin adjustments, allocations). When filtering by projectId, those rows are excluded by design.
  • format and containerId populate when the event is tied to a partner-API content-generation workflow. In-app generations from the Layers dashboard also charge but don't surface a format / containerId here.
  • balanceAfterPrepaid / usageAfterPeriod are reconciliation breadcrumbs — what the wallet looked like immediately after this event. null when the event didn't touch that side of the wallet.
  • Ordered newest first, paginated via nextCursor. The cursor is opaque — pass it back verbatim on the next call.

Common patterns

Project spend this billing period:

curl "https://api.layers.com/v1/credits/events\
?projectId=prj_…&eventType=usage&since=$(date -u +%Y-%m-01T00:00:00Z)" \
  -H "Authorization: Bearer $LAYERS_API_KEY" \
| jq '[.items[] | .credits] | add'

Per-format breakdown for a project:

curl "https://api.layers.com/v1/credits/events?projectId=prj_…&eventType=usage" \
  -H "Authorization: Bearer $LAYERS_API_KEY" \
| jq -r '.items | group_by(.format) | map({format: .[0].format, total: ([.[].credits] | add)})'

Errors

StatusCodeWhen
422VALIDATIONBad projectId shape, malformed timestamp (offset form like +00:00 is rejected — Z-suffix UTC only), invalid eventType.
401UNAUTHENTICATEDMissing or invalid key.
503KILL_SWITCHKey or org disabled.

See also

  • GET /v1/credits — wallet snapshot (the answer to "how much do I have now?")

On this page