Skip to main content
Most Korint endpoints are synchronous: the response tells you the outcome. A few are not, and they are concentrated exactly where a new-business integration spends its time — signature, payment, document processing, and activation. For those, a 2xx means accepted, not done. Completion happens elsewhere: a customer signs in their browser, Stripe confirms a mandate, a scheduled job reaches a start date. You observe it by polling the resource that carries the state.
Korint does not currently send outbound webhooks to API clients. The webhooks in the platform are inbound — Stripe and the signature provider notifying us. There is no event subscription you can register, so polling is the only way to observe completion today.

What is synchronous

These return the outcome, and you can act on the response directly:
  • Creating and editing customers, policies and assets.
  • POST /policies/{policyId}/calculate-quote and POST /policies/{policyId}/quote — pricing is computed during the request. A price that cannot be produced fails the call or is recorded as a quote failure; it does not arrive later.
  • POST /policies/{policyId}/confirm — validation is immediate.
  • Registry lookups: GET /siren, GET /vehicle-information/*, GET /address-autocomplete/suggest. These need an actor with the right permissions — GET /siren is refused to an anonymous session (403), so a public funnel collects a typed SIRET and lets enrichment happen server-side on the PATCH instead.
Products whose pricing the carrier keeps — rather than delegating it to a Korint pricing engine — are the exception. Their quote depends on an external response, so treat it as a step whose result you re-read rather than one you assume.

What you have to observe

Signature

POST /policies/{policyId}/signature creates the request and returns the signers with their links. It does not wait for anyone to sign. Poll the signature requests for the policy:
Response
This endpoint returns 200 with an empty signatureRequests array when nothing matches — an empty list is not an error and not a “not yet created” signal you can distinguish from a bad id. Confirm you are passing the policy id as externalId.
The policy itself also moves as signing completes, so GET /policies/{policyId} is the better signal for “may I proceed?”, and the signature requests are the better signal for “who still has to sign?”. A signer who has lost the email needs a fresh nudge rather than a new request: POST /signature/{signatureId}/policy/{policyId}/signers/{signerCustomerId}/resend, or fetch their link again with the matching /link endpoint. Poll every 10–15 seconds while a signing session is open in front of you, every few minutes otherwise. Signature is a human action: expect minutes to days, and never block a request thread waiting for it.

A payment method after the browser setup

Confirming a SetupIntent happens between the customer’s browser and Stripe. We learn about it from Stripe’s webhook, so the payment method appears on our side shortly after — not at the moment the browser reports success. Poll GET /customers/{customerId}/payment-methods until the method appears, every 2–3 seconds for the first half-minute, then back off. If it never appears, the setup did not actually succeed; re-check the browser-side result rather than retrying the secret.

Documents

POST /policies/{policyId}/documents returns an upload URL; you then upload the file to that URL directly. The document exists once that upload finishes, but nothing has looked at it yet. Processing is a call you make, and it is the exception to this page: GET /documents/validate?key=… scans, classifies and extracts, streaming progress as Server-Sent Events. Consume the stream instead of polling. Settled results live on GET /policies/{policyId}/documents/validity and GET /policies/{policyId}/document-extractions. Fields configured with autoFill are populated from a successful extraction (see Read the product configuration), so re-read the entity rather than assuming your earlier values survived.

Coming into force

Activation is driven by time and by payment, not by your call. A signed contract comes into force when its start date arrives, and — on products with requireFirstPaymentToActivate — once the first premium has been collected. Poll GET /policies/{policyId} at whatever cadence your business needs, minutes at most. A future-dated contract will sit signed-but-not-in-force until its start date; that is not a state you should poll tightly.

Renewals, repricing and recurring billing

These are driven by scheduled jobs on our side, on the product’s own cycle. Nothing is triggered by an API call you make, and nothing notifies you. Read the current state when you need it — a renewal appears as a new branch on the policy.

How to poll well

  • Back off. Start at the intervals above, then widen. A tight loop on a step that takes a human minutes is wasted on both sides.
  • Set a ceiling and surface it. A signature that has not completed in days is a business problem for someone to chase, not a request to keep retrying forever.
  • Poll the resource, not the action. Re-reading the policy or the payment method tells you the truth; re-issuing the original call may create a second signature request or a second setup.
  • Re-read after every asynchronous step. Extraction and registry enrichment both change values you sent. Working from your local copy is how integrations drift out of step with the contract.
There is no published rate limit on the endpoints in this guide. A few endpoints are individually limited and say so in the reference — starting an anonymous session and the claim lookup routes are each capped at 100 per hour. Treat the absence of a limit elsewhere as a courtesy rather than a guarantee: poll at the intervals above rather than as fast as your client allows.

Timestamps you control

Most commands accept a whenAt query parameter — the business time at which the action is recorded, rather than the moment the request arrives. Contracts are event-sourced, so whenAt is how you backdate an action, replay a historical journey, or keep a migrated contract’s own chronology. Read endpoints have the mirror-image parameter, simulatedAt: the state of the contract as at that date. Together they let you ask “what did this contract look like then?” without mutating anything — and they are the reason a read that ignores them can look stale when it is simply answering about now.