API, MCP server and open data
Three things need no key: the website check, the law dataset and the MCP server. Three take a per-site token from the dashboard: consent, voice receipts and the content register. The machine-readable description is at /openapi.json.
On this page
What you can call
| Need | Call | Key |
|---|---|---|
| Which AI disclosure laws apply to a business | MCP laws_for_business, or the dataset | none |
| What one law says, with sources | MCP get_law, or /datasets/ai-disclosure-laws/<slug>.json | none |
| Does this website run AI chat, and does it say so? | MCP check_website, or POST /api/scan | none |
| Record, check or revoke consent to AI calls | /api/consent, /api/consent/check, /api/consent/revoke | voice token |
| The line an AI call must open with; a receipt per call | GET /api/voice/policy, POST /api/voice/event | voice token or site key |
| Register AI-generated media as it is made | POST /api/ingest/content | content-register token |
| Show the notice on a website | One script tag; see the setup guide | site key |
Buying is self-serve: pricing is public, sign-up is a magic link to an email address, checkout is Stripe, and plans with records start with 14 days free. No sales call, no quote.
Keys and tokens
Each website in an account has its own credentials, so a token can only touch one site's records.
- Site key (12 characters): identifies the website. It is in the notice script tag and may be public. It reads the voice policy and nothing else.
- Voice token (starts with
bni_): from the site's Voice page in the dashboard. Sent asAuthorization: Bearer, as?token=, or asx-vapi-secret. Treat it as a secret; rotate it from the same page. - Content-register token: from the site's Content page. Only allows adding to that site's register.
No endpoint returns personal data about a visitor or a caller. Phone numbers are stored as a fingerprint plus the last four digits; transcripts are read once and dropped.
MCP server
A Model Context Protocol server at https://botnotice.app/mcp (Streamable HTTP, no authentication). Four read-only tools, the same facts as this site:
| Tool | Does |
|---|---|
laws_for_business | Given how a business uses AI (chatbot, voice agent, AI media, hiring…) and where its customers are (states, all U.S., EU, UK), returns the laws in force and coming, each with what to disclose, when, penalties and sources, plus the notice rules that satisfy all of them. |
get_law | One law in full, by slug. |
list_laws | Every tracked law, filterable by jurisdiction, status or kind of AI use; the pending bills too. |
check_website | Reads a public website: chat and voice-AI tools found, whether an AI notice is shown, and which laws that leaves unmet for the business described. |
In Claude, add it from the connectors directory: BotNotice: AI disclosure laws. It is also in the official MCP registry as app.botnotice/mcp. Any other client that takes a URL (ChatGPT, Cursor, VS Code and most others):
{ "mcpServers": { "botnotice": { "url": "https://botnotice.app/mcp" } } }Every answer carries not_legal_advice: true and links to the law's page and sources, so a reader can check the claim rather than take the tool's word for it.
Law dataset
29 laws and the pending bills, as JSON and CSV, under CC BY 4.0. Version 2026-10-07. Fields, licence and citation are on the dataset page.
GET https://botnotice.app/datasets/ai-disclosure-laws.json GET https://botnotice.app/datasets/ai-disclosure-laws.csv GET https://botnotice.app/datasets/ai-disclosure-laws/california-sb-243.json
Website check
The HTML pass of the free scan: which chat and voice-AI tools a site runs and whether an AI disclosure is already shown. Cached 12 hours per host; fresh: true re-reads. The browser pass (opens the chat, reads its first message) runs only on the scan page.
POST https://botnotice.app/api/scan
Content-Type: application/json
{ "url": "https://example.com" }
→ { "ok": true, "chatWidgets": [{ "name": "Intercom", "evidence": "…" }], "voiceAgents": [], "disclosureFound": false, "aiSignals": [], "pagesChecked": 3 }Consent for AI calls
Three calls, all with the voice token. Record consent when it is given; check right before dialing and dial only when allowed is true; revoke when someone says stop. The check is written to the record, so the record shows it happened before the call.
POST https://botnotice.app/api/consent
Authorization: Bearer bni_…
{ "phone": "+15551234567", "scope": "marketing", "method": "web_form", "wording": "I agree to receive AI-assisted calls from Acme.", "source": "https://acme.com/quote" }
→ 201 { "ok": true, "consent_id": "…", "last4": "4567", "scope": "marketing", "consented_at": "…" }
POST https://botnotice.app/api/consent/check
Authorization: Bearer bni_…
{ "phone": "+15551234567", "scope": "marketing", "call_ref": "call_8831" }
→ { "allowed": true, "reason": "consent_on_file", "disclosure": "Hi, this is Acme's AI assistant…", "policyVersion": 4 }
POST https://botnotice.app/api/consent/revoke
Authorization: Bearer bni_…
{ "phone": "+15551234567", "method": "texted STOP" }
→ { "ok": true, "revoked": 1 }reason is one of consent_on_file, no_consent, revoked, wrong_scope (agreed to informational calls only), invalid_number.
Voice: opening line and receipts
GET /api/voice/policy returns the line the call must open with, from the site's law determination, in the site's language. The site key alone can read it (?k=), since it is spoken to every caller. POST /api/voice/event is the webhook for the call itself: started, disclosed, handed to a person, ended. Retell and Vapi webhook bodies are understood as sent.
GET https://botnotice.app/api/voice/policy?k=<site key>
→ { "business": "Acme", "language": "en", "disclosure": "…", "timing": "start", "repeatEveryHours": null, "askForHuman": true, "laws": [ … ], "policyVersion": 4 }
POST https://botnotice.app/api/voice/event?token=bni_…
{ "call_id": "call_8831", "event": "started" }
{ "call_id": "call_8831", "event": "ended", "transcript": "…" } ← read once for the disclosure, not storedContent register
Send media as it is created or uploaded, before a CMS or CDN strips its metadata. A file is fetched and its provenance read (Content Credentials, IPTC digital source type, generator metadata); a page has every media file on it inspected. force: true registers on the sender's word, for files straight out of a creation tool.
POST https://botnotice.app/api/ingest/content
Authorization: Bearer <content-register token>
{ "url": "https://acme.com/img/hero.png", "page": "https://acme.com/", "force": true, "tool": "Midjourney" }
→ { "ok": true, "results": [{ "url": "…", "kind": "media", "verdict": "declared", "registered": 1, "item": { "id": "…", "labeled": false } }] }Limits and conduct
- Scan: 10 per minute per address. Consent and voice: 600 per minute per address and 3,000 per minute per site. Content: 20 urls per call.
- Public endpoints answer any origin (CORS
*). Tokens never belong in browser code. - Changes are additive. A field is never renamed or removed without a new path. The dataset version is its newest
last_verifieddate. - Status and incidents: support page. Questions: support@botnotice.app.
- Nothing here is legal advice. Each law record links its primary sources so the claim can be checked.
