Quickstart
Go from zero to your first protected purchase. This guide takes you from minting API keys to a confirmed protection plan you can see in your dashboard — either by embedding the browser widget or by calling the REST API directly.
Document marker: CLAIMFUL_QUICKSTART_SENTINEL
Every request in this guide runs against the base URL
https://api.claimful.ai/api/v1.
1. Get your API keys
Sign in to your merchant dashboard and open Account → API Keys
(/merchant/api-keys). Generate a key and copy the secret — it is shown once and
never re-displayed.
Two independent key families exist, and each is minted separately for test and live environments:
| Key | Prefix | Where it runs | Purpose |
| --- | --- | --- | --- |
| Publishable | wk_test_… / wk_live_… | Browser (public) | Authenticates the embedded widget's quote/confirm/decline calls. Safe to ship in page HTML. |
| Secret | mch_test_… / mch_live_… | Your server only | Authenticates server-side REST calls. Never send a mch_ key from the browser. |
Start in test mode: a wk_test_ / mch_test_ pair keeps every quote and
protected purchase isolated from live traffic. Swap the test keys for live
keys — and nothing else — when you go to production.
2. Embed the widget (or make your first REST quote)
Pick the path that matches your integration. Storefronts embed the declarative widget; headless and server-to-server integrations call REST.
Option A — Embed the widget
Paste this snippet into your checkout page, just before the closing </body>
tag. Both data-merchant-id and data-publishable-key are required — a
missing publishable key hides the widget rather than blocking checkout.
<script src="https://widget.claimful.ai/v1.20260601/widget.js"
integrity="sha384-KVy7W+9O0dxQuL9JTLt1f6/zgffj5mVJNVxIwO+99d3c7SeRQub1ExDBLpXmsOtI" crossorigin="anonymous" async></script>
<claimful-widget
data-merchant-id="YOUR_MERCHANT_ID"
data-publishable-key="wk_test_xxxxxxxx.yyyyyyyy"
data-order-amount-cents="20000"
></claimful-widget>
Replace YOUR_MERCHANT_ID and the wk_test_… publishable key with the values
from your dashboard, and swap the integrity hash for the published SRI hash of
your pinned widget version (ADR 0031). The widget fetches the offer, renders the
protection option, and dispatches the five lifecycle events documented in
Widget Events. Skip to step 4 to verify the result.
Option B — Request a quote over REST
Send a secret mch_ key as a bearer token. The offer endpoint takes a
snake_case body and requires an Idempotency-Key header (any stable
^[A-Za-z0-9_-]{16,255}$ string — a UUID works):
curl -sS https://api.claimful.ai/api/v1/offers/quote \
-H "Authorization: Bearer mch_test_xxxxxxxx.yyyyyyyy" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"order_amount_cents": 20000,
"order_id": "order_1234"
}'
order_amount_cents is the only required field. Omit protection_program_id to
use your default active program, or pass its UUID to pin a specific one.
The response body is camelCase, and the raw quote token comes back in the
X-Claimful-Quote-Token response header — never in the JSON body (ADR 0038):
HTTP/1.1 201 Created
X-Claimful-Quote-Token: 4f3c…64-hex-chars
{
"quoteId": "q_0R4X…",
"fee": 1200,
"currency": "USD",
"freeLookDays": 2,
"reasons": ["…"],
"expiresAt": "2026-07-07T12:15:00+00:00"
}
Capture both quoteId (from the body) and the X-Claimful-Quote-Token header —
you need them to confirm.
3. Confirm the protection plan
When the customer opts in, confirm the quote. The outer credential fields stay
camelCase (quoteId, quoteToken), but every confirm request now also
requires a versioned, snake_case order_context object describing the binding
order (merchant order id, purchase time, covered amount/currency, and the
event/participant facts a later claim needs). A missing or malformed
order_context fails closed with a 422 order_context_invalid response
before any protection is created.
curl -sS https://api.claimful.ai/api/v1/offers/confirm \
-H "Authorization: Bearer mch_test_xxxxxxxx.yyyyyyyy" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"quoteId": "q_0R4X…",
"quoteToken": "4f3c…value from the X-Claimful-Quote-Token header",
"order_context": {
"schema_version": "2026-07-01",
"order": {
"id": "order_8842",
"purchased_at": "2026-07-10T14:18:00Z",
"currency": "USD",
"covered_amount_cents": 84200
},
"participants": { "mode": "unnamed" }
}
}'
The official SDKs pass the confirm payload through verbatim, so the same
order_context field applies there:
$client->offers->confirm([
'quoteId' => $offer['quoteId'],
'quoteToken' => '<value from X-Claimful-Quote-Token header>',
'order_context' => [
'schema_version' => '2026-07-01',
'order' => [
'id' => 'order_8842',
'purchased_at' => '2026-07-10T14:18:00Z',
'currency' => 'USD',
'covered_amount_cents' => 84200,
],
'participants' => ['mode' => 'unnamed'],
],
], idempotencyKey: bin2hex(random_bytes(16)));
A successful confirm returns the frozen response envelope: protected_purchase_id,
reference_number, status, protection_fee_cents, covered_amount_cents,
currency, free_look_ends_at, filing_deadline_at, and — on a fresh live
confirm only — customer_access_url.
A successful confirm returns your protection reference number in
CLM-YYYY-XXXXXXXX format — include it in your order confirmation email (see the
PHP / TypeScript SDK references, §"Confirmation
email requirements").
4. See it in your dashboard
Back in your merchant dashboard, the new protected purchase appears in your
Activity feed. Because you confirmed with a test key, it is stamped as a
test-mode purchase and stays separate from live traffic — so you can rehearse the
whole flow before flipping to live keys.
If nothing shows up, the usual culprits are: a wk_/mch_ key from the wrong
environment, a snake_case confirm body (step 3), or a missing Idempotency-Key
header.
5. Set up webhooks
Once the flow works, wire webhooks so your systems react to protection and refund
events without polling. Register an endpoint under Account → Webhooks
(/merchant/webhooks); the signing secret is revealed once at creation.
Every delivery is signed with an X-Claimful-Signature: t=<unix>,v1=<hex> header
over the {timestamp}.{body} preimage, with a 300-second replay window (ADR 0009
§5). Verify it with the SDK helper rather than hand-rolling HMAC: