quore/API documentation

Issuance flow

From quote to issued policy: quote, issue, resolve conditions and get the documents.

Step by step

  1. Quote with POST /api/quotes: returns the quoteId and the coverages with their net premium and total premium.
  2. If the quote is pending_approval, wait for the insurer's approval (quote.approved webhook).
  3. Issue with POST /api/policies sending quoteId, the chosen coverageId and the issuance data.
  4. If the product uses conditional issuance, the policy stays pending until its conditions are resolved with POST /api/policies/{id}/conditions/resolve; only then does the payment open (payment_url).
  5. Get the documents: the certificate is generated automatically; you can also render or regenerate PDFs.

1. Quote

POST/api/quotes
  • Requires a key with the quote scope. Body: productId and variables (the product variables that affect the price). Each product reference lists its variables, types, ranges and options.
  • Answers 200 with the priced quote.
  • The quote expires according to the product (quoteTtlHours, 48 hours by default): see expiresAt.
  • status: priced, or pending_approval when a coverage requires approval.
  • Amounts: netPremium is the net premium (technical price, before taxes) and totalPremium is the total premium (amount to pay).

Request

curl -X POST https://api.quore.app/api/quotes \
  -H "x-api-key: sk_test_…" \
  -H "Content-Type: application/json" \
  -d '{
    "productId": "PRODUCT_ID",
    "variables": { "edad": 35, "plan": "full" }
  }'

Response (abridged)

{
  "quoteId": "3f1c2a9e-5b7d-4c1e-9a1f-2d6b8e0c4a11",
  "status": "priced",
  "expiresAt": "2026-10-28T14:00:00.000Z",
  "term_type": "annual_installments",
  "coverages": [
    {
      "key": "basica",
      "name": "Basic coverage",
      "currency": "ARS",
      "netPremium": 42000,
      "taxes": 8820,
      "totalPremium": 50820,
      "installments": 12,
      "installment": 4235
    }
  ]
}

2. Issue

POST/api/policies
  • Requires a key with the emit scope. Body: quoteId, coverageId (the key of one of the quote coverages) and data.
  • data carries the issuance-step variables and the payment method. Quoted values are taken from the quote.
  • Answers 201 with the policy. Retrying with the same quote and the same coverage returns the same policy; another coverage answers 409.
  • With an online payment provider the response includes payment to complete the charge (see Payments).
  • Manual payment method: never send the full card number or the CVV; only card_last4, card_brand and card_holder.

Request

curl -X POST https://api.quore.app/api/policies \
  -H "x-api-key: sk_test_…" \
  -H "Content-Type: application/json" \
  -d '{
    "quoteId": "QUOTE_ID",
    "coverageId": "basica",
    "data": {
      "nombre": "Ana Pérez",
      "payment": { "method": "credit_card", "card_last4": "4242", "card_brand": "visa", "card_holder": "Ana Pérez" }
    }
  }'

3. Issuance conditions

POST/api/policies/{id}/conditions/resolve
  • With conditional issuance the policy is created pending, with its conditions list (for example, an inspection).
  • Resolve each condition with status approved or failed (and failureReason). The insurer can also resolve them from its dashboard.
  • With all approved (or one, when the logic is OR) the policy becomes active; a failed condition with reject behavior makes it rejected.
  • Conditions are resolved BEFORE payment: while they're pending no charge is started (payment_after_conditions: true on issuance). Once they're all approved, if the product collects online (Stripe, Mercado Pago or Rebill), the policy moves to pending_payment, the policy.status_changed webhook and the resolve response carry payment_url (the public payment page), and the insured and the intermediary get the link to pay. When the payment is confirmed the policy becomes active right away. Without online collection it goes straight to active. A payment-type condition is not added when collecting online: the payment is the last step.
  • A declined payment leaves the policy payment_failed ("Payment declined", with payment_status: failed) and fires payment.failed. The intermediary (or the admins when there's none) and the insured are notified with the reason and the same payment link to retry; an approved retry activates it.
  • A rejected (or expired) condition ends the flow with no charge: the policy becomes rejected and the payment never opens. Older policies paid before their conditions were resolved and then rejected stay flagged with refund_status: pending (payment.refund_required) and are marked refunded in Approvals or in the policy detail (payment.refunded).
  • Optional expiry: with issuance.expires_after_hours (or expires_after_hours on a condition), a policy whose conditions are still pending when it expires is rejected with the reason "Vencida" (expired). Not configured: it never expires.
  • Concurrent resolutions of the same policy are applied one at a time, none is lost.
  • Every status change fires the policy.status_changed webhook.

Resolve a condition

curl -X POST https://api.quore.app/api/policies/POLICY_ID/conditions/resolve \
  -H "x-api-key: sk_test_…" \
  -H "Content-Type: application/json" \
  -d '{ "conditionId": "inspection", "status": "approved" }'

4. Documents

  • The certificate is generated automatically once the policy is active (on issuance, or when a conditional policy activates) and sent to the insured. A pending or rejected policy has no certificate (409 when requested).
  • The policy PDF is available when the product has its template and your plan includes that document.
  • Documents of a sandbox record can only be read with a sandbox key.
EndpointWhat it does
GET/api/policies/{id}/documentsLists the policy generated documents (id, docType, generatedAt).
GET/api/documents/{id}/downloadDownloads a document: returns a temporary URL or the PDF.
GET/api/documents/renderRenders a policy or quote PDF on the fly (docType + policyId or quoteId), without storing it.
POST/api/policies/{id}/documents/certificate/regenerateRegenerates the certificate (answers 202 with a jobId).

Documents

curl https://api.quore.app/api/policies/POLICY_ID/documents -H "x-api-key: sk_test_…"
curl https://api.quore.app/api/documents/DOCUMENT_ID/download -H "x-api-key: sk_test_…"
curl "https://api.quore.app/api/documents/render?docType=certificate&policyId=POLICY_ID" -H "x-api-key: sk_test_…" -o certificado.pdf

5. Read and update policies

To reconcile your system with Quore: list and read policies, record the number the insurer assigns, and get a quote's documents. admin includes every scope.

EndpointScopeRequestResponseCodes
GET/api/policiesread · emitOptional query: productId, status, environment, limit (50 by default, 200 max), offset.200 with { data, total, limit, offset }, newest first. Each item is the policy with camelCase fields (policyNumberInternal, netPremium, createdAt…).400 environment of the other environment · 401 · 403 missing scope
GET/api/policies/{id}read · emitPath: the policy id.200 with the policy (same format as policy.created, with numeric amounts) and documents: id, doc_type, generated_at, download_path.401 · 403 missing scope · 404 not found or of the other environment
POST/api/policies/{id}/insurer-numberemitBody: { "policyNumberInsurer": "AP-2026-000123" } (non-empty text). Replaces the previous value.200 with the updated policy (camelCase fields, as in the list).400 missing or empty · 401 · 403 missing scope · 404 not found or of the other environment
GET/api/quotes/{id}/documentsread · quote · emitPath: the quote id.200 with the quote's documents: id, docType, policyId, quoteId, templateId, generatedAt, createdAt.401 · 403 publishable key or missing scope · 404 not found or of the other environment

Requests

curl "https://api.quore.app/api/policies?status=active&limit=50&offset=0" -H "x-api-key: sk_test_…"
curl https://api.quore.app/api/policies/POLICY_ID -H "x-api-key: sk_test_…"
curl https://api.quore.app/api/quotes/QUOTE_ID/documents -H "x-api-key: sk_test_…"

curl -X POST https://api.quore.app/api/policies/POLICY_ID/insurer-number \
  -H "x-api-key: sk_test_…" \
  -H "Content-Type: application/json" \
  -d '{ "policyNumberInsurer": "AP-2026-000123" }'

GET /api/policies (abridged)

{
  "data": [
    {
      "id": "b2a7…",
      "policyNumberInternal": "POL-0042",
      "policyNumberInsurer": null,
      "status": "active",
      "productId": "PRODUCT_ID",
      "coverageId": "basica",
      "quoteId": "QUOTE_ID",
      "netPremium": 42000,
      "totalPremium": 50820,
      "currency": "ARS",
      "environment": "live",
      "createdAt": "2026-10-26T14:03:11.402Z"
    }
  ],
  "total": 1,
  "limit": 50,
  "offset": 0
}

GET /api/policies/{id} (abridged)

{
  "id": "b2a7…",
  "policy_number_internal": "POL-0042",
  "policy_number_insurer": "AP-2026-000123",
  "status": "active",
  "product_id": "PRODUCT_ID",
  "coverage_id": "basica",
  "quote_id": "QUOTE_ID",
  "net_premium": 42000,
  "total_premium": 50820,
  "currency": "ARS",
  "installments": 12,
  "installment_amount": 4235,
  "environment": "live",
  "payment_method_status": null,
  "start_date": "2026-10-26T00:00:00.000Z",
  "end_date": "2027-10-26T00:00:00.000Z",
  "documents": [
    {
      "id": "DOCUMENT_ID",
      "doc_type": "certificate",
      "generated_at": "2026-10-26T14:03:15.020Z",
      "download_path": "/api/documents/DOCUMENT_ID/download"
    }
  ]
}
  • A key only sees records of its own environment: a test key does not find live policies (404).
  • Publishable (widget) keys cannot use any of these endpoints (403).

Approvals

  • Quote: a coverage that requires approval (always or under a condition) leaves the quote pending_approval. The insurer approves or rejects it from its dashboard; it fires quote.approved or quote.rejected.
  • Intermediaries: when the product does not let them issue directly, an intermediary's quote stays pending_approval until the insurer approves it; once approved it can be issued, and the policy is issued as soon as the payment is confirmed.
  • A pending_approval, expired or rejected quote cannot be issued (400).

Statuses

Quote

StatusMeaning
draftDraft, not priced yet.
pricedPriced: ready to issue until expiresAt.
pending_approvalNeeds the insurer approval before it can be issued and paid (a coverage rule, or an intermediary quote without direct issuance). The reason is in result.approval_reasons.
approvedApproved: can be issued.
rejectedRejected: cannot be issued.
acceptedAccepted by the client.
expiredExpired: quote again.
issuedIssued: it already has its policy.

Policy

StatusMeaning
pendingWaiting for issuance conditions (for example, an inspection).
pending_paymentIssued, waiting for the online payment to complete (on conditional products, once its conditions are approved).
activeActive. Depending on its dates it shows as Contracted (starts later), In force or Expired.
rejectedRejected (failed or expired condition).
cancelledCancelled.
expiredExpired.

Recurring and usage policies also report payment_method_status: pending until the insured saves a payment method, then active. The policy only becomes active with its first charge confirmed (recurring) or its card validated (usage).

Errors

Every error answers JSON with error (a readable message in Spanish). Per-field validation errors (422) add fields: variable key → message.

CodeWhen
400Missing or invalid data: no productId/variables, inactive product or disabled channel, expired, rejected or pending-approval quote, missing required attachment, list of another environment.
401Missing, invalid or revoked key; missing or expired emission token (widget).
403Insufficient scope, publishable key on a read resource, inactive intermediary, intermediary without a commission tier for the product, or feature not included in your plan.
404Does not exist, belongs to another account or to the other environment (a test key only sees test data).
409Conflict: the quote was already issued with another coverage, or a unique value already exists (for example, externalRef).
422Per-field validation (fields), payment method not enabled for the product, or usage not billable for the policy.
429Request limit reached: wait the Retry-After seconds.

422: per-field validation

{
  "error": "Age: the minimum value is 18",
  "fields": {
    "edad": "Age: the minimum value is 18",
    "plan": "Plan: this field is required"
  }
}

Error

{
  "error": "Quote not found"
}