Detect regulatory changes and map them to obligations, policies, controls, products and evidence requirements.
Production API: https://controlgraph-api.com
Get a free API key · Documentation · Pricing · Status
Free tier: 50 mapped changes/month. No card required. Paid plans from $499/month.
Request a key. The token arrives by email; exchange it for the key, which is shown once.
curl -X POST https://controlgraph-api.com/v1/keys \
-H 'content-type: application/json' \
-d '{"email": "you@example.com"}'Then call the API:
curl -X POST https://controlgraph-api.com/v1/changes \
-H "Authorization: Bearer $KEY" \
-H 'content-type: application/json' \
-d '{"controls":[
{"controlId":"CTL-014","name":"Disclosure template review",
"owner":"Payments Compliance","status":"implemented",
"tags":["payments","disclosure"],"lastTestedAt":"2026-07-01",
"evidence":[{"kind":"policy_document","collectedAt":"2026-07-02"},
{"kind":"notification_record","collectedAt":"2026-07-14"}]}],
"change":{
"changeId":"REG-2026-0117","citation":"12 CFR 1026.19(e)",
"title":"Revised cost-of-credit disclosures","jurisdiction":"US",
"changeType":"amendment","publishedAt":"2026-03-02",
"effectiveAt":"2026-09-01","transitionEndsAt":"2026-12-01",
"obligations":[
{"obligationId":"OB-1","type":"disclosure",
"text":"Provide the revised disclosure within three business days.",
"appliesTo":["payments","disclosure"],"enforcement":"penalty"}]}}\'Every endpoint below has a runnable playground on the documentation page.
| Endpoint | Auth | Description |
|---|---|---|
GET /health |
public | Liveness and deployed version |
GET / |
public | Service index — endpoints, auth and error format |
POST /v1/changes |
API key | Map regulatory changes onto your obligations, controls, evidence and deadlines |
POST /v1/demo/map |
public | Public demo — map one change with no API key |
GET /v1/obligation-types |
public | The code catalogue: obligation types, evidence kinds, findings and the priority weights |
POST /v1/checkout |
public | Start a hosted Square checkout for a paid tier |
POST /v1/keys |
public | Request a free sandbox API key (sends a verification email) |
GET /v1/keys |
API key | List your API keys for this API |
POST /v1/keys/claim |
public | Exchange an emailed claim token for the API key |
POST /v1/keys/{id}/revoke |
API key | Revoke one of your API keys |
POST /v1/keys/{id}/rotate |
API key | Replace one of your API keys with a new secret |
GET /v1/usage |
API key | Your consumption and remaining allowance for this period |
GET /v1/subscription |
API key | Your current plan, billing window and available changes (dashboard session required) |
POST /v1/subscription/plan |
API key | Upgrade or downgrade to another plan (dashboard session required) |
POST /v1/subscription/cancel |
API key | Cancel this plan and end metered access (dashboard session required) |
GET /v1/invoices |
API key | Every invoice issued against this account, newest first (dashboard session required) |
GET /v1/payments |
API key | Every payment attempted against this account and how it went (dashboard session required) |
The full machine-readable contract is openapi.json, generated
from the deployed route table rather than maintained by hand. A
Postman collection is included.
Python — sdk/python
from regulation_control import RegulationControl
client = RegulationControl() # reads REGULATION_CONTROL_API_KEY
res = client.map_change(
controls=[
{"controlId": "CTL-014", "name": "Disclosure template review",
"owner": "Payments Compliance", "status": "implemented",
"tags": ["payments", "disclosure"], "lastTestedAt": "2026-07-01",
"evidence": [{"kind": "policy_document", "collectedAt": "2026-07-02"},
{"kind": "notification_record", "collectedAt": "2026-07-14"}]},
],
change={
"changeId": "REG-2026-0117",
"citation": "12 CFR 1026.19(e)",
"title": "Revised cost-of-credit disclosures",
"jurisdiction": "US",
"changeType": "amendment",
"publishedAt": "2026-03-02",
"effectiveAt": "2026-09-01",
"transitionEndsAt": "2026-12-01",
"obligations": [
{"obligationId": "OB-1", "type": "disclosure",
"text": "Provide the revised disclosure within three business days.",
"appliesTo": ["payments", "disclosure"], "enforcement": "penalty"},
],
},
)
mapped = res["changes"][0]
print(mapped["summary"]) # covered / weak / gaps, and the earliest deadline
# The gaps are the work nobody has started.
for ob in mapped["obligations"]:
if ob["coverage"] == "gap":
open_ticket(ob["obligationId"], ob["text"], ob["complianceDate"])
# Every score is reproducible arithmetic. Print the derivation next to it.
top = mapped["obligations"][0]
print(top["priority"]["score"], top["priority"]["band"])
for line in top["priority"]["derivation"]:
print(" ", line)TypeScript — sdk/typescript
import { RegulationControl } from './regulation-control.js'
const client = new RegulationControl() // reads REGULATION_CONTROL_API_KEY
const { changes } = await client.map({
controls: [
{ controlId: 'CTL-014', name: 'Disclosure template review',
owner: 'Payments Compliance', status: 'implemented',
tags: ['payments', 'disclosure'], lastTestedAt: '2026-07-01',
evidence: [{ kind: 'policy_document', collectedAt: '2026-07-02' },
{ kind: 'notification_record', collectedAt: '2026-07-14' }] },
],
change: {
changeId: 'REG-2026-0117',
citation: '12 CFR 1026.19(e)',
title: 'Revised cost-of-credit disclosures',
jurisdiction: 'US',
changeType: 'amendment',
publishedAt: '2026-03-02',
effectiveAt: '2026-09-01',
transitionEndsAt: '2026-12-01',
obligations: [
{ obligationId: 'OB-1', type: 'disclosure',
text: 'Provide the revised disclosure within three business days.',
appliesTo: ['payments', 'disclosure'], enforcement: 'penalty' },
],
},
})
const mapped = changes[0]
console.log(mapped.summary) // covered / weak / gaps, and the earliest deadline
// The gaps are the work nobody has started.
for (const ob of mapped.obligations) {
if (ob.coverage === 'gap') openTicket(ob.obligationId, ob.text, ob.complianceDate)
}
// Every score is reproducible arithmetic. Print the derivation next to it.
const top = mapped.obligations[0]!
console.log(top.priority.score, top.priority.band, top.priority.derivation)Every failure returns the same shape. Branch on code, which is a stable enum;
message is for humans and may change.
{"error": {"code": "invalid_api_key", "message": "...", "requestId": "0f3c8b12-…"}}requestId appears on every response and in the x-request-id header. Quote it
in any support request.
Open an issue in this repository, or see the contact route at https://controlgraph-api.com/docs.

