APIARIUM
Home
Sign in
Get started

API REFERENCE

Introduction
Authentication
Credits
Credit Packs
Multi-currency
Rate Limits
Errors
LLM — Text
Image Generation
Text to Speech
Transcription

Introduction

Apiarium provides a unified REST API to access multiple AI models under a single API key. No need to manage separate accounts for OpenAI, Anthropic, Google or other providers.

Coming from OpenRouter or LiteLLM? See how OpenRouter migration works · or LiteLLM →

Base URL:

https://api.apiarium.dev

Authentication

All requests must include your API key in the Authorization header using the Bearer scheme.

Authorization: Bearer sk_apiarium_live_...

You can find your API key in your dashboard. Keep it secret — never expose it in client-side code.

Credits

Credits are Apiarium's unit of consumption. Each request deducts credits based on the model used and the size of the task. Your balance is always visible in your dashboard.

Your account has two credit balances: plan credits (included with your subscription, reset monthly for paid plans) and extra credits (purchased separately via credit packs — see below). Plan credits are used first; extra credits are used automatically once your plan credits run out.

OPERATIONCREDITS
Text — gpt-4o-mini (per request)1–5
Text — claude-haiku (per request)8–38
Text — gemini (per request)13–63
Text — gpt-4o (per request)17–83
Text — claude-sonnet (per request)23–113
Text — smart (classification + real answer, combined)varies — see Smart routing
Image — gpt-image-2, low quality5
Image — gpt-image-2, medium quality (default)35
Image — gpt-image-2, high quality175
Image — gemini-flash-image (Starter / Pro)90
Image — gemini-pro-image (Pro)220
Text to Speech — tts-1 (per 1,000 characters)28
Text to Speech — gemini-tts (per 1,000 characters)70
Transcription (per minute of audio)10

Text generation cost depends on the number of tokens processed and the model used. Credits are calculated as: model_multiplier × (input_tokens × 0.75 + output_tokens × 4.50) / 1000, with a minimum of 1 credit per request. The multiplier reflects each model's real cost (gpt-4o-mini = 1x, claude-haiku = 7.5x, gemini = 12.5x, gpt-4o = 16.5x, claude-sonnet = 22.5x) — this is why models cost proportionally more, not just a flat token count.

Credit Packs

Need more credits without waiting for your monthly reset? You can buy credit packs at any time — no subscription required. Purchased credits never expire before 12 months and are used automatically once your plan credits run out.

There are two pricing tiers, applied automatically based on your account:

Pay-as-you-goFor Free plan accounts — no active subscription
Top-upFor Starter/Pro subscribers — same rate as your plan's own subscription price per credit, no extra markup

List active packs

GET/stripe/credits/packs

Returns your active (non-expired, non-refunded) credit packs, along with the total extra balance. Requires a Supabase session token, not an API key — this endpoint is used by the dashboard, not for programmatic API usage.

{
  "packs": [
    {
      "id": "74da67c7-...",
      "source": "payasyougo",
      "credits_original": 1714,
      "credits_remaining": 1618,
      "expires_at": "2027-07-02T13:14:13.969+00:00",
      "created_at": "2026-07-02T13:14:14.382553+00:00",
      "refunded": false,
      "expired": false
    }
  ],
  "total_extra": 1618
}

Multi-currency

Apiarium supports billing in 10 currencies: EUR, USD, GBP, CAD, INR, AUD, BRL, MXN, JPY, and SGD. Currency is detected automatically based on your location when you visit the pricing page.

Subscription prices are fixed per currency (not a live conversion) — each plan has a dedicated price for each supported currency. Pay-as-you-go and top-up purchases calculate the exact credit amount at checkout time based on the amount and currency you choose.

All amounts sent to the API (subscription checkout, credit pack purchases) must include a currency field matching one of the supported codes below, in lowercase:

eur
usd
gbp
cad
inr
aud
brl
mxn
jpy
sgd

Rate Limits

/llm's rate limit scales with your plan tier, applied per IP address. /image is different: it's a shared capacity pool across every Apiarium user, because it's constrained by our upstream AI providers' own account-wide limits rather than by any single user's traffic. If you exceed a limit, requests return a 429 status until capacity frees up.

/llm — Free plan20 requests / minute (per IP)
/llm — Starter plan60 requests / minute (per IP)
/llm — Pro / Studio plan120 requests / minute (per IP)
/imageShared pool — up to 5/min for OpenAI models, 10/min for Gemini models
/tts20 requests / minute (per IP)
/transcribe15 requests / minute (per IP)
All other routes100 requests / minute (per IP)

Because /image capacity is shared across all users rather than tied to your IP, a busy moment for Apiarium overall — not just your own usage — can occasionally result in a 429 on that endpoint. Retry after a few seconds.

/llm, /tts, and /transcribe responses include standard rate limit headers so you can track your usage:

RateLimit-Limit: 60
RateLimit-Remaining: 57
RateLimit-Reset: 42  // seconds until the window resets

Errors

Apiarium uses standard HTTP status codes. All errors return a JSON object with an error field.

200Success
202Accepted — job started, poll for the result (currently: POST /image)
400Bad request — missing or invalid parameters
401Unauthorized — invalid or missing API key
402Insufficient credits
403Model not available on your plan
404Job or resource not found
429Rate limit exceeded
500Internal server error

Example error response:

{
  "error": "Model \"claude-haiku\" is not available on your plan (starter). Upgrade to access more models.",
  "available_models": ["gpt-4o-mini"]
}

Provider errors

When a request fails on the AI provider's side (rate limits, overload, downtime), the response includes error_class and provider fields so you can branch your retry logic on the failure type, not on which provider was called. For /image, these fields show up on the failed job (see GET /image/:id below), not on the initial POST — the POST only fails synchronously for request-validation problems (bad params, insufficient credits, plan restrictions).

rate_limited429Provider rate limit hit — retry with backoff
overloaded503Provider temporarily overloaded — retry later
quota_exceeded503Provider quota exhausted on our side
invalid_request400Request rejected by the provider
content_filter400Rejected by the provider's content safety system — retrying the same input will not succeed
timeout504We gave up waiting on the provider — distinct from a provider-side error
authentication_error502Provider auth failed — not your fault, contact us
server_error502Provider had an internal error
unknown502Provider returned an error shape we don't recognize yet — rare, please report it

Example provider error response (from /llm, /tts, /transcribe):

{
  "error": "AI provider error. Please try again.",
  "error_class": "overloaded",
  "provider": "anthropic"
}

LLM — Text Generation

POST/llm

Generate text using GPT, Claude, or Gemini models. Send a list of messages in chat format and receive a completion. Streaming is not supported — the full response is returned at once.

Available models

gpt-4o-miniFree, Starter, Pro
gpt-4oPro only
claude-haikuStarter, Pro
claude-sonnetPro only
geminiPro only
smartAll plans — see below

gemini maps to Google's Gemini 3.5 Flash, their current flagship model — comparable in capability to gpt-4o and claude-sonnet, which is why it sits alongside them as a Pro-only option.

Smart routing

Send "model": "smart" instead of picking one yourself, and Apiarium classifies your request and routes it to whichever of the five models above best fits — complex code to Claude Sonnet, multi-step reasoning and translation to Gemini, everyday chat to GPT-4o mini, and so on. The response always includes model_used and reason, so it's never a black box, and if your plan doesn't include the ideal model for a request, the reason field says so explicitly instead of pretending otherwise.

Combine smart routing with an optional max_cost (in USD) to cap what Apiarium is allowed to spend on the request. It picks the best model that fits within that budget instead of the absolute best model available — and if even the cheapest eligible model exceeds your budget, it says so plainly in the reason rather than silently going over. max_cost is only valid together with "model": "smart" — it has no effect when you've already chosen a specific model, and sending both returns a 400 error rather than being silently ignored.

Smart requests are billed for the (small) classification call and the real answer together, combined into one credits_used total — never billed separately or hidden.

Knowing when a response was cut off

Every response includes finish_reason, normalized to the same four values regardless of which provider actually answered: stop (finished naturally), length (cut off because it hit max_tokens), content_filter (blocked by the provider's safety system — retrying the same input won't help), or tool_calls. Check this field instead of guessing from the content alone whenever it matters whether a response is complete.

Parameters

PARAMTYPEREQDESCRIPTION
messagesarrayYesArray of message objects with role (user/assistant/system) and content. Max 20 messages, 10,000 chars each.
modelstringNogpt-4o-mini, gpt-4o, claude-haiku, claude-sonnet, gemini, or smart (see Smart routing above). Default: gpt-4o-mini
max_tokensnumberNoMaximum tokens to generate. Range: 1–4096. Default: 4096 — the same value across all three providers, and the same ceiling this parameter already allowed you to request explicitly.
temperaturenumberNoRandomness of the response. GPT and Gemini models accept 0–2. Claude models accept 0–1 (values above 1 are clamped). Default: 1.0.
max_costnumberNoBudget in USD for this request. Only valid when model is smart — constrains which model smart routing is allowed to pick. See Smart routing above.

Example

curl
javascript
python
curl -X POST https://api.apiarium.dev/llm \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [
      { "role": "system", "content": "You are a helpful assistant." },
      { "role": "user", "content": "Write a tagline for a coffee brand" }
    ],
    "model": "claude-haiku",
    "max_tokens": 256,
    "temperature": 0.7
  }'

Response

{
  "content": "Brew the moment.",
  "model": "claude-haiku",
  "credits_used": 2,
  "credits_remaining": 9998,
  "tokens": { "input": 12, "output": 9 },
  "finish_reason": "stop"
}

Example — smart routing

curl
javascript
python
curl -X POST https://api.apiarium.dev/llm \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [{ "role": "user", "content": "Refactor this function to handle null inputs and add tests" }],
    "model": "smart"
  }'

Response — smart routing:

{
  "content": "Here's the refactored function...",
  "model": "claude-sonnet",
  "model_used": "claude-sonnet",
  "reason": "Best model for complex coding tasks",
  "credits_used": 14,
  "credits_remaining": 9986,
  "tokens": { "input": 21, "output": 187 },
  "finish_reason": "stop"
}

Example — smart routing with a budget

Same request as above, but capped at $0.002 — too tight for claude-sonnet, so it falls back to the best model that does fit:

curl
javascript
python
curl -X POST https://api.apiarium.dev/llm \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [{ "role": "user", "content": "Refactor this function to handle null inputs and add tests" }],
    "model": "smart",
    "max_cost": 0.002
  }'

Response — budget forced a cheaper model:

{
  "content": "Here's the refactored function...",
  "model": "gpt-4o-mini",
  "model_used": "gpt-4o-mini",
  "reason": "Best model for complex coding tasks — best option within your max_cost budget and current plan",
  "credits_used": 1,
  "credits_remaining": 9999,
  "tokens": { "input": 21, "output": 143 },
  "finish_reason": "stop"
}

Image Generation

POST/imageGET/image/:id

Generate images from a text prompt using OpenAI or Google's image models. All plans use gpt-image-2 by default. Starter also unlocks Gemini's gemini-flash-image. Pro plans additionally get gemini-pro-image, Google's highest-quality option. Images are stored privately and served via a short-lived signed URL — see the url_expires_in_seconds field below.

This endpoint is asynchronous. POST /image doesn't wait for the image to finish generating — high-quality generations can legitimately take over a minute, longer than any HTTP proxy should reasonably stay open. Instead, POST /image responds immediately (202) with a job_id, and you poll GET /image/:job_id until the job's status is done (with the final url) or failed (credits are refunded automatically in that case).

Note: /image has a shared capacity limit across all Apiarium users (see Rate Limits above), since it's bound by our upstream providers' account-wide throughput rather than per-user traffic. The POST call may occasionally return a 429 here even under normal usage — retry after a few seconds.

Available models

gpt-image-2Free, Starter, Pro5–175 (by quality)
gemini-flash-imageStarter, Pro90
gemini-pro-imagePro only220
smartAll plans — see belowvaries

gemini-flash-image (Nano Banana 2) is optimized for speed and high-volume generation. gemini-pro-image (Nano Banana Pro) is Google's highest-quality model, better suited for complex prompts, accurate text rendering, and multi-turn edits. gpt-image-2 sits in between, with three quality tiers (low/medium/high) covering everything from cheap icons to near-photorealistic output.

Smart routing

Send "model": "smart" and Apiarium classifies your prompt and routes to whichever of the three models above fits best — simple icons/graphics to gpt-image-2 at low quality (cheap), photorealistic or text-heavy prompts to gemini-pro-image (or gpt-image-2 at high quality if your plan doesn't include it), fast/high-volume needs to gemini-flash-image, and so on. Since the response to POST /image is just the job-started acknowledgment, model_used and reason are included there, immediately — you don't need to wait for the job to finish to see which model was picked or why. If your plan doesn't include the ideal model, smart routing picks the best one your plan does allow and says so in the reason field.

Like /llm's smart routing, the classification call's cost is folded into credits_reserved (and later credits_used on the finished job) along with the real image generation cost — never hidden or billed separately.

Combine with an optional max_cost (in USD) to cap what smart routing is allowed to spend — useful since the price gap between models here is large (5 to 220 credits). If the ideal model for your prompt is over budget, Apiarium picks the best one that fits and says so in the reason. If even the cheapest eligible model exceeds your budget, it uses that one anyway and says so plainly rather than pretending it stayed under budget. Same rule as /llm: max_cost only works with "model": "smart" — sending it with a specific model returns a 400 error.

Parameters — POST /image

PARAMTYPEREQDESCRIPTION
promptstringYesText description of the image to generate. Max 4,000 characters.
modelstringNogpt-image-2, gemini-flash-image, gemini-pro-image, or smart (see Smart routing above). Availability depends on your plan. Default: gpt-image-2, on every plan.
sizestringNo1024x1024 (default), 1536x1024, 1024x1536, or auto. Only applies to gpt-image-2.
qualitystringNolow, medium (default), or high. Only applies to gpt-image-2 — 5/35/175 credits respectively. Ignored when model is smart — smart routing picks quality automatically. Gemini models have no quality tiers.
output_formatstringNopng (default), jpeg, or webp. Only applies to gpt-image-2 — Gemini models always return png.
backgroundstringNoopaque (default) or transparent. Only applies to gpt-image-2.
max_costnumberNoBudget in USD for this request. Only valid when model is smart. See Smart routing above.

Start a job

curl
javascript
python
curl -X POST https://api.apiarium.dev/image \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "A futuristic city at sunset, digital art",
    "model": "gemini-flash-image"
  }'

Response — 202 Accepted

{
  "job_id": "b131832b-f32e-4be2-ab56-8afa2df2e768",
  "status": "processing",
  "model": "gemini-flash-image",
  "output_format": "png",
  "credits_reserved": 90,
  "poll_url": "/image/b131832b-f32e-4be2-ab56-8afa2df2e768"
}

Credits are reserved immediately (credits_reserved) so you can't accidentally over-spend by starting many jobs at once — they're adjusted to the exact final cost (usually identical) once the job completes, or fully refunded if it fails.

Some parameters only apply to specific models. If you send a parameter unsupported by the model you chose (e.g. quality with a Gemini model), the job still starts — the 202 response includes a warnings field so you know it was ignored, instead of failing silently:

{
  "job_id": "b131832b-f32e-4be2-ab56-8afa2df2e768",
  "status": "processing",
  "model": "gemini-flash-image",
  "output_format": "png",
  "credits_reserved": 90,
  "poll_url": "/image/b131832b-f32e-4be2-ab56-8afa2df2e768",
  "warnings": ["The following parameters are not supported by gemini-flash-image and were ignored: quality"]
}

Poll for the result

Use the job_id from the 202 response (or the poll_url, appended to the base URL) to check status. Same API key, no request body. We recommend polling every 2–5 seconds with light backoff.

curl
javascript
python
curl https://api.apiarium.dev/image/b131832b-f32e-4be2-ab56-8afa2df2e768 \
  -H "Authorization: Bearer YOUR_API_KEY"

Response — while processing

{
  "job_id": "b131832b-f32e-4be2-ab56-8afa2df2e768",
  "status": "processing",
  "model": "gemini-flash-image",
  "output_format": "png"
}

Response — done

url is a signed URL, not a permanent public link — it expires after url_expires_in_seconds. Re-poll the same job_id to get a fresh URL if it expires; the image itself doesn't disappear, only that particular link.

{
  "job_id": "b131832b-f32e-4be2-ab56-8afa2df2e768",
  "status": "done",
  "model": "gemini-flash-image",
  "output_format": "png",
  "url": "https://saduxychstwvxqgevqxw.supabase.co/storage/v1/object/sign/images/abc123.png?token=...",
  "url_expires_in_seconds": 3600,
  "credits_used": 90,
  "credits_remaining": 9910
}

Response — failed

If generation fails on the provider's side or our own storage upload fails, the job is marked failed and the reserved credits are refunded automatically — you're never charged for a job that didn't deliver an image.

{
  "job_id": "b131832b-f32e-4be2-ab56-8afa2df2e768",
  "status": "failed",
  "model": "gemini-flash-image",
  "output_format": "png",
  "error": "AI provider error. Please try again.",
  "error_class": "overloaded"
}

Example — smart routing

curl
javascript
python
curl -X POST https://api.apiarium.dev/image \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "A logo that says APIARIUM in bold gold letters",
    "model": "smart"
  }'

Response — job started, smart routing already resolved:

{
  "job_id": "5e2f9c3a-1b7d-4a6e-9c2f-8a3b1d4e5f6a",
  "status": "processing",
  "model": "gemini-pro-image",
  "output_format": "png",
  "credits_reserved": 221,
  "poll_url": "/image/5e2f9c3a-1b7d-4a6e-9c2f-8a3b1d4e5f6a",
  "model_used": "gemini-pro-image",
  "reason": "Best model for accurate text rendering inside the image"
}

Poll GET /image/5e2f9c3a-1b7d-4a6e-9c2f-8a3b1d4e5f6a as shown above to get the final url once status is done.

Example — smart routing with a budget

Same prompt, capped at $0.05 (≈ 21 credits) — too tight for gemini-pro-image (220 credits) or gpt-image-2 at high quality (175 credits), the two models that handle in-image text well. Smart routing falls back to the cheapest of those two and says so honestly instead of pretending it stayed within budget:

curl
javascript
python
curl -X POST https://api.apiarium.dev/image \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "A logo that says APIARIUM in bold gold letters",
    "model": "smart",
    "max_cost": 0.05
  }'

Response — job started, budget was too low even for the cheapest eligible option:

{
  "job_id": "9d1e2f3a-4b5c-6d7e-8f9a-0b1c2d3e4f5a",
  "status": "processing",
  "model": "gpt-image-2",
  "output_format": "png",
  "credits_reserved": 175,
  "poll_url": "/image/9d1e2f3a-4b5c-6d7e-8f9a-0b1c2d3e4f5a",
  "model_used": "gpt-image-2",
  "reason": "max_cost was too low for any eligible model on your plan — used the cheapest option instead, which still exceeds your budget"
}

Text to Speech

POST/tts

Convert text to natural-sounding audio using OpenAI or Gemini voices. Maximum input: 4,096 characters per request.

Available models

tts-1Free, Starter, Pro28 / 1,000 chars
gemini-ttsFree, Starter, Pro70 / 1,000 chars
smartAll plans — see belowvaries

gemini-tts (Gemini 3.1 Flash TTS) is a premium option with natural-language style control — you can direct tone, pace, accent, and emotion (e.g. [whispers], [excited]) directly in the input text, and it supports 70+ languages and up to 2 distinct speakers in a single request. tts-1 (OpenAI) is the faster, lower-cost default with 6 fixed voices.

Note: gemini-tts only supports wav and pcm as response_format — it returns raw audio natively and doesn't go through OpenAI's format conversion. Use tts-1 if you need mp3, opus, aac, or flac.

Smart routing

Send "model": "smart" and Apiarium classifies your text and routes to whichever of the two models above fits best — plain narration to tts-1 (cheaper), and anything needing emotion/style control, non-English/accented speech, or multi-speaker dialogue to gemini-tts. Text containing inline style tags like [excitedly] is always routed to gemini-tts, since tts-1 would read the brackets out loud literally.

Because /tts returns raw audio rather than JSON, smart routing's model_used and reason are returned as response headers instead of a JSON field — see Response below. An explicitly-passed voice is ignored when model is smart, since a voice name valid for one provider isn't valid for the other; each provider's own default voice is used instead.

Combine with an optional max_cost (in USD) to cap what smart routing is allowed to spend — useful since gemini-tts costs roughly 2.4x tts-1. If your text would ideally use gemini-tts but that's over budget, Apiarium falls back to tts-1 and says so in X-Routing-Reason. Note that if your text relies on style tags like [excitedly], tts-1 will read them out loud literally rather than interpreting them — the reason field doesn't warn about this specifically, so avoid combining style-tag text with a tight max_cost. Same rule as the other endpoints: max_cost only works with "model": "smart".

Parameters

PARAMTYPEREQDESCRIPTION
textstringYesThe text to convert to speech. Max 4,096 characters. For gemini-tts, you can also include style tags like [whispers] or [excited] inline.
modelstringNotts-1, gemini-tts, or smart (see Smart routing above). Default: tts-1
voicestringNoFor tts-1: alloy (default), echo, fable, onyx, nova, shimmer. For gemini-tts: one of 30 voices (default: Kore) — see Google's voice library for the full list and styles. Ignored when model is smart.
speednumberNoPlayback speed. Range: 0.25–4.0. Default: 1.0. tts-1 only.
response_formatstringNotts-1: mp3 (default), opus, aac, flac, wav, or pcm. gemini-tts: wav (default) or pcm only.
max_costnumberNoBudget in USD for this request. Only valid when model is smart. See Smart routing above.

Example

curl
javascript
python
curl -X POST https://api.apiarium.dev/tts \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text": "Hello from Apiarium", "model": "tts-1", "voice": "nova", "speed": 1.0, "response_format": "mp3"}' \
  --output audio.mp3

Example — gemini-tts with style control

curl
javascript
python
curl -X POST https://api.apiarium.dev/tts \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text": "[excitedly] Hello from Apiarium!", "model": "gemini-tts", "voice": "Puck"}' \
  --output audio.wav

Example — smart routing

curl
javascript
python
curl -X POST https://api.apiarium.dev/tts \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text": "[excitedly] Hello from Apiarium!", "model": "smart"}' \
  --output audio.wav -D -

Response

Returns a binary audio stream. The Content-Type header reflects the requested format. Cost scales with character count — Math.ceil((chars / 1000) × rate) — so a short request like the "Hello from Apiarium" example above costs 1 credit, not the full per-1,000-char rate. Headers include:

Content-Type: audio/mpeg
X-Credits-Used: 1
X-Credits-Remaining: 9999

When model is smart, two additional headers are included:

X-Model-Used: gemini-tts
X-Routing-Reason: Text contains inline style tags, which only gemini-tts understands

Transcription

POST/transcribe

Transcribe audio to text using Whisper. Send an audio file as multipart/form-data. Costs 10 credits per minute of audio. Supports 50+ languages including English, Spanish, French, German, Portuguese, Italian, Japanese, Chinese, and more.

Parameters

PARAMTYPEREQDESCRIPTION
filefileYesAudio file (mp3, mp4, wav, m4a, webm). Max 25MB.
languagestringNo2-letter ISO language code (e.g. en, es, fr). Providing this improves accuracy and speed. Auto-detected if omitted.
promptstringNoOptional context to improve transcription accuracy. Useful for domain-specific terms, names, or acronyms. Max 224 tokens.

Example

curl
javascript
python
curl -X POST https://api.apiarium.dev/transcribe \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "file=@audio.mp3" \
  -F "language=en" \
  -F "prompt=Apiarium, Node.js, API"

Response

{
  "text": "Hello, this is a transcription of the audio file.",
  "credits_used": 10,
  "credits_remaining": 9990
}