Skip to main content
Search...C
Insertion API

Authentication

The Public Insertion API accepts two auth paths. HMAC-SHA256 is preferred because the secret never leaves your server and replays are bounded by a ±5-minute timestamp window. Bearer tokens are accepted as a fallback for simple integrations and one-off scripts.

Overview

Every API key is created with an associated public key (used as a key id) and a secret. The secret is shown exactly once at creation time and stored encrypted (AES-256-GCM) at rest. AdBuy never displays the full secret again — only the last four characters. Rotate keys by creating a new one and revoking the old one.

HMAC-SHA256 Signing (Preferred)

Compute HMAC_SHA256(secret, timestamp + "." + rawBody) and send the result as three headers. The server recomputes the signature, rejects timestamps outside a ±5-minute window, and rejects mismatched signatures with 401 invalid_signature.

NameTypeDescription
X-AdBuy-Public-KeyrequiredstringThe public key id (pk_live_<random>_<last4>).
X-AdBuy-TimestamprequiredintegerUnix seconds when the request was signed. Must be within ±5 minutes of server time.
X-AdBuy-SignaturerequiredhexLowercase hex HMAC-SHA256 of (timestamp + "." + rawBody) keyed by the secret.
Node.js (crypto)
import crypto from "node:crypto";

const publicKey = "pk_live_abcd1234_xxxx";
const secret    = "<your secret>";
const body      = JSON.stringify({
  campaign_id: 123,
  external_lead_id: "f6b1d3c0-1234-4abc-9def-0123456789ab",
  phone: "+15551234567",
});
const timestamp = Math.floor(Date.now() / 1000).toString();
const signature = crypto
  .createHmac("sha256", secret)
  .update(timestamp + "." + body)
  .digest("hex");

await fetch("https://api.adbuy.ai/api/v1/insertion/leads", {
  method: "POST",
  headers: {
    "Content-Type":        "application/json",
    "X-AdBuy-Public-Key":  publicKey,
    "X-AdBuy-Timestamp":   timestamp,
    "X-AdBuy-Signature":   signature,
  },
  body,
});
Python (hmac)
import hmac, hashlib, json, time, requests

public_key = "pk_live_abcd1234_xxxx"
secret     = b"<your secret>"
body       = json.dumps({
  "campaign_id": 123,
  "external_lead_id": "f6b1d3c0-1234-4abc-9def-0123456789ab",
  "phone": "+15551234567",
}, separators=(",", ":"))
timestamp  = str(int(time.time()))
signature  = hmac.new(
  secret,
  (timestamp + "." + body).encode("utf-8"),
  hashlib.sha256,
).hexdigest()

requests.post(
  "https://api.adbuy.ai/api/v1/insertion/leads",
  data=body,
  headers={
    "Content-Type":        "application/json",
    "X-AdBuy-Public-Key":  public_key,
    "X-AdBuy-Timestamp":   timestamp,
    "X-AdBuy-Signature":   signature,
  },
)

Bearer Token (Fallback)

For simple integrations, send the secret directly as a Bearer token. This path is fully supported but offers no replay protection — anyone who captures the token can replay any request indefinitely until the key is rotated. Use HMAC for production.

HTTP
Authorization: Bearer sk_live_<secret>

Scopes

Each API key is provisioned with one or more scopes. Insufficient scope returns 403 scope_required:<scope>.

NameTypeDescription
leads:writescopeRequired for POST and PATCH on /api/v1/insertion/leads.
leads:readscopeRequired for GET on /api/v1/insertion/leads and /api/v1/insertion/leads/:id.

Key Management

Manage your API keys in the dashboard under Settings → API Keys. Best practices:

  • Store the secret in a secrets manager (Vault, AWS Secrets Manager, env vars) — never in source control.
  • Rotate keys quarterly or after any suspected exposure. Create the new key first, deploy it, then revoke the old one.
  • Use the minimum scope needed for the integration. A read-only dashboard does not need leads:write.
  • Each integration (CRM, partner pipeline, marketing automation) should have its own key for audit trail isolation.