Credits and usage

How Direct API calls are charged, settled and refunded, how to quote a job first, and how to read your key's spend and ledger.

The Direct API charges Morphic credits from your organization's balance, the same pool Studio uses, and every response says how many.

  • Direct API calls are charged at your organization's API rates, which can differ from what the same work costs in Studio. Every number the API gives you already reflects them: plan_media quotes, estimated_credits, the billing block, generation reads, webhooks and /usage.
  • Rates are set per organization and are not published. Your account contact can share your API rate sheet.
  • A rate change applies to generations started after it; a running generation is settled at the rate it started with.
  • In Studio, under Settings > Credits, API spend appears as its own row, API, beside your members, and Split API by key breaks it down per key. It draws from the organization's credits but never from a member's allocation, and each key's credit limits cap it.

How a generation is charged

  1. At start, the generation is charged its quoted price. The start response reports it in billing.credits_charged and result.estimated_credits.
  2. Some outputs are priced by what is actually produced: speech and music by produced length, timeline renders by compute time. They carry credits_settle_on_output_duration: true; the start charge is a floor, and the final amount is settled when the generation finishes.
  3. A generation that ends failed or cancelled is refunded in full, and billing.credits_refunded reports the credits given back. A succeeded generation can also carry a partial refund, for example when a settled output came out shorter than the start charge covered.
  4. Once a generation is final, billing.credits_charged is the net total on the ledger (start charge, plus or minus settlement, minus credits_refunded) and credits_are_final is true. A failed or cancelled generation ends with credits_charged: 0 and credits_refunded equal to what it was charged.
FieldMeaning
estimated_creditsthe price quoted and charged at start
credits_chargedthe net credits recorded for this generation so far, after settlement and refunds
credits_refundedevery credit given back for this generation: the whole charge on failed or cancelled, any partial refund on a succeeded one; 0 when none, never negative
credits_are_finalfalse while the generation runs or a settlement or refund is still due; true once nothing more will change it
credits_settle_on_output_durationtrue when the start charge is a floor settled from the produced output

While a generation runs, credits_charged equals the start charge. Read it again once the generation is final for the settled amount; a webhook is sent only once it is.

Billing on each response

The billing block on a call's response reports what the call charged when it returned; Calling a tool lists it per kind of call. Refunds happen later, so they appear on the generation (GET /generations/{id} and /usage), never on the original response.

  • A paid tool that answers in the call and whose work fails, such as analyze_video, answers with credits_charged: 0 and credits_refunded set to the refund.
  • The Morphic-Credits-Charged: <integer> header carries the same number as billing.credits_charged, except on an idempotent replay, which charges nothing more and sends 0 while its body repeats the original charge.

Quote before you spend

POST /v1/direct/tools/plan_media validates a plan of up to 20 steps and prices the steps it can, without starting or charging anything.

curl -s https://mcp.morphic.com/v1/direct/tools/plan_media \
  -H "Authorization: Bearer $MORPHIC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "input": {
          "steps": [
            { "id": "still", "tool_name": "generate_image", "arguments_json": "{\"prompt\":\"A red vintage bicycle\",\"aspect_ratio\":\"16:9\"}" },
            { "id": "clip", "tool_name": "generate_video", "arguments_json": "{\"prompt\":\"The bicycle rolls away\",\"duration_seconds\":8}", "depends_on": ["still"] }
          ]
        }
      }'
  • Leave out asset fields whose outputs do not exist yet, and name the step they come from in depends_on.
  • Each step gets its validation, quote_status and estimated_credits.
  • The result also gives the execution_order, known_estimated_credits, unquoted_step_ids and complete_estimate. When complete_estimate is false, the sum is a lower bound, not a budget.

Key and balance

GET /v1/direct/me returns the calling key, its limits and spend, and the organization's balance. Any key can call it.

curl -s https://mcp.morphic.com/v1/direct/me \
  -H "Authorization: Bearer $MORPHIC_API_KEY"
{
  "api_key": {
    "id": "01928e00-…",
    "name": "Order pipeline (prod)",
    "scopes": ["assets:read", "assets:write", "generations:write", "projects:read"],
    "expires_at": null,
    "credit_limits": {
      "total":   { "limit": 500000, "used": 182340, "remaining": 317660 },
      "monthly": { "limit": 100000, "used": 41200,  "remaining": 58800, "resets_at": "2026-11-01T00:00:00.000Z" },
      "daily":   { "limit": null,   "used": 2310,   "remaining": null,  "resets_at": "2026-10-26T00:00:00.000Z" }
    }
  },
  "organization": {
    "id": "01928d00-…",
    "plan": "enterprise",
    "remaining_credits": 1240000,
    "unlimited": false
  }
}

Usage ledger

GET /v1/direct/usage (scope assets:read) returns every ledger entry the key caused, for reconciliation with your own records.

QueryMeaning
from, toISO 8601 bounds on created_at; default the last 30 days, at most 92 days
generation_identries of one generation only
limit1 to 200, default 50
cursorthe previous page's next_cursor
curl -s "https://mcp.morphic.com/v1/direct/usage?from=2026-10-01T00:00:00Z&limit=200" \
  -H "Authorization: Bearer $MORPHIC_API_KEY"
{
  "usage": [
    { "id": "0192a7b3-…", "created_at": "2026-10-25T09:14:03.500Z", "kind": "charge",     "credits": 120, "generation_id": "0192a7b3-a1c4-…", "tool": "generate_video", "model_id": "mdl_7rk2pq9vxa4m", "metadata": { "order_id": "4411" } },
    { "id": "0192a7b4-…", "created_at": "2026-10-25T09:15:41.950Z", "kind": "settlement", "credits": -24, "generation_id": "0192a7b3-a1c4-…", "tool": "generate_video", "model_id": "mdl_7rk2pq9vxa4m", "metadata": { "order_id": "4411" } }
  ],
  "totals": { "charged": 120, "settled": -24, "refunded": 0, "net": 96 },
  "next_cursor": null
}
  • kind is one of charge, settlement or refund; a negative credits gives credits back.
  • totals covers the whole filtered range, not just the page.
  • A tool that answers in the call (analyze_video, analyze_audio, filmlab_edit) starts no generation, so its entries carry generation_id: null and are told apart by tool.

If you have any trouble or have any questions, feel free to reach out. We're happy to help. Write to us at support@morphic.com.

On this page