HelipodDocs

Management API

Read prices, balance, usage and metrics, revoke AI keys and top up the AI balance with a Helipod API key.

The AI Gateway itself answers model requests with an AI key (hel_ai_...). Everything around it, what the AI Gateway pages of the dashboard show, is available from the AI API with a Helipod API key: prices, the AI balance, usage and charts, your AI keys, and top-ups from the wallet.

Base URL
https://api.helipod.io/api/ai

The key needs AI API enabled. It is not in a new key's default products: tick it when you create the key. An AI key (hel_ai_...) is not accepted here, and a Helipod API key is not accepted by the gateway.

curl https://api.helipod.io/api/ai/overview \
  -H "Authorization: Bearer hel_your_key"

Whole account or one project

The AI balance and the wallet belong to your account, so the overview, top-ups and auto top-up need a whole-account key (403 ACCOUNT_KEY_REQUIRED otherwise). Usage, metrics and the key list work with both: a key limited to one project sees that project only, and a whole-account key can narrow them with ?projectId=.

Method and pathKey
PricesGET /modelsany
BalanceGET /overviewwhole account
UsageGET /usage, GET /metricsany
AI keysGET /keys, DELETE /keys/{keyId}any
Top upPOST /topup, PUT /auto-topupwhole account

Creating AI keys stays in the dashboard

The API lists and revokes AI keys but never creates or shows one, so a Helipod key can't be used to mint a key that spends your balance. Create AI keys in the dashboard under AI Gateway.

Prices

GET/ai/models
Every model with its price for you, per 1M tokens in Rupiah.
{
  "success": true,
  "data": {
    "currency": "IDR",
    "unit": "per 1M tokens",
    "taxPercent": 11,
    "models": [
      {
        "code": "glm-5.3",
        "name": "GLM 5.3",
        "family": "glm",
        "limits": { "context": 200000, "maxInput": 200000, "maxOutput": 32000 },
        "capabilities": ["tools", "reasoning"],
        "formats": ["openai", "anthropic"],
        "peakHours": null,
        "currentWindow": "all",
        "sunset": null,
        "campaign": null,
        "tiers": [ { "window": "all", "minInputTokens": 0, "input": 9000, "output": 36000, "cached": 1800, "promo": null } ]
      }
    ]
  }
}

tiers lists the prices per window (peak and off-peak, when the model has them) and per prompt size (minInputTokens). promo holds the discounted prices of a running promotion that applies to you, described in campaign. See Pricing and billing.

Balance

GET/ai/overview
The AI balance, free credit, wallet, top-up packs and auto top-up.
{
  "success": true,
  "data": {
    "balance": 85000,
    "held": 1200,
    "freeCredit": 10000,
    "available": 93800,
    "walletBalance": 482500,
    "limitedCredit": [],
    "autoTopup": { "enabled": false, "threshold": null, "amount": null, "lastFailedAt": null },
    "minTopup": 20000,
    "taxPercent": 11,
    "currency": "IDR",
    "packs": [ { "id": "pack-100k", "name": "Rp 100.000", "amount": 100000, "bonus": 5000 } ],
    "coupons": []
  }
}

Prop

Type

Usage

GET/ai/usage
Recent requests one by one, and this month's totals per model.

Prop

Type

{
  "success": true,
  "data": {
    "thisMonth": {
      "charge": 15230.5,
      "saved": 0,
      "byModel": [ { "model": "glm-5.3", "requests": 412, "inputTokens": 1210000, "cachedTokens": 380000, "outputTokens": 214000, "charge": 15230.5, "saved": 0 } ]
    },
    "requests": [
      {
        "requestId": "req_01JA8Z3K4M",
        "createdAt": "2026-10-16T09:12:03.000Z",
        "model": "glm-5.3",
        "format": "openai",
        "stream": true,
        "status": "ok",
        "projectId": "3b0cd5ac-ac26-4012-9b28-17466f73788c",
        "aiKeyId": "5f4e3d2c-1b0a-4f9e-8d7c-6b5a4f3e2d1c",
        "inputTokens": 3200, "cachedTokens": 1800, "cacheWriteTokens": 0, "outputTokens": 640,
        "priceWindow": "all",
        "charge": 54.7,
        "listCharge": 54.7,
        "latencyMs": 2140,
        "promo": null
      }
    ],
    "total": 100,
    "capped": true,
    "page": 1,
    "pageSize": 50,
    "currency": "IDR"
  }
}

The request list keeps the latest 100 requests; capped: true means older ones exist. charge is what a request cost you, listCharge what it would have cost without a promotion.

GET/ai/metrics
Charts for the last 24 hours (hourly) or 7 or 30 days (daily).

Takes projectId, keyId and model like usage, and range: 24h (default), 7d or 30d.

{
  "success": true,
  "data": {
    "range": "24h",
    "bucket": "hour",
    "timezone": "Asia/Jakarta",
    "currency": "IDR",
    "totals": {
      "requests": 412, "ok": 405, "errors": 5, "cancelled": 2, "successRate": 0.983,
      "charge": 15230.5, "saved": 0, "promoRequests": 0,
      "inputTokens": 1210000, "cachedTokens": 380000, "outputTokens": 214000,
      "cacheHitRate": 0.239, "avgLatencyMs": 1980, "p95LatencyMs": 6100
    },
    "previous": { "requests": 380, "charge": 13900 },
    "series": [ { "t": "2026-10-16T09", "requests": 31, "errors": 0, "charge": 1104.2, "inputTokens": 91000, "cachedTokens": 30000, "outputTokens": 16000, "avgLatencyMs": 1870 } ],
    "byModel": [ { "model": "glm-5.3", "requests": 412, "charge": 15230.5, "saved": 0, "tokens": 1804000 } ]
  }
}

previous is the same range just before, for comparison. Buckets are in Western Indonesia Time.

AI keys

GET/ai/keys
Your active AI keys, without their secrets. Takes projectId like usage.
{
  "success": true,
  "data": [
    {
      "id": "5f4e3d2c-1b0a-4f9e-8d7c-6b5a4f3e2d1c",
      "name": "production",
      "prefix": "hel_ai_Xk3q",
      "projectId": "3b0cd5ac-ac26-4012-9b28-17466f73788c",
      "status": "active",
      "allowedModels": null,
      "spendLimitMonthly": 500000,
      "lastUsedAt": "2026-10-16T09:12:03.000Z",
      "expiresAt": null,
      "createdAt": "2026-09-01T08:00:00.000Z"
    }
  ]
}

allowedModels is null when the key may use every model.

DELETE/ai/keys/{keyId}
Revokes the key at once. Requests with it fail from then on.

Returns { "id": "...", "revoked": true }, or 404 KEY_NOT_FOUND. A key limited to one project can revoke only that project's AI keys.

Top up

POST/ai/topupcharges your walletdryRunIdempotency-Key
Move money from the wallet to the AI balance.

Prop

Type

Send exactly one of packId or amount (400 INVALID_TOPUP otherwise). See it first with ?dryRun=true:

curl -X POST "https://api.helipod.io/api/ai/topup?dryRun=true" \
  -H "Authorization: Bearer hel_your_key" -H "Content-Type: application/json" \
  -d '{ "amount": 100000 }'
{
  "success": true,
  "data": {
    "dryRun": true,
    "currency": "IDR",
    "amount": 100000,
    "packId": null,
    "bonus": 0,
    "packBonus": 0,
    "campaignBonus": 0,
    "walletBalance": 482500,
    "walletBalanceAfter": 382500,
    "enoughBalance": true,
    "aiBalance": 85000,
    "aiBalanceAfter": 185000
  }
}

The real call needs an Idempotency-Key header (400 IDEMPOTENCY_KEY_REQUIRED otherwise), so a retry never moves the money twice:

curl -X POST https://api.helipod.io/api/ai/topup \
  -H "Authorization: Bearer hel_your_key" -H "Content-Type: application/json" \
  -H "Idempotency-Key: ai-topup-2026-10-16-a1b2" \
  -d '{ "amount": 100000 }'
{ "success": true, "data": { "dryRun": false, "currency": "IDR", "amount": 100000, "bonus": 0, "campaignBonus": 0, "aiBalance": 185000, "walletBalance": 382500 } }

The AI balance can't be moved back to the wallet. A wallet that can't cover it answers 402 INSUFFICIENT_WALLET, an amount below the minimum 400 AMOUNT_TOO_SMALL, an unknown pack 404 PACK_NOT_FOUND. A running top-up bonus is subject to its remaining budget, so the real campaignBonus can be lower than the dry run's.

Auto top-up

PUT/ai/auto-topupdryRun
Top up from the wallet automatically when the AI balance runs low.

Prop

Type

curl -X PUT https://api.helipod.io/api/ai/auto-topup \
  -H "Authorization: Bearer hel_your_key" -H "Content-Type: application/json" \
  -d '{ "enabled": true, "threshold": 20000, "amount": 100000 }'

The response is the overview with the new autoTopup. With ?dryRun=true nothing is saved; the response is { "dryRun": true, "current": { ... }, "next": { ... }, "walletBalance": ..., "currency": "IDR" }. A missing threshold answers 400 INVALID_THRESHOLD, an amount below the minimum 400 AMOUNT_TOO_SMALL.

Errors

StatusCodeWhen
401NO_API_KEY, INVALID_API_KEY, API_KEY_EXPIREDAuthentication failed
403SCOPE_NOT_ALLOWEDThe key was not given the AI API
403ACCOUNT_KEY_REQUIREDBalance, top-up or auto top-up with a key limited to one project
400INVALID_TOPUP, AMOUNT_TOO_SMALL, INVALID_THRESHOLD, IDEMPOTENCY_KEY_REQUIREDSee above
402INSUFFICIENT_WALLETThe wallet can't cover the top-up
404KEY_NOT_FOUND, PACK_NOT_FOUND, PROJECT_NOT_FOUNDDoesn't exist, or the key can't reach it
409REQUEST_IN_PROGRESSA top-up with the same Idempotency-Key is still running
422VALIDATION_ERRORThe body or query does not match the schema

On this page