CP·CP LEDGER
Documentation

Quickstart

Make a first chat completion against the gateway and read what comes back.

The gateway speaks the OpenAI chat-completions dialect over HTTP. If you already have code that talks to an OpenAI-compatible endpoint, the base URL and the key are the only two things that change.

Every sample on this page was run against a live deployment before it was published, and the responses below are the ones that came back.

Before you start

You need two things.

A base URL. It is https://api.impossiblecarrot.cc/api/v1, written out in full in every sample on this site, so there is nothing for you to set.

That is a different hostname from the site you are reading this on, and deliberately so. impossiblecarrot.cc is where your browser holds its login cookie; api.impossiblecarrot.cc is a bearer-token surface that holds no cookies at all. Keeping the two apart is why https://impossiblecarrot.cc/api/v1 does not route and is not going to — an API credential and a browser session never travel to the same origin.

An API key. Inference keys start with sk-or-v1-. Sign in and create one on the Account page — the plaintext is shown once, when it is created, and never again. See Authentication for what the two key classes are allowed to do.

Keep the key in the environment rather than in the command, so it does not end up in your shell history:

BASH
export CP_API_KEY="sk-or-v1-..."

The key is the only thing the samples read from your environment; on every code sample on this site it is the line highlighted in red.

Find a model to call

Model ids are author/slug. The catalogue is public — no key is needed to read it — so the shortest way to get a valid id is to ask for one:

BASH
curl -s "https://api.impossiblecarrot.cc/api/v1/models" | head -c 200
JSON
{"data":[{"id":"impCC/DeepSeek-V4-Flash-0731","canonical_slug":"impCC/DeepSeek-V4-Flash-0731","name":"ImpCC: DeepSeek V4 Flash 0731 (abliterated)","created":1786677579,"description":"An abliterated (d

Read the id rather than copying one out of a document — including this one. The id above replaced a different one while these pages were being written, which is the most direct argument for the advice. This deployment serves exactly one routable model today; see Models and providers for that in full.

Your first request

BASH
curl -s "https://api.impossiblecarrot.cc/api/v1/chat/completions" \
  -H "Authorization: Bearer $CP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "impCC/DeepSeek-V4-Flash-0731",
    "messages": [
      { "role": "user", "content": "Reply with exactly: hello from the gateway" }
    ],
    "max_tokens": 24
  }'

That request returned 200 and this body:

JSON
{
  "id": "gen-1786757875-5np6jh6ix9nh6n0h",
  "object": "chat.completion",
  "created": 1786757875,
  "model": "impCC/DeepSeek-V4-Flash-0731",
  "provider": "Stealth",
  "choices": [
    {
      "index": 0,
      "finish_reason": "stop",
      "native_finish_reason": "stop",
      "message": {
        "role": "assistant",
        "content": "hello from the gateway",
        "refusal": null,
        "annotations": null,
        "function_call": null,
        "reasoning": null
      },
      "logprobs": null
    }
  ],
  "system_fingerprint": "vllm-0.0.0-pp4-bd4126a7",
  "usage": { "prompt_tokens": 12, "completion_tokens": 5, "total_tokens": 17, "is_byok": false },
  "service_tier": null
}

Read the response

choices[0].message.content is the answer. The rest of the envelope is what makes a generation accountable after the fact:

  • id — the generation id, prefixed gen-. Quote it in a bug report; it is also the key for GET /generation, which reports what the call cost.
  • model — the id that was actually served, which is worth checking against the id you asked for.
  • provider — the display name of the endpoint that answered. On this deployment it reads Stealth: the field is constrained to a fixed set of upstream provider names, our own endpoint has to borrow one of them, and the routing identity that actually selected it is impcc. It is a placeholder standing in for a name the field cannot yet express, not the name of a third party who served your request.
  • usage — prompt, completion and total tokens. total_tokens is what the charge is computed from; see Credits and usage.
  • finish_reasonstop means the model stopped on its own. native_finish_reason carries the provider's own word for the same event, unmapped.

Three response headers carry the same identifiers, so a client can correlate a request even when it never gets to parse a body:

TEXT
request-id: req-3p
x-generation-id: gen-1786757875-5np6jh6ix9nh6n0h
x-provider-name: Stealth

x-generation-id is set before anything can fail, so a generation that produced no tokens at all still has an id you can quote.

When it does not work

Two failures account for most first attempts, and both were run to produce the bodies below.

No credential at all:

JSON
{"error":{"code":401,"message":"Missing Authentication header","metadata":{"error_type":"authentication"}}}

A model id that the catalogue does not hold:

JSON
{"error":{"code":404,"message":"No endpoints found for nonexistent/model.","metadata":{"requested":"nonexistent/model","resolved":"nonexistent/model","reason":"model_not_in_catalogue","error_type":"not_found"}}}

error.code always repeats the HTTP status. Errors lists every status this API returns and what each one means.

Where to go next