Ingesting orders and products
Push purchases into warrantini from any system — and the one identifier decision that cannot be undone afterwards.
If your commerce platform has a connector, use it. This guide is for everything else: an ERP, a bespoke checkout, a warehouse system — anything where you own the integration and push data in yourself.
Read this part twice: anchor to the upstream ID
Every line item you send carries an identifier from the system the sale actually happened in. Send that system's own ID. Never a synthetic one your integration made up, never a connector's internal ID, never a row number from a CSV.
Coverage resolves against that identifier for the entire life of the warranty — one to ten years. If it changes, every registration behind it is orphaned: the coverage still exists, and nothing can find it. There is no error. Nothing fails. It is simply gone, and you discover it when a customer files a claim.
This is also what keeps you free to change vendors later. Anchored to the upstream ID, a connector swap is a migration of transport. Anchored to a connector's ID, it is data loss.
Orders and products are both required
It is tempting to send orders and stop, because orders are what customers buy. But coverage terms come from rules, and rules match on sku, product_type, category and vendor — which live on the product, not the line item.
Send orders without products and the pipeline runs cleanly, matches nothing, and produces no coverage.
One order at a time
The real-time path. Call it when an order is placed, or when it ships if coverage should start from fulfilment.
curl -s -X POST https://api.warrantini.com/api/v1/orders \
-H "Authorization: Bearer $WARRANTINI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"external_id": "SO-2026-00184",
"order_number": "SO-2026-00184",
"customer_email": "dana@example.com",
"customer_name": "Dana Okoye",
"ordered_at": "2026-08-08T14:02:00Z",
"line_items": [
{
"external_id": "SO-2026-00184-1",
"sku": "PMP-450-SS",
"product_title": "450 Series Circulation Pump",
"quantity": 1,
"price": "1249.00"
}
]
}'external_id on the order and on each line item are the upstream anchors. ordered_at is what coverage windows are measured from, so send the real purchase timestamp rather than the moment you happened to call.
Re-sending is safe, and that is the design
Order ingestion is idempotent on external_id. Posting the same one again upserts — it updates the existing order rather than creating a second. Products behave identically, keyed on external_id (plus variant_external_id where you send one).
So a nightly reconciliation that re-sends the last 48 hours is not a bug, it is a reasonable belt-and-braces design. You do not need to track what you have already sent.
Products
Same shape, same idempotency. Send the fields your rules actually match on, or the rules cannot fire.
curl -s -X POST https://api.warrantini.com/api/v1/products \
-H "Authorization: Bearer $WARRANTINI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"external_id": "PMP-450-SS",
"sku": "PMP-450-SS",
"title": "450 Series Circulation Pump",
"product_type": "Pumps",
"vendor": "Northline Industrial"
}'Backfilling in bulk
Bulk import takes up to 500 records per call and is Scale tier only. It is asynchronous: the call returns a job, and you poll it.
# Submit
curl -s -X POST https://api.warrantini.com/api/v1/orders/bulk \
-H "Authorization: Bearer $WARRANTINI_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "orders": [ /* up to 500 */ ] }'
# Poll
curl -s https://api.warrantini.com/api/v1/orders/bulk/job_01hxyz \
-H "Authorization: Bearer $WARRANTINI_API_KEY"Because ingestion is idempotent, a bulk job that partially fails can simply be re-submitted whole. Records that landed the first time update in place; the ones that did not are created.
Sequencing a backfill
Order matters more than it looks, because rules match at ingestion time.
- Products first. A rule that cannot see the product cannot term the coverage.
- Then rules, in the dashboard — confirm they are what you expect before real data lands against them.
- Then orders, oldest first. Coverage is measured from
ordered_at, so historical orders will correctly produce already-expired registrations rather than a wave of fresh coverage. - Then reconcile — list registrations and confirm the count and terms look like your policy.
Common failures
403.../tier-insufficienton/bulk— bulk is Scale; single-record ingestion is Growth.422.../validation-error— the response'serrorsarray names the offending field. Checkordered_atis ISO 8601 andpriceis a decimal string, not a number.- Silence — no registrations appear. Almost always missing products, or rules that do not match the
sku/product_typeyou actually sent. Fetch a line item back and compare its fields against the rule conditions.
Next
Webhooks so your system hears about coverage and claims rather than polling for them, and Errors, idempotency, pagination, and rate limits before you run a backfill unattended.