Gateway docs
Getting started › Quickstart

Quickstart

Create a project API key, list the models that key can use, then send a request through the Gateway with any of three SDK formats.

1

Create a project API key

Sign in to the console, create or choose an organization, workspace, and project, then issue an API key from that project. The key inherits the project's allowed model list and credit balance. Keys start with atp- and are 92 characters long. The full secret is shown once at creation — store it somewhere safe.

2

Point your SDK at the Gateway

The Gateway accepts the OpenAI, Anthropic, and Google GenAI SDKs using each SDK's default authentication header — no wrapper library needed. See Authentication for the three accepted key locations.

# OpenAI SDK
from openai import OpenAI
client = OpenAI(
    base_url="https://api.atptoken.ai/v1",
    api_key="atp-..."
)

# Anthropic SDK
from anthropic import Anthropic
client = Anthropic(
    base_url="https://api.atptoken.ai",
    api_key="atp-..."
)

# Google GenAI SDK (Gemini) — uses x-goog-api-key by default
from google import genai
client = genai.Client(
    api_key="atp-...",
    http_options={"base_url": "https://api.atptoken.ai"}
)
3

Discover allowed models

curl https://api.atptoken.ai/v1/models \
  -H "Authorization: Bearer atp-..."

Use one of the returned model IDs in the request body. If a model is not enabled for the project, the Gateway returns 403 before reaching any provider.

4

Make a request

curl https://api.atptoken.ai/v1/chat/completions \
  -H "Authorization: Bearer atp-..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "<model from GET /v1/models>",
    "messages": [{"role": "user", "content": "hi"}]
  }'
Model discovery
GET/v1/models

List available models

Lists every model available on the platform — the same catalog for every key, not only the models enabled for your project. Use it to get exact, current model IDs instead of copying names from a marketing page or provider dashboard.

This list is the menu, not your key's permissions

GET /v1/models is not scoped to your project. Which of these models a key may actually call is set by its project's allowed list and enforced at request time — calling a model that isn't enabled returns 403.

Response

{
  "object": "list",
  "data": [
    { "id": "claude-sonnet-4-6", "object": "model", "created": 1700000000, "owned_by": "llm-gateway" },
    { "id": "gpt-5.4", "object": "model", "created": 1700000000, "owned_by": "llm-gateway" }
  ]
}
Models

How model access works

One key · Project controls
model
OpenAI-compatible
Use the same SDK shape and swap only the base URL.
model
Project-scoped
Each key follows the models enabled on its project.
model
Fallback-ready
Route through the configured provider pool for that model.
model
Discoverable
API keys can list their available models from the Gateway.
Authentication

Three accepted key locations

The Gateway accepts a project API key in any of the locations below. Use whichever your SDK sends by default — there's no need to override headers. The Gateway strips the key from the request before forwarding to the provider.

LocationUsed by
Authorization: Bearer atp-…OpenAI SDK, Anthropic SDK, curl
x-goog-api-key: atp-…Google GenAI SDK (recommended for Gemini)
?key=atp-…Gemini REST clients. Logs scrub this query param — prefer the header form when possible.

If none of the three are present → 401. If the key is disabled or expired → 401.

Getting started

Coding agents (Claude Code, Codex)

Any agent that speaks the Anthropic or OpenAI wire format can run on a project key — point it at the Gateway base URL and use a model from GET /v1/models.

Claude Code

Set the base URL (no /v1 — Claude Code appends /v1/messages itself) and send the key as the auth token. Clear ANTHROPIC_API_KEY so it doesn't take precedence.

export ANTHROPIC_BASE_URL="https://api.atptoken.ai"
export ANTHROPIC_AUTH_TOKEN="atp-..."
export ANTHROPIC_API_KEY=""
export ANTHROPIC_MODEL="claude-sonnet-4-6"   # any model from GET /v1/models
claude

Or set the same values under the env block of ~/.claude/settings.json:

{
  "env": {
    "ANTHROPIC_BASE_URL": "https://api.atptoken.ai",
    "ANTHROPIC_AUTH_TOKEN": "atp-...",
    "ANTHROPIC_API_KEY": ""
  },
  "model": "claude-sonnet-4-6"
}

Codex CLI

Add the Gateway as a custom OpenAI-compatible provider in ~/.codex/config.toml (base URL includes /v1), then export the key named by env_key.

# ~/.codex/config.toml
model = "gpt-5.4"            # any model from GET /v1/models
model_provider = "atp"

[model_providers.atp]
name = "ATP"
base_url = "https://api.atptoken.ai/v1"
env_key = "ATP_API_KEY"
wire_api = "chat"
export ATP_API_KEY="atp-..."
codex

Both tools authenticate with Authorization: Bearer atp-…. The model must be enabled for the key's project, or the Gateway returns 403.

Using the console

Set up your organization

Everything in the console hangs off a four-level hierarchy. You create an organization once, then nest workspaces, projects, and keys inside it.

LevelWhat it holds
OrganizationThe billing and team boundary. Either Personal or Team.
WorkspaceA credit container that groups related projects.
ProjectSets the allowed model list and holds a credit balance.
API keyA scoped credential that inherits its project's models and credits.

On first sign-in, onboarding asks for an organization name (an optional lowercase slug is auto-generated). A Team organization can invite members and assign roles; a Personal organization is single-user and hides the Team page.

Using the console

Workspaces & projects

The Resources page is where you create workspaces and projects and move credits between them.

1

Create a workspace

A workspace groups projects and holds a pool of credits you can allocate downward. Most teams use one workspace per product or environment.

2

Create a project and pick allowed models

Inside a workspace, create a project and choose its allowed models (at least one). Those models — and only those — can be called by every key in the project. Model access is set per project, never per key.

3

Allocate credits

Credits flow down the tree: organization → workspace → project. Allocate a budget to the project so its keys have something to spend. See How credits work for the terminology.

Using the console

Managing API keys

The Create key wizard walks you through naming the key, choosing (or creating) the workspace and project, and optionally seeding starting credits. A key is always scoped to one project and inherits that project's models and credit balance.

The secret is shown only once

Keys start with atp- and are 92 characters long. The full secret is displayed once at creation — copy and store it safely. Afterwards only the prefix is visible.

The API keys page lists every key in the organization across all workspaces and projects. Search by name or prefix, filter by workspace, and revoke a key at any time — revoked keys stop working immediately but stay in the roster for audit.

Using the console

Team & roles

Team organizations can add people and assign them roles at the workspace or project level. There are three roles:

RoleCan do
OwnerFull control. Read-only in the UI and cannot be removed.
AdminManage members, resources, keys, and credit allocation.
MemberRead and use what they have access to.

Invite by email sends an invitation the person must accept; add existing user attaches an account that already exists immediately. Personal organizations have no team and show a note instead of the members panel.

Using the console

Usage & logs

Three places tell you what happened and what it cost:

Usage

Credit summary (Available, Received, Consumed), top models by month, and per-key token totals.

Request logs

A per-request audit trail. Filter by time range, scope, model, status, or request ID; columns show status and input / output tokens.

Activity

Security and admin events — sign-ins, invites, quota changes, and resource updates.

Timestamps render in your local timezone. Token counts are raw totals, not per-million.

Billing & credits

How credits work

Usage is paid for in credits. 1 credit = USD 0.01 (100 credits = USD 1). Pay-as-you-go credits don't expire (committed contract credits may carry an expiry date — see Top up & wallet). Balances are shown to four decimal places; a non-zero amount below that shows as <0.0001.

Credits flow down the hierarchy — organization → workspace → project — and a key spends from its project's balance. Each level reports the same four figures:

TermMeaning
AvailableCredits you can spend or allocate at this level.
ReceivedTotal credits received from the parent level.
AllocatedCredits pushed down to child workspaces or projects.
ConsumedCredits actually spent on API calls (project level).

If a project spends more than it was allocated it is flagged In debt until topped up.

Billing & credits

Pricing

Billing is usage-based, measured on input + output tokens. Each model has its own rate; the exact per-model economics are resolved by the gateway's pricing tables at request time, not by a static table on this page. Which models a key may call is scoped by its project.

There is no monthly fee. See the pricing page for the current model lineup and access tiers.

Billing & credits

Top up & wallet

Your pay-as-you-go (PAYG) wallet is funded through Stripe from the Billing page. The minimum top-up is USD 5, and every tier converts at a flat 100 credits per dollar:

PackagePriceCredits
StarterUSD 5500
StandardUSD 505,000
ProUSD 20020,000
ScaleUSD 1,000100,000

Every top-up is recorded in the Billing history (date, amount, credits added, balance after, status). Top-ups and credits are non-refundable. Credits are shown as a single Wallet balance. Enterprise accounts may also hold committed contract credits (with an expiry date); these are included in that balance and listed on the Billing page.

Personal vs team organizations

Top-ups credit your personal account. In a personal organization that balance is what your keys spend directly. For a team organization, allocate credits to it (Console → Resources) — keys in a team org spend from the org's allocated credits, not from an individual's wallet.

Billing & credits

Tracking spend

The Usage page summarizes credits and tokens for a chosen period, broken down by model and by API key. The credit allocation tree lets you drill from organization down to workspace and project to see Allocated versus Consumed at each level, so you can tell exactly where credits are going before a balance runs low.

OpenAI-compatible
POST/v1/chat/completions

Use this endpoint with any OpenAI SDK client. The request body follows OpenAI's chat completions schema unchanged. The model field must be a value returned by GET /v1/models.

FieldTypeDescription
modelstring · requiredA model id from GET /v1/models.
messagesarray · requiredChat messages, each { role, content }.
max_tokensintegerMax output tokens. Set high enough for reasoning models.
temperaturenumberSampling temperature, 0–2.
streambooleanStream the response as SSE chunks.
toolsarrayTool/function definitions (OpenAI tool schema).

Response

{
  "id": "chatcmpl-...",
  "object": "chat.completion",
  "model": "<model>",
  "choices": [
    {
      "index": 0,
      "message": { "role": "assistant", "content": "..." },
      "finish_reason": "stop"
    }
  ],
  "usage": { "prompt_tokens": 9, "completion_tokens": 12, "total_tokens": 21 }
}
Anthropic-compatible
POST/v1/messages

Anthropic Messages requests are accepted and normalized by the Gateway. The top-level system field must be a string. The array form used by Anthropic's cache_control feature is not yet supported — sending an array returns 400 invalid_request_error. The anthropic-version header is accepted and forwarded unchanged.

FieldTypeDescription
modelstring · requiredA model id from GET /v1/models.
max_tokensinteger · requiredMax output tokens (Anthropic requires this).
messagesarray · requiredConversation turns, each { role, content }.
systemstringSystem prompt. Must be a string, not an array.
temperaturenumberSampling temperature, 0–1.
streambooleanStream as Anthropic SSE events.

Request

curl https://api.atptoken.ai/v1/messages \
  -H "Authorization: Bearer atp-..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "<model from GET /v1/models>",
    "max_tokens": 256,
    "messages": [{"role": "user", "content": "hi"}]
  }'
Gemini-compatible
POST/v1/models/{model}:generateContent

Gemini REST-style generateContent and streamGenerateContent routes are supported under both /v1 and /v1beta (the Google GenAI SDK default). Authenticate with x-goog-api-key — the SDK's default.

Request

curl "https://api.atptoken.ai/v1/models/<model>:generateContent" \
  -H "x-goog-api-key: atp-..." \
  -H "Content-Type: application/json" \
  -d '{
    "contents": [{ "parts": [{ "text": "hi" }] }]
  }'
Files
POST/v1/files

Upload a file to the Gateway and reference it in subsequent chat or messages requests by the returned gw_file_id (format an_<ULID>).

curl https://api.atptoken.ai/v1/files \
  -H "Authorization: Bearer atp-..." \
  -F "file=@./input.pdf"
# → { "gw_file_id": "an_01H...", ... }
POST /v1/files

multipart/form-data upload with a file part. Max 20 MB. Identical bytes are deduped by SHA-256.

GET /v1/files/:id

Returns 302 to a short-lived presigned URL on the object store. Follow the redirect to download.

Streaming · OpenAI format

Server-Sent Events

When you set stream: true on /v1/chat/completions, the Gateway streams the upstream provider response as OpenAI-format SSE chunks. The final chunk contains the usage object; the stream ends with data: [DONE].

Streaming · Anthropic format

Event sequence for /v1/messages

/v1/messages with stream: true emits this event sequence regardless of which upstream provider served the request:

event: message_start
data: {"type":"message_start","message":{...}}

event: content_block_start
data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}

# one per delta:
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"..."}}

event: content_block_stop
data: {"type":"content_block_stop","index":0}

event: message_delta
data: {"type":"message_delta","delta":{"stop_reason":"end_turn"},"usage":{"output_tokens":N}}

event: message_stop
data: {"type":"message_stop"}

stop_reason maps from the provider: stop end_turn, length max_tokens.

Operational behavior

Common responses

All error responses include a request_id — quote it when contacting support. The error envelope follows whichever SDK format you called (OpenAI / Anthropic / Gemini).

400
Bad request — missing field, malformed body, or unsupported feature (e.g. Anthropic system as array).
401
Missing, disabled, expired, or unrecognized API key.
402
Wallet or credit pool exhausted. Top up to resume.
403
Model is not enabled for this project.
429
Rate limit, quota, or provider cooldown. Honor Retry-After if present.
502
Provider connection failed or timed out. Safe to retry.
503
All providers for the model are circuit-open. Retry-After: 60.
5xx
Provider or Gateway error. Check request logs in the console.

200 with empty content

A request can return 200 OK with an empty message — no error, just no text. This is almost always driven by request parameters, not a failure. The most common cause is a max_tokens that is too low for a reasoning model: the budget is spent on internal reasoning before any visible output, so the content comes back empty and finish_reason / stop_reason is length.

Always inspect the response before assuming text exists. Check finish_reason and the usage object: if completion tokens were produced but content is empty, raise max_tokens and re-send. The request is still billed for the tokens it used.

Next: Console setup →
Create an account, set up a project, then issue a project key.
Create account