Convert contracts and order forms into machine-readable entitlements, obligations, renewals, usage limits and commercial commitments.
Production API: https://contractentitlement-api.com
Get a free API key · Documentation · Pricing · Status
Free tier: 25 contracts/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://contractentitlement-api.com/v1/keys \
-H 'content-type: application/json' \
-d '{"email": "you@example.com"}'Then call the API:
curl -X POST https://contractentitlement-api.com/v1/contracts \
-H "Authorization: Bearer $KEY" \
-H 'content-type: application/json' \
-d '{"contract":{
"contractId":"ORD-2026-0041","customer":"Acme Corp",
"supplier":"Northwind Software","currency":"USD",
"startsAt":"2026-01-01","endsAt":"2026-12-31",
"lineItems":[{"sku":"platform.enterprise","quantity":250,
"unitPriceMinor":4000,"frequency":"monthly"}],
"renewal":{"autoRenew":true,"noticeDays":90,
"termMonths":12,"upliftCapPct":5}}}'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/contracts |
API key | Normalize contracts into entitlements, obligations and schedules |
POST /v1/entitlements/check |
API key | Ask whether a customer is entitled to a SKU, right now |
POST /v1/demo/normalize |
public | Public demo — normalize one contract without a key |
GET /v1/obligation-types |
public | Every obligation kind and reason code the engine emits |
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 contract_entitlement import ContractEntitlement
client = ContractEntitlement() # reads CONTRACT_ENTITLEMENT_API_KEY
res = client.normalize({
"contractId": "ORD-2026-0041",
"customer": "Acme Corp",
"supplier": "Northwind Software",
"currency": "USD",
"startsAt": "2026-01-01",
"endsAt": "2026-12-31",
"lineItems": [
{"sku": "platform.enterprise", "quantity": 250,
"unitPriceMinor": 4_000, "frequency": "monthly"},
],
"renewal": {"autoRenew": True, "noticeDays": 90,
"termMonths": 12, "upliftCapPct": 5},
})
contract = res["contracts"][0]
# The date that actually costs money is not the term end.
notice = next(o for o in contract["obligations"] if o["kind"] == "renewal_notice")
print(notice["dueAt"], notice["status"], notice["description"])
for o in contract["obligations"]:
if o["status"] in ("due_soon", "passed"):
alert(o)TypeScript — sdk/typescript
import { ContractEntitlement } from './contract-entitlement.js'
const client = new ContractEntitlement() // reads CONTRACT_ENTITLEMENT_API_KEY
const { contracts } = await client.normalize({
contractId: 'ORD-2026-0041',
customer: 'Acme Corp',
supplier: 'Northwind Software',
currency: 'USD',
startsAt: '2026-01-01',
endsAt: '2026-12-31',
lineItems: [
{ sku: 'platform.enterprise', quantity: 250,
unitPriceMinor: 4_000, frequency: 'monthly' },
],
renewal: { autoRenew: true, noticeDays: 90,
termMonths: 12, upliftCapPct: 5 },
})
const contract = contracts[0]
// The date that actually costs money is not the term end.
const notice = contract.obligations.find((o) => o.kind === 'renewal_notice')!
console.log(notice.dueAt, notice.status, notice.description)
for (const o of contract.obligations) {
if (o.status === 'due_soon' || o.status === 'passed') alert(o)
}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://contractentitlement-api.com/docs.

