API, SDKs & AI assistants
Back to section

API integration guide

Use SDKs, authenticate requests, paginate results and handle retries, idempotency and webhooks.

Use this guide for integration workflows. See the generated endpoint reference for exact parameters, permissions and response models.

Current API, SDK, CLI and MCP

Check GET /v1/version and GET /v1/capabilities before using optional workflow features. Strict response validation is enforced.

Use bf for new integrations. bf-api is an actively supported compatibility alias of the same CLI, not a separate lower-level interface. Both are included in the Python SDK package and use the same commands, authentication and version.

The current reference describes 182 customer API operations. SDK/CLI 0.1.17 downloads are available for Python, Node.js, PHP and Go. The Python package includes bf, bf-api and the local bf-api-mcp server. Download Python, Node.js, PHP or Go, and verify the archive against SHA256SUMS.

Environment API origin SDK downloads Hosted MCP
Production https://api.blazingfast.io https://docs.blazingfast.io/sdk https://mcp.blazingfast.io/mcp

Set BF_API_BASE_URL to the origin without /v1. SDKs sign requests using BF_API_KEY and BF_API_SECRET; the copyable endpoint snippets use bearer authentication with BF_API_BEARER. Set its complete issued credential privately. Choose the authentication mode when creating the credential in Settings → API.

Start with discovery:

bf version
bf capabilities
bf regions
bf catalog list nl vps
bf service list

GET /v1/version identifies the deployed API contract. GET /v1/capabilities reports feature availability. Check the required scopes, owned resources and current stock as well; a documented operation does not guarantee that every environment has the same products or provider availability.

Authentication and generated clients

For HMAC/SignedAuth requests, all five headers are required: x-api-key, x-ts, x-nonce, x-content-sha256 and x-signature. The body hash and signature cover the exact transmitted bytes. Refresh the timestamp and nonce for every HTTP attempt while retaining the original idempotency key and payload on write retries.

Generic OpenAPI-generated clients do not automatically implement BlazingFast HMAC signing. SignedAuth's API-key declaration alone cannot compute the signature. Prefer an official SDK, or Bearer authentication with a bearer-mode credential. Implement custom signing only after following the signing algorithm. A signed-mode credential cannot be used as a bearer-mode credential simply by changing headers.

Pagination and page size

Pagination is endpoint-specific. Clients must follow the model documented for each endpoint; there is no API-wide page-based pagination contract.

Model Request Continue with Examples
Page page, limit Increment page until page >= pages or items is empty GET /v1/services, billing lists
Cursor cursor, limit Pass next_cursor unchanged; null means finished GET /v1/api-credentials, audit and webhook-delivery lists
Offset offset, limit Use next_offset; null means finished GET /v1/products, GET /v1/dns/zones?view=summary

limit is the canonical page-size parameter. page_size and pageSize are deprecated compatibility request aliases only where that endpoint explicitly documents them. If multiple size parameters are supplied, their values must match. Defaults and bounds vary by endpoint. Page-based responses retain pageSize for compatibility; do not interpret that response field as a recommendation to use the deprecated request alias.

For services, use GET /v1/services?statuses=active,suspended&type=vps&limit=50&page=1. Ownership, status, type, search, external_id and label filters are applied server-side before pagination and counts. The default is active plus suspended. Historical states require an explicit status selection; this API uses terminated for its terminal lifecycle state rather than adding unsupported cancelled/expired filter values.

group_by=type groups only the current paginated result set. GET /v1/services/grouped returns the complete filtered dashboard inventory without pagination and supports its documented status/type filters. This is a legacy compatibility endpoint with an active-only default; MCP/automation clients should pass status explicitly. use status=suspended or status=all explicitly. It does not provide the paginated endpoint's search or metadata filters.

Service families and product codes

type is the normalized service family for inventory filters. product_code is the specific purchasable family for catalog/deployment selection.

product_code Normalized type
vps vps
dedicated dedicated
tcp-proxy other
waf dns
license other

Discover the exact product_code before purchasing; type=other does not select a product.

MCP/automation should pass lifecycle/type filters explicitly. Prefer /v1/services?statuses=active,suspended; follow all pages. Legacy /v1/services/grouped accepts one status or all: fetch active and suspended separately and merge by ID when excluding history. Filters run before pagination; lifecycle is separate from runtime power.

DNSSEC

Registered-domain DNSSEC is public at GET/POST /v1/domains/{serviceId}/dnssec. Read and action=refresh need domains.read; enable/disable need domains.write, acknowledge=true and a stable Idempotency-Key. Enable supports managed signing or external public DNSKEYs. HTTP 202 is accepted, not completed: poll the same DNSSEC GET and reconcile unconfirmed outcomes. Registrar configuration does not verify parent propagation.

SDK/CLI 0.1.17 includes DNSSEC methods and bf domain dnssec show/check/enable/disable; writes require --confirm and an explicit --request-key. Local MCP has read/refresh tools and an opt-in update tool; hosted MCP has none. See DNSSEC modes, keys, scopes and operation states.

Choose the ordering and payment workflow

Workflow Use when Payment
Separate order and invoice You need invoice review, a mixed cart, or separate payment approval Quote → create an unpaid draft → inspect the invoice → explicitly pay → track provisioning
Atomic deployment You authorize one discovered regional product and payment of the full final order amount from account balance together Quote optionally → POST /v1/deploy/{region}/{productCode}/{variantCode} → payment of the full final order amount from account balance and queued provisioning

The atomic deploy endpoint always attempts payment of the full final order amount from account balance; it never silently creates an unpaid order or uses a card/top-up. Insufficient credit returns HTTP 402 with error.code=insufficient_credit, without a committed new order, invoice or debit. The final tax/setup/add-on-inclusive amount must satisfy max_total. Both billing.order.create and billing.invoice.pay permissions are required.

A separate invoice payment may be partial if wallet funds are insufficient; read its remaining amount. That behavior is different from atomic deploy's all-or-nothing payment. A successful payment does not mean the guest or provider is ready.

Use one stable Idempotency-Key per intended write. Same key and exact request is a retry; a different request with that key is rejected. Separate order and payment requests need separate keys. CLI write keys are optional: an omitted key is generated, saved and printed before dispatch. Preserve it for retries. SDKs never automatically retry writes.

After a timeout or unknown response, inspect the original order, invoice, service or returned operation URL before retrying. Reuse the original key and exact payload; never create a new identity simply because a response was lost. Inspect fullyPaid/paidNow and the invoice status to confirm payment. Poll the operation until succeeded and check service readiness to confirm provisioning; accepted, pending or unknown does not confirm completion. A later provisioning failure must be handled separately from payment; inspect billing state rather than assuming an automatic refund.

Use bf billing order-preview/order-create and bf billing invoice-pay for the separate workflow. Use bf deploy or bf billing deploy for atomic deployment; bf dedicated deploy creates an unpaid order unless its explicit payment option is supplied.

Find the right resource

Resource Typical tasks
Integrations Version, capabilities, account audit events, API credentials and OAuth connections
Billing and deployment Products, regional plans, quotes, order previews, orders, invoices and balance payments
Services Status/type filters, recorded hostnames, service details, billing settings, renewal and termination
VPS Status, recorded credentials, browser console, installed OS, IPs, power, reinstall, snapshots, backups and usage
Dedicated servers Catalog, deployment, browser console, credentials, power, reinstall, rescue and task history
DNS and Website Protection Empty or imported zones, templates, records, proxy routing, protection, SSL and country access
Domains Registrations, contacts, nameservers, lock and privacy
TCP Proxy Backends, ports, traffic and source/country access settings
SSH, Firewall and Storage Public keys, firewall policies and volume operations
Webhooks Signed notifications, delivery history, tests and secret rotation

Use GET /v1/services for the service inventory. By default it includes active and suspended services; select terminated/history statuses explicitly. For suspended VPS and dedicated servers, use GET /v1/services?status=suspended&type=vps,dedicated.

Lists include recorded hostname and type, never passwords. Credential endpoints require separate permissions and private response handling. Console endpoints return a browser URL that still requires sign-in and ownership; they do not return provider VNC tickets.

Deploy and track a service

  1. Discover the region, product, variant, available OS choices and your SSH keys. Use the returned identifiers and codes.
  2. Obtain an optional quote or preview. Neither reserves stock nor purchases the service.
  3. Deploy with the canonical fields: billing_cycle, hostname, os, ssh_key_id, addons, max_total, external_id and labels, as supported by the selected product. Use max_total to cap the price you accept.
  4. Save the response's service IDs, request ID and operation handle. A paid or accepted response can still mean provisioning is in progress.
  5. Poll the returned operation/task status or use supported webhooks, then read the service's runtime status before connecting.

Use each endpoint's snake_case fields. Legacy fields remain compatible; SDKs translate native argument names.

Use snapshots before risky changes and backups for recovery. Poll progress until completion, then verify guest reachability.

Retry keys and uncertain outcomes

See machine-readable purchase and operation recovery for runtime requirements, optional canonical receipts, quote ceilings and lost-response recovery.

Use a stable Idempotency-Key for writes. The same key and exact request identify a retry; a different payload with that key is rejected. Keep the key with your application's order or operation record.

CLI --request-key and its --idempotency-key alias are optional. If omitted, the CLI generates a key once, saves it locally before dispatch and prints it for explicit retries. An explicit key is useful when your management system needs to control the retry identity.

After a timeout or interrupted write, inspect the service, invoice or operation before retrying. Reuse the original key and payload. Generating a new key can create a second action. SDKs do not automatically retry writes; safe read retries follow their documented limits and Retry-After.

Hosted MCP's request key maps to the API's idempotency key. The connection's scopes and policy still apply: read only, write with approval, or full access. Local MCP uses an API key and exposes read-only tools by default; enable mutations explicitly when needed. Hosted MCP does not expose passwords or private keys.

Domain names and free DNS

Enter example.com or www.example.com without a trailing dot. Dotted absolute names are accepted too. Customer-facing fqdn responses now use plain lowercase hostnames:

{"ok":true,"fqdn":"example.com","type":"A","proxied":true,"protection":true}

For DNS record selectors, @ means the zone apex and www means that zone's www record. Raw DNS RRset names, zone names and DNS target values can retain a trailing dot; it marks an absolute DNS name. Preserve that notation when using advanced RRsets, zone files or CNAME/MX/NS target values.

Creating a free DNS zone does not automatically create proxy/WAF configuration. Direct DNS is the default; protection requires an explicit request and an eligible backend or active Website Protection entitlement.

Read the current record and configuration before changing them. Prefer GET /v1/dns/zones/{name}/records/config for a read-only configuration lookup. Use the zone's /records/protection GET/POST endpoints to inspect or toggle mitigation without a hosting service ID. That switch preserves proxy routing, origin IPs, DNS values and TTL; it does not remove the proxy or free a protected-domain slot.

Website Protection and domain migration

The €25/month Website Protection plan includes 10 protected domains. Capacity counts distinct protected DNS zones, including protection transitions that are pending. Additional records under the same zone do not consume a new zone slot. Unprotected free DNS zones do not consume those protected-domain slots.

One protected hostname can use multiple backend servers. Follow the endpoint's backend/record schema and read back the saved routing; supplying a backend array replaces that array. The current release supports IP-based affinity. Automatic origin-health checks and failover are not guaranteed; remove unavailable origins through the API and verify traffic before relying on a migration. Traffic statistics describe WAF/proxy traffic, not authoritative DNS query statistics.

For a domain replacement:

  1. Add the new domain/zone and configure its origin routing.
  2. Enable protection while checking available domain capacity.
  3. Upload your own certificate in advance, or arrange automatic issuance once DNS points to the proxy.
  4. Verify certificate configuration, DNS resolution and an HTTPS request through the proxy.
  5. Switch the website and retain the old domain for redirects while a protected slot remains available.
  6. When the old domain is no longer needed, turn off proxy routing for its protected records or remove its zone through the appropriate endpoint, then check capacity again. Switching mitigation off alone keeps the proxy and does not free a slot.

Old and new protected domains each use a slot. If all 10 are occupied, retire an old protected domain or obtain more capacity before protecting another; the API does not promise a temporary extra slot. DNSSEC delegation must be retired safely before deleting a signed DNS zone.

SSL readiness and validation errors

Automatic certificate issuance requires the domain to point to the proxy. You can pre-configure routing and upload a valid certificate and its matching private key before switching DNS.

Use the documented upload-ssl endpoint and read back with get-ssl. Upload validation checks certificate syntax, hostname coverage, validity dates and the matching private key before provider writes. Invalid inputs return a safe 400 error such as invalid_ssl_cert, invalid_ssl_key, ssl_key_mismatch, invalid_ssl_domain, ssl_cert_expired or ssl_cert_not_yet_valid. Use the actual returned code and message.

Read data.status, data.ready and data.readiness_scope. A scope of certificate_configuration means readiness covers the configured certificate. It does not establish DNS propagation, public browser trust or successful HTTPS on every proxy edge. Verify those separately.

An accepted upload can return pending or unknown when readback is not yet confirmed. Keep the upload's expected_fingerprint256, poll get-ssl, and compare the reported certificate fingerprint before considering it ready. A provider lookup failure is an error, not proof that the certificate is absent. Private key material is never returned in these readiness responses.

Errors, rate limits and audit

Responses carry x-request-id; API errors include the same request ID. SDK errors expose it for support and application logs. You can supply x-client-request-id as your own correlation label; it does not replace an idempotency key.

Inspect HTTP status and the canonical error.code, error.message, error.request_id and error.field_errors. Flat code, message, request_id, field_errors, details and status fields are legacy compatibility fields and may still be returned. New integrations should read the nested envelope:

{
  "ok": false,
  "error": {
    "code": "scope_denied",
    "message": "Required scope is missing",
    "request_id": "00000000-0000-4000-8000-000000000001",
    "field_errors": []
  }
}

Production enforces the published response schemas; treat missing or null optional data according to the endpoint contract.

For 429 responses, follow Retry-After. Rate headers include RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset when authenticated accounting is available. Keep automatic retries bounded and retain a write's original identity.

Use GET /v1/audit/events with the documented filters to review account-owned activity. For support, include the action, time, SDK version, HTTP status, error code and request ID. Never send secrets, private keys or complete authorization headers.

Webhooks and application state

Subscribe only to events supported by the current capabilities and webhook event catalog. Verify signatures against the exact raw request body, acknowledge deliveries promptly and deduplicate by event ID. A delivery retry must not execute the same business operation twice.

Use delivery history and the webhook test endpoint to verify your receiver. Secret rotation returns the new secret once; update the receiver's verification configuration. For completion-sensitive workflows, correlate notifications with the resource or operation and read its current state.

The schema describes public HTTP operations. SDKs handle request signing; MCP tools additionally apply the connection's permissions and policy.

SDK examples

SDK 0.1.17

A single SDK call for each workflow. The configured client handles request signing.

GET

/v1/services

Scope: billing.services.read

Discover your owned service IDs using explicit active+suspended filters. This is one paginated page; follow the endpoint pagination model. Lifecycle status is separate from power state. This does not change any service.

javascript

const result = await client.services_list({ statuses: ["active", "suspended"] });
Install the Node.js SDK

Run in your project directory. Initialize a Node.js project with npm init -y or a Go module with go mod init example.com/my-integration first, if needed. Compare the archive checksum with SHA256SUMS.

bash

curl --fail --location --output bf-sdk-nodejs-0.1.17.tar.gz https://docs.blazingfast.io/sdk/bf-sdk-nodejs-0.1.17.tar.gz
npm install ./bf-sdk-nodejs-0.1.17.tar.gz
Client setup and complete runnable example

Create a signed key in Settings → API and privately configure BF_API_BASE_URL, BF_API_KEY and BF_API_SECRET. Use the API origin without /v1 and unset BF_API_BEARER. Never commit or log credentials.

Node.js 18+ · Save as example.cjs

javascript

const { BfClient, BfApiError } = require('bf-api');

function requiredEnv(name) {
  const value = process.env[name];
  if (!value) throw new Error('Missing environment variable: ' + name);
  return value;
}

async function main() {
  const client = new BfClient({
    baseUrl: requiredEnv('BF_API_BASE_URL'),
    apiKey: requiredEnv('BF_API_KEY'),
    apiSecret: requiredEnv('BF_API_SECRET'),
    verifyTls: true,
  });
  const result = await client.services_list({ statuses: ["active", "suspended"] });
  console.log(JSON.stringify(result, null, 2));
}

main().catch((error) => {
  if (error instanceof BfApiError) {
    console.error(JSON.stringify({
      status: error.status, code: error.code, request_id: error.request_id,
    }));
  } else {
    console.error('Check SDK configuration and required environment variables.');
  }
  process.exitCode = 1;
});

Run locally: node example.cjs

Errors and safe retries