Your system sends ProveCart two things per transaction: the customer's signed instruction (the mandate) and what the agent actually built. ProveCart compares them before the payment and answers MATCH, REVIEW, or BLOCK. Every check leaves a sealed evidence record. ProveCart never holds or moves money.
Start with shadow mode to see your own numbers. Move to enforcement when you are ready for the verdict to gate the payment.
Send copies of agent transactions and the matching customer instructions. ProveCart runs the same checks and reports the verdicts, and nothing is stopped: your customers see no change.
Zero-code start: send a scheduled export of your agent orders, bookings, or reservations together with the customer instructions behind them (for example, a nightly file). We check them after the fact and report what would have been flagged or stopped.
Or make the same API calls as enforcement mode and simply not act on the verdict yet. Verdicts are recorded either way, which is what your pilot report is built from.
Call ProveCart before the payment is captured (and, for bookings, before a ticket is issued), and act on the answer:
On a REVIEW or BLOCK, the response tells the agent exactly what to fix, so a correctable transaction can be fixed and resubmitted instead of lost. See Corrections.
Base URL for every call: https://api.provecart.com. Interactive endpoint reference: api.provecart.com/docs.
X-API-Key header on every call.POST /mandates (orders), POST /booking-mandates (travel), or POST /reservation-mandates (services). The server signs the mandate and returns its id and signature.POST /verify, POST /verify-booking, or POST /verify-reservation. Add an Idempotency-Key header, unique per attempt.corrections, the signed verdict_token your payment step uses, and the record_id of the sealed evidence record.Create a mandate:
curl -X POST https://api.provecart.com/mandates \
-H "X-API-Key: your-store-key" \
-H 'Content-Type: application/json' -d '{
"user_id": "user-123",
"item_description": "Wireless noise cancelling over-ear headphones",
"item_keywords": ["wireless", "headphones", "noise", "cancelling"],
"category": "electronics",
"max_total_price": 300.00,
"currency": "USD",
"merchant_allowlist": ["shop.example.com"],
"max_quantity": 1,
"expires_at": "2027-01-01T00:00:00Z"
}'
# The answer includes the mandate "id" and "signature".
Verify a cart against it:
curl -X POST https://api.provecart.com/verify \
-H "X-API-Key: your-store-key" \
-H "Idempotency-Key: attempt-0001" \
-H 'Content-Type: application/json' -d '{
"mandate_id": "<MANDATE_ID>",
"merchant": {"name": "Example Shop", "domain": "shop.example.com"},
"items": [{"name": "Wireless Noise-Cancelling Headphones",
"variant": "black", "quantity": 1, "unit_price": 249.99}],
"total_price": 249.99,
"currency": "USD"
}'
# Expect "verdict": "MATCH" for this cart.
# The same cart at 349.99 answers "BLOCK": over the buyer's ceiling.
POST /intake/draft turns it into a draft mandate in the same shape, listing any fields the text does not determine as missing. Fields are never guessed. POST /intake/confirm then runs the confirmed draft through the same signing flow as any other mandate.Three mandate types, one shape: what the customer authorized, then what the agent built.
POST /mandates)| Field | What it is |
|---|---|
user_id | Your identifier for the buyer. |
item_description | What the buyer asked for, in words. |
item_keywords | The key terms of the buyer's instruction. |
category | The category the purchase must stay in. |
max_total_price | The buyer's price ceiling. |
price_basis | Which total the ceiling applies to: grand_total (default; tax and fees included) or merchandise. |
currency | The currency of the ceiling. |
merchant_allowlist / merchant_blocklist | Merchants the agent may, or may not, buy from. |
brand | A required brand, when the buyer named one. |
variant_constraints | Required variant attributes (color, size, capacity, model). A constraint marked required must match. |
max_quantity | The most units the buyer authorized. |
expires_at | When the instruction stops being valid. |
type: "standing" + period_budget | Optional: a standing instruction with a per-period budget, tracked across checks. |
Then verify the cart (POST /verify) with: mandate_id; merchant as {name, domain}; items, each with name, variant, quantity, and unit_price; total_price plus any tax, shipping, and fees; currency; and, for a corrected resubmission, previous_record_id.
POST /booking-mandates)| The mandate records | What it is |
|---|---|
| Travelers | Names as they appear on identification. |
| Origin and destination | Airport or city granularity, plus any acceptable alternate airports. A same-metro substitution counts only when listed; substitution is never silent. |
| Departure and return dates | With optional flex days and a departure time window. |
| Cabin | The minimum cabin the traveler asked for. |
| Fare terms | Whether a refundable fare is required, and a maximum change fee. |
| Itinerary limits | Maximum connections per direction, minimum connection time, maximum layover, and whether overnight layovers or airport changes are allowed. |
| Lodging (optional) | Room type and occupancy requirements. |
| Price ceiling and basis | The ceiling, and the basis it applies to: all_in, fare_taxes, or base_fare. |
Verify with POST /verify-booking: the booking as the agent built it (travelers, segments, cabin and fare terms, lodging if any, and the price). The verdict gates both payment capture and ticket issuance, and a re-priced, re-scheduled, or substituted booking must be re-verified before either happens.
POST /reservation-mandates)| The mandate records | What it is |
|---|---|
| Service | What is being reserved. |
| Provider and location | An optional named provider; a city, optionally an exact branch. |
| Date and time | The date and the time slot, with a stated tolerance in minutes. |
| Party size | The expected party size, and an optional maximum. |
| Name | The name on the reservation. |
| Deposit and total | An optional deposit cap and a total ceiling. |
| Cancellation terms | Free cancellation until a set number of hours before, and a maximum cancellation fee. |
Verify with POST /verify-reservation: the reservation as the agent made it.
Every check compares the transaction part by part and answers one of three verdicts. A hard failure (over the price ceiling, a different traveler, an excluded merchant, an expired instruction) is a BLOCK. A soft failure (more units than the stated maximum, a different currency, anything genuinely in between) is a REVIEW. Everything passing is a MATCH. When the checker is uncertain, the answer is REVIEW, never a silent pass.
Idempotency-Key with each verify call. Repeating the same call with the same body returns the original verdict, marked as a replay, with no duplicate record. Reusing the same key with a different body is refused with a 409.GET /verdicts?since=<record_id> to receive the same signed verdict payloads in order.A REVIEW or BLOCK answer carries a machine-readable corrections array: for each problem the agent can fix, the action to take and the expected versus actual values. Nothing about the checking internals is included.
remove_item, replace_item, change_variant, reduce_quantity, reduce_total, change_currency.correct_traveler_name, change_travel_date, change_airport, change_cabin, change_fare_terms, rebuild_itinerary, change_room, and more.change_date, change_time, change_party_size, correct_reservation_name, reduce_deposit, change_cancellation_terms, change_provider, change_location.Problems an agent cannot fix by editing the transaction (an expired or invalid instruction, an excluded merchant, an exhausted standing budget) are marked correctable: false on their result, so the agent does not loop retrying them.
The agent resubmits the corrected transaction as a new verify call against the same mandate, with previous_record_id set to the earlier check. Both rounds stay in the evidence chain, and the response suggests a guidance limit of max_attempts: 3.
POST /mock-psp/authorize creates a hold, you verify the cart, and POST /mock-psp/capture accepts only a valid, unexpired token bound to the same cart and amount. A BLOCK always refuses; a REVIEW capture needs an explicit override: true, and the override is recorded. POST /mock-psp/void releases a hold. For bookings, POST /mock-ticketing/issue applies the same rules to ticket issuance.GET /records/verify-chain recomputes the evidence chain and reports whether it is intact.Three ways in, in order of effort. Every pilot starts at the top of this ladder.
| Start | Your work | Typical time |
|---|---|---|
| Shadow, by export | No development at all. Send a recurring export of agent transactions and the customer instructions behind them; we run the same checks after the fact and report the verdicts. | Live in days |
| Shadow or check, by API | One developer adds one call in the checkout or booking flow: create the mandate, send the verify, read the verdict. You do not have to act on the verdict yet. | Typically an afternoon |
| Enforcement | A planned change around the payment step: hold capture on BLOCK, pause on REVIEW for approval, and let the agent fix and resubmit when a correction comes back. | Usually two to three weeks, including testing |
During pilots, ProveCart works white-glove alongside your developer: key setup, field mapping, and test cases are done with you, not handed over as homework.