> ## Documentation Index
> Fetch the complete documentation index at: https://docs.velobase.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Endpoints

> Complete reference for all Velobase API endpoints.

Velobase is an AI gateway first. Point your OpenAI or Anthropic SDK at `https://api.velobase.io/v1` and bill every model call to an end-customer's wallet by sending the `X-Velobase-Customer: <user-id>` header. It is also a billing ledger (freeze, consume, deduct) for work you price yourself.

This page covers the REST surface for managing customers and their wallets, plus the billing primitives. It accepts JSON-encoded request bodies and returns JSON-encoded responses. For the model gateway itself (`POST /v1/chat/completions`, `POST /v1/messages`, `GET /v1/models`, `GET /v1/usage`), see the gateway reference.

Base URL: `https://api.velobase.io`

<Note>
  Customer wallet deposit uses `amount` as integer credits. Other billing
  primitives that price work yourself may expose explicit fiat/credit unit
  fields such as `amount_usd`, `amount_cents`, or `amount_credits`. 1 USD =
  100 cents = 1,000,000 credits.
</Note>

## Model gateway

The gateway is OpenAI- and Anthropic-compatible. Set your SDK's base URL to `https://api.velobase.io/v1`, authenticate with a project key, and name the end-customer to bill with the `X-Velobase-Customer` header. The call is relayed upstream and the real token cost is settled against that customer's wallet.

| Endpoint                    | Description                                             |
| --------------------------- | ------------------------------------------------------- |
| `POST /v1/chat/completions` | OpenAI-compatible chat completions. Supports streaming. |
| `POST /v1/messages`         | Anthropic-compatible messages.                          |
| `GET /v1/models`            | List available models. Authenticated, not billed.       |
| `GET /v1/usage`             | Per-call usage and cost records.                        |

<Note>
  Health check is unauthenticated at `GET /health` (no `/v1` prefix). For a quick authenticated check, call `GET /v1/models`.
</Note>

#### Authentication and routing

Two key types decide which customer is billed:

* `vb_live_` is a project key for server-side use. Pair it with `X-Velobase-Customer: <user-id>` to name the customer to bill.
* `vb_customer_` is a customer-scoped key that already carries its own customer binding, so no header is needed. It supports an `allowedModels` whitelist and `expiresAt`.

Billable endpoints require a resolvable customer (header or key binding) or return 400. Non-billable endpoints like `GET /v1/models` do not.

#### Per-call billing headers

Each billed response includes settlement details:

* `x-velobase-cost-cents`
* `x-velobase-cost-credits`
* `x-velobase-balance-credits`
* `x-velobase-transaction-id`

#### Models

Velobase is model-agnostic. Live models include:

* `deepseek/deepseek-v4-pro` (supports streaming)
* `anthropic/claude-opus-4.5`, `anthropic/claude-opus-4.6`, `anthropic/claude-opus-4.7`, `anthropic/claude-opus-4.8`, `anthropic/claude-sonnet-4.6`, `anthropic/claude-haiku-4.5` (served via Bedrock, non-streaming)

More models are available through additional upstreams. Call `GET /v1/models` for the current list.

#### Example request

<CodeGroup>
  ```python Python theme={null}
  from openai import OpenAI

  client = OpenAI(
      base_url="https://api.velobase.io/v1",
      api_key="vb_live_1234567890abcdef",
  )

  resp = client.chat.completions.create(
      model="deepseek/deepseek-v4-pro",
      messages=[{"role": "user", "content": "Hello!"}],
      extra_headers={"X-Velobase-Customer": "user_987"},
  )
  ```

  ```bash cURL theme={null}
  curl https://api.velobase.io/v1/chat/completions \
    -H "Authorization: Bearer vb_live_1234567890abcdef" \
    -H "X-Velobase-Customer: user_987" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "deepseek/deepseek-v4-pro",
      "messages": [{"role": "user", "content": "Hello!"}]
    }'
  ```
</CodeGroup>

#### SDKs

The Velobase billing SDKs wrap the customer and wallet endpoints below. The gateway itself works with any OpenAI or Anthropic SDK.

<CodeGroup>
  ```bash Python theme={null}
  pip install "velobase-billing>=0.2.2"
  ```

  ```bash JavaScript theme={null}
  npm i @velobaseai/billing@^1.1.2
  ```
</CodeGroup>

You can manage models, customers, keys, and usage in the dashboard under Overview, Models, Customers, Keys, Usage, and Settings.

## Customers

### Get a customer

Retrieve a customer's profile and their wallets. Each wallet reports `total`, `used`, `frozen`, and `available`, plus a per-source breakdown.

**`GET /v1/customers/:customer_id`**

#### Path parameters

<ParamField path="customer_id" type="string" required>
  The unique identifier for this customer in your system.
</ParamField>

#### Response fields

<ResponseField name="id" type="string">
  The customer identifier.
</ResponseField>

<ResponseField name="name" type="string">
  The customer's display name.
</ResponseField>

<ResponseField name="email" type="string">
  The customer's email address.
</ResponseField>

<ResponseField name="metadata" type="object">
  Arbitrary key-value metadata you attached to this customer.
</ResponseField>

<ResponseField name="wallets" type="object">
  A map of wallet name to wallet balance. Each wallet reports its aggregate totals and a per-source breakdown.

  <Expandable title="wallet properties">
    <ResponseField name="total" type="number">
      Total credits in this wallet.
    </ResponseField>

    <ResponseField name="used" type="number">
      Consumed credits in this wallet.
    </ResponseField>

    <ResponseField name="frozen" type="number">
      Credits currently reserved for an in-progress task.
    </ResponseField>

    <ResponseField name="available" type="number">
      Credits immediately available to spend.
    </ResponseField>

    <ResponseField name="sources" type="array">
      Per-source breakdown of this wallet. Each source is one deposit grant with its own validity window.

      <Expandable title="source properties">
        <ResponseField name="source" type="string">
          The source label for this grant.
        </ResponseField>

        <ResponseField name="total" type="number">
          Total credits from this source.
        </ResponseField>

        <ResponseField name="used" type="number">
          Consumed credits from this source.
        </ResponseField>

        <ResponseField name="frozen" type="number">
          Frozen credits from this source.
        </ResponseField>

        <ResponseField name="available" type="number">
          Available credits from this source.
        </ResponseField>

        <ResponseField name="starts_at" type="string | null">
          ISO 8601 datetime. Credits are inactive before this date, or `null` if not set.
        </ResponseField>

        <ResponseField name="expires_at" type="string | null">
          ISO 8601 datetime. Credits expire after this date, or `null` if not set.
        </ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="created_at" type="string">
  ISO 8601 datetime when this customer record was created.
</ResponseField>

#### Example request

```bash theme={null}
curl https://api.velobase.io/v1/customers/user_987 \
  -H "Authorization: Bearer vb_live_1234567890abcdef"
```

#### Example response

```json theme={null}
{
  "id": "user_987",
  "name": "Alice",
  "email": "alice@example.com",
  "metadata": {},
  "wallets": {
    "default": {
      "total": 1500000000,
      "used": 0,
      "frozen": 0,
      "available": 1500000000,
      "sources": [
        {
          "source": "default",
          "total": 1500000000,
          "used": 0,
          "frozen": 0,
          "available": 1500000000,
          "starts_at": null,
          "expires_at": null
        }
      ]
    }
  },
  "created_at": "2026-04-07T12:00:00.000Z"
}
```

<Note>
  Wallet balances are reported in credits. The example above shows 1,500,000,000 credits, which is \$1,500.00 (1 USD = 1,000,000 credits). There is a separate `GET /v1/customers/:customer_id/balance` endpoint that returns an object-shaped summary if you need it.
</Note>

***

## Customer wallets

These endpoints fund and settle a customer's wallet directly. Use them for work you price yourself, such as a fixed credit grant or a one-shot charge. Model calls made through the gateway settle automatically against the wallet, so you do not need these for per-token billing.

### Deposit to a wallet

Add integer credits to a customer's wallet. If the customer does not exist yet, Velobase automatically creates them using the `name` and `email` fields you provide.

**`POST /v1/customers/deposit`**

#### Request parameters

<ParamField body="customer_id" type="string" required>
  The unique identifier for this customer in your system.
</ParamField>

<ParamField body="amount" type="number" required>
  Positive integer credits to deposit.
</ParamField>

<ParamField body="idempotency_key" type="string" required>
  Unique identifier for this deposit to prevent double processing.
</ParamField>

<ParamField body="credit_type" type="string">
  The wallet category. Defaults to `"default"`.
</ParamField>

<ParamField body="starts_at" type="string">
  ISO 8601 datetime. Credits are ignored before this date.
</ParamField>

<ParamField body="expires_at" type="string">
  ISO 8601 datetime. Credits are ignored after this date.
</ParamField>

<ParamField body="name" type="string">
  Customer's display name. Used only when creating a new customer.
</ParamField>

<ParamField body="email" type="string">
  Customer's email address. Used only when creating a new customer.
</ParamField>

<ParamField body="description" type="string">
  Optional note for the ledger.
</ParamField>

#### Response fields

<ResponseField name="customer_id" type="string">
  The customer identifier.
</ResponseField>

<ResponseField name="account_id" type="string">
  The wallet (account) that received the credits.
</ResponseField>

<ResponseField name="credit_type" type="string">
  The wallet category.
</ResponseField>

<ResponseField name="total_amount" type="number">
  Total credits in this wallet after the deposit.
</ResponseField>

<ResponseField name="added_amount" type="number">
  Credits added in this operation. 1 USD = 1,000,000 credits.
</ResponseField>

<ResponseField name="starts_at" type="string | null">
  ISO 8601 credit activation date, if set.
</ResponseField>

<ResponseField name="expires_at" type="string | null">
  ISO 8601 credit expiry date, if set.
</ResponseField>

<ResponseField name="record_id" type="string">
  The unique ledger record ID.
</ResponseField>

<ResponseField name="is_idempotent_replay" type="boolean">
  `true` if this was a duplicate request that returned the original result.
</ResponseField>

#### Example request

```bash theme={null}
curl -X POST https://api.velobase.io/v1/customers/deposit \
  -H "Authorization: Bearer vb_live_1234567890abcdef" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_id": "user_987",
    "amount": 10000000,
    "idempotency_key": "dep_unique_001"
  }'
```

#### Example response

```json theme={null}
{
  "customer_id": "user_987",
  "account_id": "acc_abc123",
  "credit_type": "default",
  "total_amount": 10000000,
  "added_amount": 10000000,
  "starts_at": null,
  "expires_at": null,
  "record_id": "rec_xyz789",
  "is_idempotent_replay": false
}
```

***

## Billing primitives

The freeze, consume, deduct, and unfreeze primitives let you reserve and settle a customer's wallet for work you price yourself, keyed by your own `transaction_id`. Model calls made through the gateway settle automatically and do not need these.

### Direct deduct

Atomically deduct from a customer's available balance in a single step. Use this for immediate, one-shot charges where you do not need to reserve funds first.

**`POST /v1/billing/deduct`**

#### Request parameters

<ParamField body="customer_id" type="string" required>
  The unique identifier for this customer in your system.
</ParamField>

<ParamField body="amount_usd" type="number" required>
  Amount to deduct, in US dollars. You may instead send `amount_cents` or `amount_credits` (1 USD = 100 cents = 1,000,000 credits). A bare `amount` is legacy and is interpreted as cents.
</ParamField>

<ParamField body="transaction_id" type="string" required>
  Unique identifier for this task or job.
</ParamField>

<ParamField body="credit_types" type="string[]">
  Whitelist of wallet categories to deduct from.
</ParamField>

<ParamField body="description" type="string">
  Optional note for the ledger.
</ParamField>

#### Response fields

<ResponseField name="transaction_id" type="string">
  Echo of the request identifier.
</ResponseField>

<ResponseField name="deducted_amount" type="number">
  Total credits deducted.
</ResponseField>

<ResponseField name="deduct_details" type="array">
  Breakdown by wallet. Each item contains `account_id`, `credit_type`, and `amount`.
</ResponseField>

<ResponseField name="deducted_at" type="string">
  ISO 8601 timestamp of the deduction.
</ResponseField>

<ResponseField name="is_idempotent_replay" type="boolean">
  `true` if this was a duplicate request.
</ResponseField>

#### Example request

```bash theme={null}
curl -X POST https://api.velobase.io/v1/billing/deduct \
  -H "Authorization: Bearer vb_live_1234567890abcdef" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_id": "user_987",
    "amount_usd": 2,
    "transaction_id": "task_001"
  }'
```

#### Example response

```json theme={null}
{
  "transaction_id": "task_001",
  "deducted_amount": 2000000,
  "deduct_details": [
    {
      "account_id": "acc_abc123",
      "credit_type": "default",
      "amount": 2000000
    }
  ],
  "deducted_at": "2026-04-08T10:30:00.000Z",
  "is_idempotent_replay": false
}
```

***

### Freeze credits

Reserve a specific amount for an ongoing task. Frozen credits are held exclusively for that task and cannot be spent by any other operation until they are consumed or unfrozen.

**`POST /v1/billing/freeze`**

#### Request parameters

<ParamField body="customer_id" type="string" required>
  The unique identifier for this customer in your system.
</ParamField>

<ParamField body="amount_usd" type="number" required>
  Amount to freeze, in US dollars. You may instead send `amount_cents` or `amount_credits` (1 USD = 100 cents = 1,000,000 credits). A bare `amount` is legacy and is interpreted as cents.
</ParamField>

<ParamField body="transaction_id" type="string" required>
  Unique identifier for this task or job.
</ParamField>

<ParamField body="credit_types" type="string[]">
  Whitelist of wallet categories to freeze from.
</ParamField>

<ParamField body="description" type="string">
  Optional note for the ledger.
</ParamField>

#### Response fields

<ResponseField name="transaction_id" type="string">
  Echo of the request identifier.
</ResponseField>

<ResponseField name="frozen_amount" type="number">
  Total credits frozen.
</ResponseField>

<ResponseField name="freeze_details" type="array">
  Breakdown by wallet. Each item contains `account_id`, `credit_type`, and `amount`.
</ResponseField>

<ResponseField name="is_idempotent_replay" type="boolean">
  `true` if this was a duplicate request.
</ResponseField>

#### Example request

```bash theme={null}
curl -X POST https://api.velobase.io/v1/billing/freeze \
  -H "Authorization: Bearer vb_live_1234567890abcdef" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_id": "user_987",
    "amount_usd": 5,
    "transaction_id": "task_002"
  }'
```

#### Example response

```json theme={null}
{
  "transaction_id": "task_002",
  "frozen_amount": 5000000,
  "freeze_details": [
    {
      "account_id": "acc_abc123",
      "credit_type": "default",
      "amount": 5000000
    }
  ],
  "is_idempotent_replay": false
}
```

***

### Consume frozen credits

Permanently deduct from a previously frozen transaction. You supply the actual amount used, which may be less than what was originally frozen, and Velobase returns any remainder to the customer's available balance.

**`POST /v1/billing/consume`**

#### Request parameters

<ParamField body="transaction_id" type="string" required>
  The `transaction_id` used in the original `freeze` call.
</ParamField>

<ParamField body="actual_amount_usd" type="number" required>
  Amount to actually deduct, in US dollars. You may instead send `actual_amount_cents` or `actual_amount_credits` (1 USD = 100 cents = 1,000,000 credits). A bare `actual_amount` is legacy and is interpreted as cents. Must be less than or equal to the originally frozen amount.
</ParamField>

#### Response fields

<ResponseField name="transaction_id" type="string">
  Echo of the request identifier.
</ResponseField>

<ResponseField name="consumed_amount" type="number">
  Credits permanently deducted from the frozen amount.
</ResponseField>

<ResponseField name="returned_amount" type="number">
  Unused credits returned to the available balance (`frozen - consumed`).
</ResponseField>

<ResponseField name="consume_details" type="array">
  Breakdown by wallet. Each item contains `account_id`, `credit_type`, and `amount`.
</ResponseField>

<ResponseField name="consumed_at" type="string">
  ISO 8601 timestamp of the consumption.
</ResponseField>

<ResponseField name="is_idempotent_replay" type="boolean">
  `true` if this was a duplicate request.
</ResponseField>

#### Example request

```bash theme={null}
curl -X POST https://api.velobase.io/v1/billing/consume \
  -H "Authorization: Bearer vb_live_1234567890abcdef" \
  -H "Content-Type: application/json" \
  -d '{
    "transaction_id": "task_002",
    "actual_amount_usd": 3
  }'
```

#### Example response

```json theme={null}
{
  "transaction_id": "task_002",
  "consumed_amount": 3000000,
  "returned_amount": 2000000,
  "consume_details": [
    {
      "account_id": "acc_abc123",
      "credit_type": "default",
      "amount": 3000000
    }
  ],
  "consumed_at": "2026-04-08T10:35:00.000Z",
  "is_idempotent_replay": false
}
```

***

### Unfreeze credits

Release all unused frozen credits back to the customer's available balance. Use this when a task is canceled or fails and you want to return the reserved credits without consuming any.

**`POST /v1/billing/unfreeze`**

#### Request parameters

<ParamField body="transaction_id" type="string" required>
  The `transaction_id` used in the original `freeze` call.
</ParamField>

#### Response fields

<ResponseField name="transaction_id" type="string">
  Echo of the request identifier.
</ResponseField>

<ResponseField name="unfrozen_amount" type="number">
  Total credits released back to the available balance.
</ResponseField>

<ResponseField name="unfreeze_details" type="array">
  Breakdown by wallet. Each item contains `account_id`, `credit_type`, and `amount`.
</ResponseField>

<ResponseField name="unfrozen_at" type="string">
  ISO 8601 timestamp of the unfreeze.
</ResponseField>

<ResponseField name="is_idempotent_replay" type="boolean">
  `true` if this was a duplicate request.
</ResponseField>

#### Example request

```bash theme={null}
curl -X POST https://api.velobase.io/v1/billing/unfreeze \
  -H "Authorization: Bearer vb_live_1234567890abcdef" \
  -H "Content-Type: application/json" \
  -d '{
    "transaction_id": "task_002"
  }'
```

#### Example response

```json theme={null}
{
  "transaction_id": "task_002",
  "unfrozen_amount": 5000000,
  "unfreeze_details": [
    {
      "account_id": "acc_abc123",
      "credit_type": "default",
      "amount": 5000000
    }
  ],
  "unfrozen_at": "2026-04-08T10:40:00.000Z",
  "is_idempotent_replay": false
}
```
