anoman
Sign InGet API Key
Documentation home

Batch jobs.

POST · /v1/chat/completions + GET · /anoman/v1/batch — async routing for non-interactive workloads. ~50% cheaper than realtime with 5-30 minute SLA depending on tier.

When to use batch

Pick batch when…

  • Latency does not matter — overnight summarization, eval suites, data enrichment pipelines, batch RAG.
  • Volume is high — thousands of independent requests where ~50% savings adds up.
  • You can poll or wait — your code path is fine with 5-30 minute response times.

Pick realtime when…

  • You are streaming output to a user UI.
  • Latency is part of the product (chat, autocomplete, voice agents).
  • You need stream: true — batch does not support streaming.

SLA by tier

TierBatch SLANotes
Starter30 minDefault; overflow + opt-in
Pro15 minDefault for new accounts
Pay-As-You-Go15 minSame as Pro
Enterprise5 minOr custom contract SLA

When a queued job hits 80% of its SLA deadline without completing, Anoman auto-promotes it to realtime at full cost. You never see a breach — but you also stop saving.

Enqueue

Same endpoint, opt-in header

Batch is opt-in per request via x-anoman-prefer-batch: true (or set default_routing: batch on the API key in the dashboard for set-and-forget). The response is 202 with a poll_url.

# Opt-in via header; existing tools/SDKs work unchanged.
curl https://api.anoman.io/v1/chat/completions \
  -H "Authorization: Bearer anm-sk-..." \
  -H "Content-Type: application/json" \
  -H "x-anoman-prefer-batch: true" \
  -d '{
    "model": "deepseek-v3",
    "messages": [{"role": "user", "content": "Summarize this 50-page doc..."}]
  }'
{
  "id": "job_abc123def456",
  "object": "batch_job",
  "status": "queued",
  "sla_minutes": 15,
  "poll_url": "/anoman/v1/batch/job_abc123def456",
  "reason": "customer_preference",
  "meta": {
    "request_id": "req_xyz",
    "timestamp": "2026-05-28T10:00:00Z",
    "region": "id"
  }
}

Poll

GET /anoman/v1/batch/{job_id}

Hit the URL returned in the enqueue response. While processing, you get 202 with a hint poll_again_in_seconds. When complete, 200 with the full chat completion result plus savings_usd.

curl https://api.anoman.io/anoman/v1/batch/job_abc123def456 \
  -H "Authorization: Bearer anm-sk-..."
{
  "id": "job_abc123def456",
  "status": "processing",
  "sla_remaining_minutes": 8,
  "poll_again_in_seconds": 30
}
{
  "id": "chatcmpl-job_abc123def456",
  "object": "chat.completion",
  "choices": [{
    "message": { "role": "assistant", "content": "Summary: ..." }
  }],
  "usage": { "prompt_tokens": 4892, "completion_tokens": 1203 },
  "batch_job_id": "job_abc123def456",
  "routing_mode": "batch",
  "completed_at": "2026-05-28T10:08:42Z",
  "savings_usd": "0.0084"
}

Python helper

Enqueue + poll in one call

import time
import httpx
 
API = "https://api.anoman.io"
KEY = "anm-sk-..."
 
def enqueue(model, messages):
    r = httpx.post(
        f"{API}/v1/chat/completions",
        headers={
            "Authorization": f"Bearer {KEY}",
            "x-anoman-prefer-batch": "true",
        },
        json={"model": model, "messages": messages},
    )
    r.raise_for_status()
    return r.json()  # 202 with poll_url
 
def poll(job_id, deadline_minutes=30):
    deadline = time.time() + deadline_minutes * 60
    while time.time() < deadline:
        r = httpx.get(
            f"{API}/anoman/v1/batch/{job_id}",
            headers={"Authorization": f"Bearer {KEY}"},
        )
        r.raise_for_status()
        if r.status_code == 200:
            return r.json()  # complete
        # 202: still processing — respect poll_again_in_seconds
        wait = r.json().get("poll_again_in_seconds", 30)
        time.sleep(wait)
    raise TimeoutError(f"Job {job_id} exceeded {deadline_minutes}m deadline")
 
# Usage
job = enqueue("deepseek-v3", [{"role": "user", "content": "..."}])
print(f"Queued: {job['id']}, SLA: {job['sla_minutes']}m")
result = poll(job["id"])
print(result["choices"][0]["message"]["content"])
print(f"Saved: $-{result.get('savings_usd', '0')}")

Equivalent helper exists in the official Anoman SDK as client.poll_batch(job_id).

Cancel

DELETE /anoman/v1/batch/{job_id}

Queued jobs can be cancelled with a single DELETE. Once execution starts upstream, cancellation returns 409 (you are still billed for whatever has already run).

curl -X DELETE \
  https://api.anoman.io/anoman/v1/batch/job_abc123def456 \
  -H "Authorization: Bearer anm-sk-..."
 
# 200 — { "id": "job_abc123def456", "status": "cancelled" }
# 409 — if job already started executing

What batch does not support

Constraints

  • No streaming — stream:true forces realtime regardless of headers.
  • No realtime guarantees — the Enterprise tier realtime SLA does not apply.
  • Auto-promotion to realtime at 80% SLA — when SF degrades or queue is hot, we promote rather than miss the SLA. You stop saving but the job still completes on time.
  • Same guardrail pipeline runs before enqueue — a batch request that fails injection detection returns 403 immediately and is never queued.

See batch economics in the dashboard.

Per-month savings broken down by model + provider.