Get started

Authentication

Every request to the Baynoy API must carry an Authorization: Bearer sk_… header. Optionally, you can pin requests to a list of source IPs, sign the body with HMAC-SHA256 for tamper evidence, and lock to a specific API version.

Response envelope

Every API response wraps its payload in an envelope. Branch on the top-levelok boolean before consuming the body:

{
  "ok": true,
  "data": { /* endpoint-specific payload */ }
}

// or on failure:
{
  "ok": false,
  "error": { "code": "...", "message": "...", "details": { /* optional */ } }
}

Every response uses this envelope, so read thedata field for the result and branch onok (or inspecterror) to handle failures. There is no SDK to install — call the REST endpoints directly with any HTTP client.

Secret keys

Generate keys from /dashboard/developers. There are two modes:

  • sk_test_… — sandbox. No real charges, free limits, available immediately.
  • sk_live_…— production. Requires Tier 1 KYC. Charges hit your customers' cards for real money.

A resource is locked to the mode of the key that created it — a link, invoice or price created with sk_test_… always charges as a test, even on an approved live account. So you can build and test an integration in parallel with your live traffic, no mode switch required.

The plain secret is shown once on creation; only its SHA256 hash is stored. You also get a publishable key (pk_test_… / pk_live_…) that's safe to embed in client code.

curl https://baynoy.com/api/v1/balance \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxx"

Scopes

Each key declares a permission list at creation. The wildcard "*" grants every scope; otherwise pick a subset:

payments:readpayments:writecustomers:readcustomers:writeproducts:readproducts:writeinvoices:readinvoices:writerefunds:readrefunds:writepayment_links:readpayment_links:writesubscriptions:readsubscriptions:writepayouts:readbalance:readevents:read

Requests lacking the scope required by an endpoint return 403 insufficient_scope with the required scope echoed in the error body.

IP allowlist

Lock a key to a list of source IPs or CIDR blocks. Empty allowlist means any IP is allowed (handy for local dev / mobile). Populated means strict — non-matching IPs return 403 ip_not_allowed.

203.0.113.42
198.51.100.0/24
192.0.2.7

IPv4 supports full CIDR. IPv6 entries are exact-string match only.

HMAC request signing

For high-value integrations, sign each request with aBaynoy-Signature header alongside your Bearer call. Every key has its own dedicated signing secret (bnsig_…), shown once at key creation and independent of the secret key itself — so a leaked Bearer key alone cannot forge a signature. Compute:

signature = HMAC_SHA256(signing_secret, "<unix_ms>." + raw_body)
Baynoy-Signature: t=<unix_ms>,v1=<hex_signature>

The server recomputes and constant-time compares. Rules:

  • Timestamps outside ±5 min reject (stale_timestamp / future_timestamp).
  • Each signature is accepted once inside its window — a replay returns 409 signature_replayed.
  • A present-but-invalid signature returns 401 signature_invalid.
  • Signing is optional by default. Turn on requireSignature for a key to make it mandatory — unsigned requests then return 401 signature_required. Recommended for keys that move money.

Same t=…,v1=… format as our outbound webhook signing, so you only learn one pattern.

Legacy keys created before signing secrets shipped fall back to using the SHA256 of the secret key — rotate to a new key to get a dedicated bnsig_… secret.

API version

Pin a specific date-stamped version via the Baynoy-Version header. The server resolves the version on every Bearer call (validation, deprecation warnings) and echoesBaynoy-Version back on every Bearer response across every /v1/* endpoint. POST writes additionally honour Idempotency-Key for 24h retry safety.

curl https://baynoy.com/api/v1/balance \
  -H "Authorization: Bearer sk_test_…" \
  -H "Baynoy-Version: 2026-05-27"

The current stable version is 2026-05-27. Every Bearer response echoes the resolved Baynoy-Versionback; if you send a version we no longer support, the response also carries a baynoy-version-unsupported: yes warning header so you can detect drift in CI.