B2BB2B LLM

Claude Message Batches

Use Anthropic-compatible Message Batches while Model Gate executes every item through its durable internal queue.

Claude Message Batches

Existing Batch read/control operations remain available at zero balance for an otherwise valid active credential, but POST /v1/messages/batches requires fresh positive-balance/spend admission before any job/item rows are stored. A zero-balance key therefore cannot create a new Claude batch or consume MariaDB retention storage. Actual items re-check admission when workers claim them and wait in the durable queue if funds are later exhausted. Input is decoded incrementally item by item rather than loaded as a complete 256 MB in-memory JSON document, and per-user active-job/queued-item quotas bound storage abuse independently of billing.

Model Gate implements an Anthropic-compatible Message Batches API on https://api.model-gate.com. It is a compatibility layer: Model Gate stores the batch durably and executes each item through the normal Model Gate /v1/messages path. It does not submit a provider-native Anthropic batch upstream.

Use a normal Model API key (mg_live_...). Every item is accounted as an individual request with request_mode=batch, batch_protocol=claude, the batch ID, and its custom_id.

Streaming is not supported inside a batch. Model aliases are resolved before the item is queued.

Create a message batch

Request

curl https://api.model-gate.com/v1/messages/batches \
  -H "x-api-key: mg_live_..." \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{
    "requests": [
      {
        "custom_id": "summary-1",
        "params": {
          "model": "ch-47",
          "max_tokens": 256,
          "messages": [{"role":"user","content":"Summarize this text."}]
        }
      }
    ]
  }'

Response — 200

{
  "id": "msgbatch_01K...",
  "type": "message_batch",
  "processing_status": "in_progress",
  "request_counts": {
    "processing": 1,
    "succeeded": 0,
    "errored": 0,
    "canceled": 0,
    "expired": 0
  },
  "ended_at": null,
  "created_at": "2026-08-13T08:30:00Z",
  "expires_at": "2026-08-14T08:30:00Z",
  "cancel_initiated_at": null,
  "results_url": null
}

Retrieve a batch

Request

curl https://api.model-gate.com/v1/messages/batches/msgbatch_01K... \
  -H "x-api-key: mg_live_..."

Response — ended

{
  "id": "msgbatch_01K...",
  "type": "message_batch",
  "processing_status": "ended",
  "request_counts": {
    "processing": 0,
    "succeeded": 1,
    "errored": 0,
    "canceled": 0,
    "expired": 0
  },
  "ended_at": "2026-08-13T08:30:04Z",
  "results_url": "https://api.model-gate.com/v1/messages/batches/msgbatch_01K.../results"
}

Read results

Results are returned as JSON Lines. Do not assume that application logic depends on the original input order; match results by custom_id.

Request

curl https://api.model-gate.com/v1/messages/batches/msgbatch_01K.../results \
  -H "x-api-key: mg_live_..."

Response — 200

{"custom_id":"summary-1","result":{"type":"succeeded","message":{"id":"msg_...","type":"message","role":"assistant","content":[{"type":"text","text":"..."}]}}}

List batches

limit defaults to 20 and must be from 1 to 100. Use after_id or before_id for cursor pagination; do not send both in one request.

Request

curl "https://api.model-gate.com/v1/messages/batches?limit=20&after_id=msgbatch_01K..." \
  -H "x-api-key: mg_live_..."

Response — 200

{
  "data": [],
  "has_more": false,
  "first_id": null,
  "last_id": null
}

Cancel a batch

Cancel stops queued items from being claimed. An item already processing may finish.

Request

curl -X POST https://api.model-gate.com/v1/messages/batches/msgbatch_01K.../cancel \
  -H "x-api-key: mg_live_..."

Response — 200

{
  "id": "msgbatch_01K...",
  "type": "message_batch",
  "processing_status": "canceling",
  "request_counts": {
    "processing": 1,
    "succeeded": 0,
    "errored": 0,
    "canceled": 0,
    "expired": 0
  }
}

Delete an ended batch

Delete is accepted only after the batch has reached a terminal state.

Request

curl -X DELETE https://api.model-gate.com/v1/messages/batches/msgbatch_01K... \
  -H "x-api-key: mg_live_..."

Response — 200

{
  "id": "msgbatch_01K...",
  "type": "message_batch_deleted"
}

Recovery semantics

Batch items use the same durable queue as native async requests. Recovery is at-least-once, not exactly-once: after a worker crash, an abandoned lease can be reclaimed, and an item may be sent upstream again if the first upstream response was not durably stored. The Model Gate request ID remains stable across retries and settlement guards prevent a second account debit for an already-finished request.

Each item is admitted immediately before a worker claims it. Otherwise-valid items remain queued while the current account balance is non-positive or the key/group resettable spend limit is already exhausted; waiting for funds does not consume an attempt or mark the item failed. A later top-up, usage reset, or limit increase automatically resumes eligible queued items. Model Gate does not reserve a worst-case batch cost, so concurrently admitted items may finish with a negative final balance or a small spend-limit overshoot; only subsequent new items are held.

Pricing and accounting

Each batch item uses the same model routing, token accounting, pricing snapshot, usage valuation, API-key/group limits, and settlement logic as a normal Model Gate request. An administrator may configure a Batch request price coefficient on the account pricing template. The default is 1.

For example, with normal Model Gate cost 0.02 and batch coefficient 0.5, the actual account debit is 0.01. The saved official-provider reference amount is not multiplied by this Model Gate batch coefficient. Native requests using "async": true are also not affected.

If the coefficient differs from 1, it is shown on the Model prices page and in /v1/models as batch_pricing plus the effective batch_cost rates.

Errors

Invalid or duplicate custom_id, an unknown model, stream:true, nested async:true, an oversized request, or an invalid body returns a normal Anthropic-style error response.

{
  "type": "error",
  "error": {
    "type": "invalid_request_error",
    "message": "summary-1: stream=true is not supported inside a batch"
  }
}