{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":[]},"type":"markdown"},"seo":{"title":"Robustness — kwery Docs","siteUrl":"https://docs.kwery.co","description":"How to build an integration that survives kwery's non-breaking API changes and service incidents."},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"robustness","__idx":0},"children":["Robustness"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["kwery sits between your systems and marketplaces that change daily. This page is the short"," ","list of practices that make an integration ride through bad days — ours, yours, and the"," ","marketplaces' — without waking anyone up."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"id":"additive","level":2,"__idx":1},"children":["Tolerate additive change "]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Per the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/api-change-policy"},"children":["API change policy"]},", new response fields, sources, and event"," ","types can appear at any time. Read the fields you need, ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["ignore unknown fields"]},", never"," ","depend on field order, and treat every field outside ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["key"]}," / ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["success"]}," / ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["reason"]}," as"," ","optional — a source can stop exposing an attribute (that's the marketplace's doing, and"," ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/trust#components"},"children":["trust ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["completeness"]}]}," will tell you)."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"id":"envelope","level":2,"__idx":2},"children":["Always check ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error"]}," first "]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Validation problems return ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["HTTP 200"]}," with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["{\"error\": true, \"message\": …}"]}," — consuming a"," ","response without checking ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error"]}," is the single most common integration bug. See"," ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/errors-and-limits"},"children":["Errors & limits"]},"."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"id":"retries","level":2,"__idx":3},"children":["Retry the right things, with backoff "]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["5xx"]}," and network-level failures"]}," — transient server-side or connection problems."," ","Retry with exponential backoff and a finite attempt count; a submission that fails this"," ","way never consumes credits. (There is no per-account rate limit to back off from — see"," ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/errors-and-limits#rate-limiting"},"children":["Errors & limits"]},".)"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Per-value ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["reason: \"source currently unavailable\""]}]}," — a transient crawl failure (never"," ","billed): re-submit those values in a later job rather than instantly."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Don't retry"]}," validation errors (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["parameter …"]},"), ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["401"]},"/",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["403"]},", or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["402"]}," — they won't"," ","succeed until something changes on your side."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"id":"per-value","level":2,"__idx":4},"children":["Handle per-value outcomes, not just per-job "]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["A job with 1 000 values can contain found products, not-founds, and transient failures side"," ","by side. Process results per value on ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["success"]}," + ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["reason"]},"; never treat a finished job as"," ","\"all good\" or one bad value as a failed batch."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"id":"logging","level":2,"__idx":5},"children":["Log what support needs "]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Log the job id for every submission, and the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["reason"]}," plus (with"," ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/audit-and-provenance"},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["include_meta"]}]},") the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["crawl_id"]}," for anything odd. A support"," ","request with a job id and a crawl id gets answered in minutes; \"yesterday some results"," ","looked wrong\" doesn't."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"id":"webhooks","level":2,"__idx":6},"children":["Webhooks: idempotent and fast "]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Ack ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["2xx"]}," immediately, process async, de-duplicate on ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["X-Kwery-Delivery-Id"]}," (retries can"," ","race a slow ack), and verify signatures against the raw body. Full walkthrough:"," ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/webhooks"},"children":["Webhooks"]},". If your endpoint goes down, deliveries are retried for ~43 minutes"," ","and then dead-lettered for ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/webhooks#5-replay-and-polling-fallback"},"children":["replay"]}," — build the"," ","replay call into your recovery runbook."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"id":"monitoring","level":2,"__idx":7},"children":["Watch your own consumption "]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Monitor request volume, retry rates, and credit consumption — a buggy loop shows up in"," ","your credit curve before it shows up anywhere else. The dashboard shows balance and daily"," ","usage, and we email you at 80% / 95% / depleted so a runaway integration never burns"," ","silently. Cap worst-case overage spend with the"," ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/pricing#budget-cap"},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["cap_stop"]}," overage mode"]},"."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"id":"retention","level":2,"__idx":8},"children":["Mind the retention window "]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Results are downloadable for ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["72 hours"]},". Persist what you need on your side promptly —"," ","retention is a pickup window, not an archive."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"next-steps","__idx":9},"children":["Next steps"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/api-change-policy"},"children":["API change policy"]}," — what can change without notice, and what"," ","can't."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/errors-and-limits"},"children":["Errors & limits"]}," — envelope, status codes, what consumes credits."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/webhooks"},"children":["Webhooks"]}," — signature verification, retries, replay."]}]}]},"headings":[{"value":"Robustness","id":"robustness","depth":1},{"value":"Tolerate additive change","id":"additive","depth":2},{"value":"Always check error first","id":"envelope","depth":2},{"value":"Retry the right things, with backoff","id":"retries","depth":2},{"value":"Handle per-value outcomes, not just per-job","id":"per-value","depth":2},{"value":"Log what support needs","id":"logging","depth":2},{"value":"Webhooks: idempotent and fast","id":"webhooks","depth":2},{"value":"Watch your own consumption","id":"monitoring","depth":2},{"value":"Mind the retention window","id":"retention","depth":2},{"value":"Next steps","id":"next-steps","depth":2}],"frontmatter":{"seo":{"title":"Robustness — kwery Docs","description":"How to build an integration that survives kwery's non-breaking API changes and service incidents."}},"lastModified":"2026-09-17T11:19:31.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/guides/robustness","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}