Skip to content

Credits ​

3 endpoints. Every path below is relative to the API base URL and already includes the /api/v1 prefix — see conventions for authentication, pagination, errors and idempotency.

Endpoint
GET/billing/auto-reloadReturn the organization's auto-reload configuration and its failure history
PUT/billing/auto-reloadEnable or update auto reload with its threshold, reload amount, payment method and monthly caps
POST/billing/credits/purchaseCreate a Stripe PaymentIntent to top up credits and return the client secret for the browser

Endpoints ​

Return the organization's auto-reload configuration and its failure history ​

GET/billing/auto-reload
  • Requires billing.read.
  • data is literally null when auto reload has never been configured, not an empty object
bash
curl -X GET "$CALLAGENT_API_URL/billing/auto-reload" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/billing/auto-reload`, {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
  },
});

if (!response.ok) {
  const { error } = await response.json();
  throw new Error(`${error.type}: ${error.message}`);
}

const { data } = await response.json();
php
<?php

$handle = curl_init(getenv('CALLAGENT_API_URL') . '/billing/auto-reload');

curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
        'Accept: application/json',
    ],
]);

$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);

if ($status >= 400) {
    throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}

$data = $body['data'];
python
import os, requests

response = requests.get(
    f"{os.environ['CALLAGENT_API_URL']}/billing/auto-reload",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Responses

StatusBody
200data-wrapped object

Errors

StatusWhen it happens
403Neither the API key scope nor the session user's permission allows billing.read

Example response, generated from the schema:

json
{
  "data": {
    "enabled": true,
    "threshold_amount": "string",
    "reload_amount": "string",
    "currency": "string",
    "payment_method_id": "01JQ0000000000000000000000",
    "monthly_reload_limit": 25,
    "monthly_reload_cap_amount": "string",
    "cooldown_minutes": 1,
    "consecutive_failures": 1,
    "disabled_reason": "string",
    "last_succeeded_at": "2026-01-01T12:00:00+00:00",
    "last_failed_at": "2026-01-01T12:00:00+00:00"
  }
}

Enable or update auto reload with its threshold, reload amount, payment method and monthly caps ​

PUT/billing/auto-reload
  • Requires billing.write.
  • Setting enabled=true also clears a dunning-triggered disable and resets the consecutive-failure counter

Request body

FieldTypeRequiredNotes
enabledbooleanyes
threshold_amountnumber—
reload_amountnumber—
payment_method_idstring | null—
monthly_reload_limitinteger | null—min 1. max 100
monthly_reload_cap_amountnumber | null—
bash
curl -X PUT "$CALLAGENT_API_URL/billing/auto-reload" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
       "enabled": true,
       "threshold_amount": 1,
       "reload_amount": 1,
       "payment_method_id": "01JQ0000000000000000000000",
       "monthly_reload_limit": 25,
       "monthly_reload_cap_amount": 1
     }'
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/billing/auto-reload`, {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "enabled": true,
    "threshold_amount": 1,
    "reload_amount": 1,
    "payment_method_id": "01JQ0000000000000000000000",
    "monthly_reload_limit": 25,
    "monthly_reload_cap_amount": 1
  }),
});

if (!response.ok) {
  const { error } = await response.json();
  throw new Error(`${error.type}: ${error.message}`);
}

const { data } = await response.json();
php
<?php

$handle = curl_init(getenv('CALLAGENT_API_URL') . '/billing/auto-reload');

curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => 'PUT',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
        'Accept: application/json',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
    'enabled' => true,
    'threshold_amount' => 1,
    'reload_amount' => 1,
    'payment_method_id' => '01JQ0000000000000000000000',
    'monthly_reload_limit' => 25,
    'monthly_reload_cap_amount' => 1,
]),
]);

$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);

if ($status >= 400) {
    throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}

$data = $body['data'];
python
import os, requests

response = requests.put(
    f"{os.environ['CALLAGENT_API_URL']}/billing/auto-reload",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    json={
      "enabled": True,
      "threshold_amount": 1,
      "reload_amount": 1,
      "payment_method_id": "01JQ0000000000000000000000",
      "monthly_reload_limit": 25,
      "monthly_reload_cap_amount": 1
    },
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Responses

StatusBody
200data-wrapped object

Errors

StatusWhen it happens
403Neither the API key scope nor the session user's permission allows billing.write
404The supplied payment_method_id is not a usable card on this organization
422Field validation failed, or the reload amount exceeds the platform maximum

Example response, generated from the schema:

json
{
  "data": {
    "enabled": true,
    "threshold_amount": "string",
    "reload_amount": "string",
    "currency": "string",
    "payment_method_id": "01JQ0000000000000000000000",
    "monthly_reload_limit": 25,
    "monthly_reload_cap_amount": "string",
    "cooldown_minutes": 1,
    "consecutive_failures": 1,
    "disabled_reason": "string",
    "last_succeeded_at": "2026-01-01T12:00:00+00:00",
    "last_failed_at": "2026-01-01T12:00:00+00:00"
  }
}

Create a Stripe PaymentIntent to top up credits and return the client secret for the browser ​

POST/billing/credits/purchase
  • Requires billing.write.
  • Accepts an Idempotency-Key header; replaying a key returns the original result instead of acting twice.
  • Idempotency uses the request-body field idempotency_key, not an Idempotency-Key header. Credits are granted only when the Stripe webhook settles the charge.

Request body

FieldTypeRequiredNotes
amountnumberyes
payment_method_idstring | null—
idempotency_keystring | null—max 191 chars
bash
curl -X POST "$CALLAGENT_API_URL/billing/credits/purchase" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
       "amount": 1,
       "payment_method_id": "01JQ0000000000000000000000"
     }'
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/billing/credits/purchase`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "amount": 1,
    "payment_method_id": "01JQ0000000000000000000000"
  }),
});

if (!response.ok) {
  const { error } = await response.json();
  throw new Error(`${error.type}: ${error.message}`);
}

const { data } = await response.json();
php
<?php

$handle = curl_init(getenv('CALLAGENT_API_URL') . '/billing/credits/purchase');

curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
        'Accept: application/json',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
    'amount' => 1,
    'payment_method_id' => '01JQ0000000000000000000000',
]),
]);

$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);

if ($status >= 400) {
    throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}

$data = $body['data'];
python
import os, requests

response = requests.post(
    f"{os.environ['CALLAGENT_API_URL']}/billing/credits/purchase",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    json={
      "amount": 1,
      "payment_method_id": "01JQ0000000000000000000000"
    },
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Responses

StatusBody
200JSON object

Errors

StatusWhen it happens
402Stripe declined the charge; the body carries failure_message
403Neither the API key scope nor the session user's permission allows billing.write
404The supplied payment_method_id is not a usable card on this organization
422amount is missing or not greater than zero
503Stripe is not configured or unreachable

Example response, generated from the schema:

json
"string"

Documented against the code. Anything not yet implemented is labelled, never described as working.