Skip to content
Contract Entitlement
CONTRACT & ENTITLEMENT API

The date that costs you money is not the date on the contract.

A term ending 31 December with 90 days' notice really ends on 2 October. Miss that and you have bought another year. Contract Entitlement turns an order form into machine-readable output (dated obligations, per-SKU entitlements, an exact billing schedule, commitment pace and the largest lawful renewal price) in integer minor units that always reconcile.

Free tier: 25 contracts/month Paid from $499/month No card to run the demo
Live normalization Ready

Runs the same engine the paid endpoint uses. Nothing is stored and no key is needed.

Press “Normalize this contract” to call the live API.
The problem

The commitments are in the contract. The contract is a PDF.

Every obligation your business has to a vendor (and every entitlement a customer has bought) is written down somewhere no system can read. So the dates get tracked by hand, in a spreadsheet, by whoever remembers.

Nobody computes the notice date

The term end is on the cover page. The notice period is in clause 11. The date that actually matters is the arithmetic between them, and nothing in your stack does that arithmetic: so it lives in someone's calendar reminder, if it lives anywhere.

Entitlement questions get answered from memory

Is this customer covered for that module? For how many seats? Did the mid-term addition take effect yet? Support asks finance, finance opens the PDF, and by then the ticket is a day old and the answer is a guess.

The spreadsheet is a cent out and nobody knows why

Prorated periods, mixed billing frequencies, mid-term additions. Each rounded on its own, in a float, in a formula copied down a column. The schedule stops matching the contract value and the reconciliation becomes an argument.

What it costs

A missed date is not an incident. It is a signed obligation.

Nothing alerts. No system fails. The clause simply operates, and the first anyone hears of it is an invoice for a year nobody decided to buy.

  • Renewal
    Another twelve months, agreed by nobody

    The notice window closed while the renewal was still "on the list to look at". The vendor did nothing wrong; the contract said so. The cost is a full term at a price you had leverage to negotiate right up until the day you didn't.

  • Uplift
    An increase accepted above what the contract permits

    The renewal quote arrives, the cap is in clause 11.3, and checking it means annualising a monthly line and an annual line into one comparable figure. Faced with that under time pressure, most people accept the number on the quote.

  • Commitment
    A shortfall discovered in the final month

    A minimum-spend commitment is only a problem at the end, which is exactly when nothing can be done about it. Pace against it is arithmetic anyone could run monthly: and almost nobody does, because it means reopening the contract.

What it computes

Five things a PDF cannot tell you.

Send the order form; get back structured output your systems can act on. No document parsing, no model guessing at clauses: you supply the terms, the engine does the arithmetic that nobody wants to do by hand.

OutputWhat it answersWhy it is hard by hand
ObligationsEvery dated commitment, soonest first, with days remaining and a status.The notice deadline is derived, not written down.
EntitlementsPer-SKU quantities and the exact window each is active.Mid-term additions and early lapses overlap.
Billing scheduleEvery invoice date and amount across the term.Proration, mixed frequencies, month-end drift.
Renewal ceilingThe largest lawful price under the uplift cap.Monthly and annual lines must be annualised first.
Commitment paceWhether spend is on track, and the projected shortfall.Only useful monthly; only checked annually.

Order form Validated Entitlements Schedule Obligations Into your systems

  • 01

    Terms in, structured

    Parties, term, line items, renewal terms, commitments. Every amount is an integer number of minor units: a fractional unit price is rejected at validation rather than rounded into a dispute later.

  • 02

    The notice deadline, computed

    Term end minus notice period, in whole UTC days. If it has passed and the contract auto-renews, the output says so in as many words rather than leaving you to infer it from a date.

  • 03

    A schedule that reconciles

    Period boundaries come from the anchor date, so a term starting on the 31st returns to the 31st after February instead of drifting to the 28th forever. A final partial period is prorated by days, and the amounts always sum exactly to the contract value.

  • 04

    The renewal ceiling, annualised

    A monthly line and an annual line are normalised to twelve months before the cap is applied: adding the raw unit prices reads $10,000 a month as $10,000 a year. One-time fees are excluded, because they do not recur.

  • 05

    Commitment pace, monthly

    What should have been spent by today, what is projected at this rate, and the gap at term end. Enough to act on in month four rather than discover in month twelve.

  • 06

    Entitlement checks at runtime

    Is this customer covered for this SKU, at this quantity, on this date? Quantities are summed across line items, so a mid-term seat addition counts. You get a reason code, not a bare boolean.

Example output

This is what an order form looks like once code can read it.

A one-year contract with 250 seats billed monthly, annual premium support, a one-time implementation fee, 90 days' notice, a 5% uplift cap and a $20,000 minimum commitment, as returned by POST /v1/contracts.

{
  "contractId": "ORD-2026-0041",
  "termDays": 365,
  "totalContractValueMinor": 13950000,
  "annualizedValueMinor": 13200000,
  "renewal": {
    "autoRenew": true,
    "noticeDeadline": "2026-10-02T00:00:00.000Z",
    "noticeWindowMissed": false,
    "daysToNoticeDeadline": 32,
    "renewsOn": "2026-12-31T00:00:00.000Z",
    "renewalTermEndsAt": "2027-12-31T00:00:00.000Z",
    "maxRenewalPriceMinor": 13860000,
    "maxUpliftMinor": 660000
  },
  "commitment": {
    "minimumSpendMinor": 2000000,
    "spentToDateMinor": 400000,
    "requiredToDateMinor": 1315068,
    "projectedSpendMinor": 608306,
    "projectedShortfallMinor": 1391694,
    "onPace": false
  },
  "obligations": [
    { "kind": "renewal_notice",     "dueAt": "2026-10-02", "daysRemaining": 32,  "status": "upcoming" },
    { "kind": "auto_renewal",       "dueAt": "2026-12-31", "daysRemaining": 122, "status": "upcoming" },
    { "kind": "minimum_commitment", "dueAt": "2026-12-31", "daysRemaining": 122, "status": "upcoming" },
    { "kind": "term_expiry",        "dueAt": "2026-12-31", "daysRemaining": 122, "status": "upcoming" }
  ]
}

The schedule always sums to the total

Every entitlement's billing periods add up to its total, and those totals add up to the contract value: exactly, in integers, including prorated periods. If a schedule ever failed to reconcile, the number you invoice against would be a guess.

$138,600, not $23,100

The 5% ceiling applies to $132,000 of annualised recurring value. Summing the raw unit prices instead reads $10,000 a month as $10,000 a year and understates the lawful renewal by a factor of six. That is the arithmetic people lose renegotiations to.

You supply the terms

Contract Entitlement does not parse PDFs or infer clauses with a model. You send the terms your systems already hold, and it does the arithmetic deterministically: the same input always produces the same output.

This service is newly launched. We publish no uptime percentage, customer count, logo wall or certification claim until we have the operating history to support one. Output is arithmetic on the terms you supply; it is not legal advice.

How it works

Two calls to make a contract machine-readable

  • Normalize the contract

    POST the terms. Back come entitlements, obligations, schedules, renewal analysis and commitment pace. One unit per contract, up to 100 per call.

  • Route the obligations

    Every obligation has a dueAt, a daysRemaining and a status. Push due_soon and passed into whatever already gets looked at: a queue, a CRM field, a digest.

  • Answer entitlement questions in code

    Ask whether a SKU is covered at a quantity on a date. Check 500 SKUs against one contract for one unit: charging per query would only teach you to cache the answers.

Two rules the engine never bends

Integer money, UTC days

  • unitPriceMinor and every ceiling are integer minor units. A fractional price is a 400, not a rounding. Proration multiplies first and rounds once, at one named function.
  • Dates are whole UTC days. A notice deadline that shifts an hour across a DST boundary is a missed deadline.
  • endsAt is the last day covered. Contracts say "through 31 December"; treating that as exclusive silently shorts the final period.
  • Period boundaries come from the anchor date. 31 January clamps to 28 February and then returns to 31 March, instead of drifting to the 28th for the rest of the term.
  • Output is deterministic. Same terms, same evaluation instant, same bytes: so a stored result can be diffed.
Developer integration

Small surface, versioned, OpenAPI-first

Authenticate with Authorization: Bearer <key>. Every error returns a stable code and a requestId you can quote, and validation failures name the exact field in details.path.

POST/v1/keysPublic. Emails a one-time claim token to the address you give it. No key is returned on this call, proving the mailbox is what stops anyone minting a key on your account.
POST/v1/keys/claimPublic. Spends the emailed token and returns the key, shown once: 25 contracts a month, no card.
POST/v1/contractsNormalize one contract or up to 100. Billed one unit per contract.
POST/v1/entitlements/checkUp to 500 SKU questions against one contract. Billed one unit: per contract, not per query.
POST/v1/demo/normalizePublic. Real engine, capped at 20 line items. No key required.
GET/v1/obligation-typesPublic. Every obligation kind, status and check reason code.
curl -X POST https://contractentitlement-api.com/v1/contracts \
  -H "Authorization: Bearer $CONTRACT_ENTITLEMENT_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}}}'
Pricing

Priced per contract, capped so a bulk import can’t surprise you

One unit is one contract normalized: or one contract checked, however many SKUs you ask about. Every plan includes an allowance, then a per-unit overage that is hard-capped per billing period: your worst-case bill is the base price plus the cap, never more.

Developer
$499 /month
  • 250 contracts included
  • $3.00 per additional contract
  • Overage capped at $1,000 per period
  • Full API access, Python and TypeScript SDKs
Start with this plan
Scale
$4,999 /month
  • 5,000 contracts included
  • $1.50 per additional contract
  • Overage capped at $10,000 per period
  • Full API access, Python and TypeScript SDKs
Start with this plan
Enterprise
$10,000+ /month
  • 15,000 contracts included
  • $1.00 per additional contract
  • Overage capped at $20,000 per period
  • Full API access, Python and TypeScript SDKs
Contact sales

Free tier: 25 contracts per month, no card. Prices in USD, billed monthly. Payment is processed by Square through our shared billing platform; card details never touch this site.

What counts as a contract?
One contract in one call. Normalizing 50 contracts in a batch bills 50 units. An entitlement check bills one unit for the contract regardless of how many SKUs you query: charging per query would only push you into caching entitlement answers, which is exactly the wrong incentive.
Does it read PDFs?
No. You supply the terms your systems already hold (parties, dates, line items, renewal terms, commitments) and it does the arithmetic. There is no model guessing at clauses, which is why the same input always produces the same output and why you can defend a number in a negotiation.
Is the contract stored?
No. Every endpoint is stateless: you send the terms with each request and get the analysis back. Nothing about your commercial relationships is retained here.
Why integer minor units everywhere?
Because a contract value is the last place a floating-point cent belongs. A fractional unit price multiplied across 36 monthly periods is a reconciliation dispute. Fractional amounts are rejected at validation with the exact field named, and proration rounds once rather than at every step.
How is the renewal ceiling computed?
The uplift cap is applied to annualised recurring value. Monthly and annual lines are normalised to twelve months first, and one-time fees are excluded because they do not recur. Adding raw unit prices instead treats $10,000 a month as $10,000 a year.
Can I evaluate it before paying?
Yes. The demo at the top of this page is the real engine with no key at all, and the free tier gives you 25 contracts a month against the full authenticated surface.

Find the deadline before it finds you.

The free tier is 25 contracts a month, no card. Create a key, post one order form, and the response tells you the date the contract actually turns on.

One email address, no password, no card. Prefer the terminal? The same key, in two calls:

curl -X POST https://contractentitlement-api.com/v1/keys \
  -H "content-type: application/json" \
  -d '{"email":"you@company.com","name":"Evaluation key","source":{"source":"web","medium":"landing"}}'

# 202 Accepted. A one-time token is emailed to that address — spend it,
# and the response carries the key, shown once.

curl -X POST https://contractentitlement-api.com/v1/keys/claim \
  -H "content-type: application/json" \
  -d '{"token":"<token from the email>"}'