Skip to main content

API tokens

All /v1/ endpoints authenticate via an API token. Tokens:
  • Start with the prefix ab_
  • Are 51 characters long
  • Are scoped to a single organization
  • Never expire (but can be revoked instantly)
Create a token: Dashboard → Settings → API tokens → New token. API token access requires the Team plan. The token value is shown only once at creation — store it in a secrets manager or environment variable immediately.

Authorization header

Pass your token in the Authorization header on every request:
curl https://api.kallima.bio/v1/me \
  -H "Authorization: Bearer ab_your_token_here"
from kallima import KallimaClient
client = KallimaClient("ab_your_token_here")
Requests without a valid token return 401 unauthorized.

Check your balance

Before submitting compute jobs, verify your credit balance with:
curl https://api.kallima.bio/v1/me \
  -H "Authorization: Bearer ab_your_token_here"
{
  "org_id": "aabbccdd-...",
  "plan": "team",
  "subscription_balance": 11840,
  "purchased_balance": 500,
  "total_credits": 12340,
  "monthly_grant": 12000
}
See Credits for the full cost table and how to buy additional credits.

Rate limits

Every /v1/ response carries rate-limit headers:
HeaderMeaning
X-RateLimit-LimitRequests allowed per minute
X-RateLimit-RemainingRequests left in the current window
X-RateLimit-ResetRFC 7231 timestamp when the window resets
X-Quota-LimitWrite requests allowed this calendar month
X-Quota-RemainingWrite requests left this month
X-Quota-ResetRFC 7231 timestamp when the monthly quota resets
Reads (GET) consume the rate bucket but do not count against your monthly write quota — polling for job status is free. Writes (POST/PATCH/DELETE) consume both the rate bucket and the quota. Pipeline submits additionally spend credits.
PlanRateMonthly writes
Team60 req/min25,000
Enterprisecustomcustom
When you hit a limit the API returns 429 with a Retry-After header giving the seconds until the window resets.

Errors

All error responses use RFC 9457 problem+json with Content-Type: application/problem+json.
{
  "type": "https://docs.kallima.bio/errors/insufficient_credits",
  "title": "Insufficient credits",
  "status": 402,
  "detail": "Humanization costs 1 credit; balance is 0.",
  "instance": "/v1/humanizations",
  "code": "insufficient_credits",
  "request_id": "req_01JB..."
}
Switch on the code field — it is stable across API versions.
codeHTTPMeaning
unauthorized401Missing or invalid token
not_found404Resource doesn’t exist in your org
insufficient_credits402Not enough credits — top up or upgrade
plan_required402Endpoint requires a higher plan
rate_limit_exceeded429Slow down — check Retry-After
quota_exceeded429Monthly write quota exhausted
invalid_request400Malformed body
validation_failed422Field-level validation error — see errors array
idempotency_mismatch422Same Idempotency-Key with different body
conflict409e.g. canceling an already-running job
internal_error500Something went wrong on our side

Python SDK error handling

from kallima import (
    KallimaClient,
    KallimaError,
    InsufficientCreditsError,
    RateLimitError,
    NotFoundError,
)
import time

client = KallimaClient(api_key)

try:
    job = client.humanizations.submit(variant_id=variant_id)
except InsufficientCreditsError as e:
    print(f"Out of credits: {e}")
except RateLimitError as e:
    time.sleep(e.retry_after or 60)
    job = client.humanizations.submit(variant_id=variant_id)
except NotFoundError:
    print("Variant not found or doesn't belong to your org")
except KallimaError as e:
    print(f"API error {e.status_code} [{e.code}]: {e}")

Idempotency

All write endpoints accept an Idempotency-Key header. Send a unique UUID per logical operation — replayed requests with the same key return the cached response without creating a duplicate job or spending credits twice.
curl -X POST https://api.kallima.bio/v1/humanizations \
  -H "Authorization: Bearer ab_..." \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"variant_id": "11112222-3333-4444-5555-666677778888"}'
Keys expire after 24 hours. Sending the same key with a different request body returns 422 idempotency_mismatch.