Docs
API 1.39
Status
Guides

Bring your own providers

Use your own proxies, language models and captcha solvers: configuration, fallback, billing, health checks and how credentials are kept.

Kaabist buys three things on your behalf, each billed per use: proxies to reach sites from (per megabyte), language models that help heal broken locators and recognise unfamiliar pages (per token), and captcha solvers (per solve). If you already have an account with a vendor, you can register it with Kaabist and your jobs use it instead, and that item disappears from your bill.

#When to use it

Bring your own provider when:

  • you already pay a proxy vendor, or need exits in a network you control (an office address a site has allow-listed, a residential pool you negotiated);
  • your organisation has a contract with a model vendor, or a rule that page content may only be sent to the model you chose;
  • you have a captcha-solving balance you want to use up.

Stay on the platform's providers when you have no such account: they need no configuration, pick a proxy pool per site, and fall back automatically. Bring-your-own (BYO) providers are part of the Developer plan and above, and need a verified payment method (403 plan_required or 403 payment_method_required otherwise).

#Supported vendors

KindVendors
ProxyAny HTTP, HTTPS or SOCKS5 proxy (static, list, gateway), with presets for Bright Data, Oxylabs, Decodo (Smartproxy), IPRoyal and Webshare
LLMOpenAI, Anthropic, Google Gemini, Azure OpenAI, and any OpenAI-compatible server
Captcha2Captcha, CapSolver

#Registering a provider

Every provider is created with POST /v1/byo-providers and an admin key, as { "kind", "name", "config" }. Creating it tests it straight away:

TypeScript
// Credentials are write-only: sealed under your organisation's key, never returned or logged.
const provider = await kaab.byoProviders.create({
  kind: "proxy",
  name: `my-proxy-${Date.now().toString(36)}`,
  config: { type: "static", url: proxyUrl, pool: "datacenter", country: "DE" },
});
console.log(`${provider.id}: ${provider.status} ${JSON.stringify(provider.config_public)}`);

The examples on this page use placeholders: never paste a real credential into a ticket or a chat.

#Proxies

A single endpoint:

{ "type": "static", "url": "http://USER:[email protected]:3128", "pool": "datacenter" }

A list. Each job sticks to one address for its whole run, and jobs spread across the list:

{ "type": "list", "urls": ["http://USER:[email protected]:3128", "http://USER:[email protected]:3128"], "pool": "datacenter" }

A vendor's rotating gateway. With a preset, Kaabist writes the job's country and a per-job session into the credential in that vendor's own format, so each job keeps one exit IP:

{ "type": "gateway", "vendor": "brightdata", "url": "http://brd-customer-ID-zone-ZONE:[email protected]:33335", "pool": "residential", "country": "DE" }
{ "type": "gateway", "vendor": "oxylabs", "url": "http://USER:[email protected]:7777", "pool": "residential" }
{ "type": "gateway", "vendor": "decodo", "url": "http://USER:[email protected]:7000", "pool": "residential" }
{ "type": "gateway", "vendor": "iproyal", "url": "http://USER:[email protected]:12321", "pool": "residential" }

Webshare's proxy list is fetched from its API with your key:

{ "type": "list", "vendor": "webshare", "api_key": "WEBSHARE_API_KEY", "pool": "datacenter" }

A gateway without a preset can still be steered: {country} and {session} in the URL are filled in per job, for example http://acme-{country}-{session}:[email protected]:8000.

Proxy hosts must be public addresses. A proxy on a private network is refused (422 ssrf_blocked).

#Language models

{ "kind": "llm", "name": "openai", "config": { "vendor": "openai", "api_key": "sk-…", "model": "gpt-4.1" } }
{ "kind": "llm", "name": "claude", "config": { "vendor": "anthropic", "api_key": "sk-ant-…", "model": "claude-sonnet-5-5" } }
{ "kind": "llm", "name": "gemini", "config": { "vendor": "gemini", "api_key": "AIza…", "model": "gemini-2.5-flash" } }
{ "kind": "llm", "name": "azure", "config": { "vendor": "azure_openai", "api_key": "…", "base_url": "https://RESOURCE.openai.azure.com", "model": "DEPLOYMENT" } }
{ "kind": "llm", "name": "gateway", "config": { "vendor": "openai_compatible", "api_key": "…", "base_url": "https://llm.example.com/v1", "model": "MODEL" } }

base_url is required for Azure OpenAI and OpenAI-compatible servers. Supported models are listed per vendor. Models marked capable heal locators and classify pages; basic models (smaller, cheaper ones, and any model behind an OpenAI-compatible server until it is listed) are accepted and marked unsupported_for_healing in config_public: they classify pages only. A model never decides anything by itself: every selector it suggests is checked against the page before it becomes a candidate.

#Captcha solvers

{ "kind": "captcha", "name": "solver", "config": { "vendor": "2captcha", "api_key": "…" } }
{ "kind": "captcha", "name": "solver", "config": { "vendor": "capsolver", "api_key": "…" } }

#Using a provider in a job

Name it in the job's (or the program's) options:

{
  "program": "acme-prices",
  "options": {
    "proxy": { "mode": "byo", "byo_id": "byo_…", "fallback": "none" },
    "llm": { "byo_id": "byo_…" },
    "captcha": { "byo_id": "byo_…" }
  }
}

Or set organisation defaults once in the panel (Settings → Providers), and jobs that name none use them: proxy.mode: "byo" without a byo_id uses the default proxy, and every job uses the default model and solver.

A job naming a provider that is failing its health checks is refused with 422 byo_provider_failing; one naming a provider of another kind, or another organisation's, with 422 validation_failed. A schedule whose provider is failing skips that run (byo_unavailable).

#What fallback means

When your proxy cannot be reached:

  • "none" (the default): the job fails with byo_proxy_unreachable. Your traffic never leaves through an exit you did not choose.
  • "platform": the job continues through Kaabist's own proxies, the result carries the warning byo_fallback_used, and that job's proxy traffic is billed at the platform's rate.

#Billing

A BYO provider removes only its own item from the job's bill: a BYO proxy makes the proxy line zero, a BYO model the llm line, a BYO solver the captcha line. Compute is always billed. The breakdown in meta.credits.breakdown shows each line, including the zeroed ones. You pay your vendor directly for what they served.

#Tests and health

POST /v1/byo-providers/{id}/test tests a provider again on demand and answers { ok, latency_ms, detail, egress_ip? }:

  • a proxy is dialled from Kaabist's egress network and fetches an echo page; the answer includes the exit IP it saw (egress_ip);
  • a model is asked to classify a small canned page;
  • a solver reports its balance.
TypeScript
// Probes the proxy from Kaabist's egress network and stores the verdict.
const result = await kaab.byoProviders.test(provider.id);
console.log(`ok=${result.ok} latency=${result.latency_ms} ms: ${result.detail}`);
const checked = await kaab.byoProviders.get(provider.id);
console.log(`${checked.id} is ${checked.status} (checked ${checked.last_health_at})`);

Kaabist repeats the check every hour. One failure makes a provider degraded; jobs still run. Three failures in a row make it failing: jobs naming it are refused, the event byo.unhealthy is sent to your webhooks and your organisation's owners and admins get an e-mail. Two passes in a row make it healthy again (byo.recovered).

When your own model fails (a refused key, an exhausted quota), healing continues without it, and the proposal's evidence says why (byo_llm_auth_failed, byo_llm_quota_exceeded, …). When your own solver refuses its key or runs out of balance, a job with policies.captcha: "solve" fails with byo_captcha_auth_failed or byo_captcha_balance, because nobody but you can fix that.

#How your credentials are kept

  • Credentials are write-only. Kaabist encrypts them with your organisation's key the moment they arrive and never returns them: not in GET, not in errors, not in logs. You can replace them with PATCH; you cannot read them back. A PATCH that changes only, say, the country keeps the stored credentials, and re-tests the provider.
  • The plaintext exists only inside the processes that use it: the egress gateway, and the worker or healer that calls your model or solver.
  • What Kaabist learns about a site through your providers stays with your organisation: it never improves the platform-wide site profile.
  • A provider cannot be deleted while an organisation default or an active schedule still uses it (409 byo_in_use).

#Worked example

Send a job through your own proxy and check what the bill says:

  1. Register the proxy as in the first snippet. The answer is the provider, healthy when its first test passed, with your URL nowhere in it: config_public shows type, pool and country.
  2. Test it. ok is true and egress_ip is your proxy's exit address, not Kaabist's.
  3. Run a job on a product page through it:
    { "url": "https://shop.example.com/p/1", "extract": { "title": "h1" },
      "options": { "max_tier": "http", "proxy": { "mode": "byo", "byo_id": "byo_…", "fallback": "none" } } }
    
  4. The job succeeds, and meta.credits.breakdown.proxy is 0: you paid your vendor for those bytes, not Kaabist.

#Pitfalls

  • fallback: "platform" changes where your traffic exits. Choose it only when finishing the job matters more than the exit; the warning byo_fallback_used tells you when it happened.
  • One shared session per gateway. A gateway without a preset or a {session} placeholder may rotate the exit IP mid-job, which logs a site out. Use a preset, or put {session} in the URL.
  • Basic models do not heal. A provider marked unsupported_for_healing classifies pages but never proposes a locator; pick a capable model if you rely on healing.
  • Failing providers block jobs. After three failed checks, jobs that name the provider are refused and schedules skip their runs. Subscribe to byo.unhealthy and byo.recovered.
  • Deleting a provider in use. Remove it from the organisation defaults and from active schedules first (409 byo_in_use).

#Reference

Was this page helpful?