Advertiser API v1
Your card is a measured connection, not just an ad. Every click, every request — yours to see and pull into your own systems.
1 · Key
Sign in at app/advertiser.html with the e-mail on your card and tap Make an API key. It is shown once. Keep it on your server — never in a web page. A new key turns the old one off.
curl https://aicbct.com/api/advertiser-api?r=card \ -H "Authorization: Bearer aic_…"
2 · Track — clicks
GET /api/advertiser-api?r=clicks&days=30
→ { "clicks": { "total": 412, "last30": 120,
"days": [{ "day": "2026-11-05", "n": 7 }, …],
"bySource": { "card": 80, "qr": 31, "email": 9 },
"byCity": { "chicago": 22, "seoul": 14 } } }
Trackable links (GET ?r=links) — use the qr one for printed QR codes at shows, in brochures or box inserts, so offline reach is counted on its own:
https://aicbct.com/api/ad-go?ad=CO-XXXXXX&src=qr (also src=email, src=card)
Counts only. Nothing about the visitor is stored or passed on. Your site receives utm_source=aicbct, utm_medium=<source>.
3 · Report — your card
GET /api/advertiser-api?r=card
→ { "card": { "id": "CO-XXXXXX", "company": "…", "category": "implants", "line": "…",
"website": "https://…", "cta": "quote", "leads": true, "status": "active", "priceUsd": 299 } }
4 · Lead — requests from dentists
Turn on Requests from dentists and pick a button (Get a quote · Book a demo · Ask for a call). A dentist fills a short form on your card; you get an e-mail, a row in your account, and — if set — a webhook.
GET /api/advertiser-api?r=leads&days=90
→ { "leads": [{ "id": "ld_…", "at": "…", "kind": "quote", "name": "…", "clinic": "…",
"email": "…", "phone": "…", "city": "Chicago", "country": "US", "message": "…" }] }
B2B only. The form asks for no patient details; patient information never leaves AICBCT's consent flow.
Webhook
POST /api/advertiser-api { "r": "webhook", "url": "https://crm.example.com/aicbct" }
→ { "secret": "whsec_…" } (shown once; setting the URL again makes a new secret)
POST /api/advertiser-api { "r": "webhook-test" }
We POST JSON { id, type: "lead.created" | "test", created, adId, data } with the header
AICBCT-Signature: t=1762300000,v1=<hex HMAC-SHA256 of "t.body" with your whsec_ secret>
// Node — check it
const [t, v1] = sig.split(',').map(p => p.split('=')[1]);
const ok = crypto.createHmac('sha256', SECRET).update(t + '.' + rawBody).digest('hex') === v1
&& Math.abs(Date.now() / 1000 - t) < 300;
Public https addresses only. One try, 5-second limit; every lead is also kept in your account and e-mailed.
5 · Card — edit your own
POST /api/advertiser-api
{ "r": "card", "line": "Short implants · next-day ship", "website": "https://…",
"cta": "visit" | "quote" | "demo" | "call", "leads": true }
Errors
| 401 | No or wrong key. |
| 400 | A field is not valid — the message says which. |
| 503 | Not open yet. |
Cards are labelled Sponsored and shown side by side, not ranked. No fee per patient or per treatment — ever. Partner Terms · order@aicbct.com
