Bitcall logoBitcall API

Quick Start

Get an API key and make your first authenticated request.

This guide takes you from nothing to a working request against the gateway.

Get an API key

Keys are minted by an admin through the key‑management API. Ask your Bitcall admin (or, if you are one, see Key Management) for a key scoped to what you need.

You will receive two values:

ValueExampleNotes
Key idak_test_1a2b…Sent on every request as x-key-id.
Secret9f83… (128 hex chars)Sent on every request as x-api-secret. Shown once — store it securely.

The secret is displayed only at creation (and rotation). It is never retrievable again. If you lose it, rotate the key.

Know the base URL

Send every request to the Bitcall gateway:

https://api.khalil.chatup.ch

All product endpoints live under /v1/*. The examples below use this URL; if you are running a gateway locally, substitute its address.

Make your first request

Send both headers. Nothing else is required — a read‑only catalog endpoint is the cheapest way to confirm the key works:

curl 'https://api.khalil.chatup.ch/v1/otp/countries' \
  --header 'x-key-id: ak_test_1a2b…' \
  --header 'x-api-secret: 9f83…'

A valid key returns 200 and the list of countries. An invalid or expired one returns 401 with error.code set to INVALID_API_KEY — the gateway never says which part was wrong.

In code it is an ordinary request — no wrapper, no crypto:

first-request.mjs
const BASE_URL = 'https://api.khalil.chatup.ch';

const res = await fetch(`${BASE_URL}/v1/otp/countries`, {
  headers: {
    'x-key-id': process.env.KEY_ID,
    'x-api-secret': process.env.SECRET,
  },
});

console.log(res.status, await res.json());
KEY_ID=ak_test_... SECRET=... node first-request.mjs

Call a product

The same two headers work on any endpoint your key is scoped for. A POST adds only a body and its content type:

curl -X POST 'https://api.khalil.chatup.ch/v1/otp/request' \
  --header 'x-key-id: ak_test_1a2b…' \
  --header 'x-api-secret: 9f83…' \
  --header 'Content-Type: application/json' \
  --data '{"service_id":"SP-RU-telegram"}'

If the key is not permitted to make this call, the gateway returns 401 with error.code set to INVALID_API_KEY — the same answer as a wrong secret, so check both.

Optional: a small helper

Since the credentials are the same on every call, most integrations wrap them once. The product guides use an api() helper of this shape:

api.mjs
const BASE_URL = process.env.BITCALL_BASE_URL ?? 'https://api.khalil.chatup.ch';

export async function api(method, path, { query, body } = {}) {
  const url = new URL(BASE_URL + path);
  for (const [k, v] of Object.entries(query ?? {})) {
    if (v !== undefined) url.searchParams.append(k, v);
  }

  const res = await fetch(url, {
    method,
    headers: {
      'x-key-id': process.env.KEY_ID,
      'x-api-secret': process.env.SECRET,
      ...(body ? { 'Content-Type': 'application/json' } : {}),
    },
    body: body ? JSON.stringify(body) : undefined,
  });

  if (!res.ok) throw new Error(`${res.status} ${(await res.json()).error}`);
  return res.json();
}

Next steps

On this page