Resources

Quotes

Submit a user profile, get back ranked HMO plan quotes with rationale, frozen pricing, and a 24-hour validity window.

A quote is a personalised, time-bound snapshot. You submit a minimal user profile (no PII), Pierflow scores every active plan against the profile, applies the per-HMO contract math, and returns a ranked list. The numbers are frozen so the same quote you displayed in comparison flows through to enrollment and settlement.

Requires an API key with the insurance:read scope.

Create a quote#

POST/v1/quotes

Profile shape

FieldRequiredDescription
age_in_yearsYesNumeric age 0–120.
sexNoM | F | U. Defaults to U.
dependentsNoNumber of dependents to cover. Default 0.
monthly_budget_ngnNoBudget in NGN minor units (kobo). Influences ranking. Omit for no constraint.
stateNoUser's state. Used by geographic scoring (and plan filtering once provider networks are wired up).
lgaNoUser's LGA.
conditionsNoSelf-declared lowercase condition tokens (e.g. ['asthma','diabetes']). Influences exclusion penalty.
fintech_refNoOpaque reference (e.g. your user id + session id). Round-tripped on retrieval.
limitNoHow many ranked quotes to return. 1–20. Defaults to 5.
provider_slugNoRestrict to one HMO. Omit to score across the catalogue.
Don't send full date of birth, BVN, or NIN at quote time. The quote step is anonymous by design — identity verification happens at POST /v1/enrollments.
bash
bash
curl -X POST https://sandbox.api.pierflow.com/v1/quotes \
  -H "Authorization: Bearer $PIERFLOW_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "age_in_years": 28,
    "sex": "M",
    "dependents": 0,
    "monthly_budget_ngn": 1000000,
    "state": "Lagos",
    "lga": "Ikeja",
    "limit": 5,
    "fintech_ref": "session_8f3a92"
  }'

Response#

200 OK
json
{
  "request_id": "qreq_b3f9c21a",
  "expires_at": "2026-06-09T12:00:00.000Z",
  "quotes": [
    {
      "id": "quote_a1b2c3d4",
      "plan_id": "plan_silver",
      "rank": 1,
      "score": 0.845,
      "wholesale_ngn": "850000",
      "markup_ngn": "150000",
      "member_pays_ngn": "1000000",
      "rationale": {
        "reasons": [
          "Fits your ₦10,000 monthly budget",
          "Available for age 28",
          "Broad benefit coverage"
        ],
        "warnings": [],
        "signals": {
          "budget": 1,
          "age": 1,
          "dependents": 1,
          "geography": 0.6,
          "coverage": 0.545,
          "exclusionPenalty": 0
        }
      },
      "contract_version": 1,
      "splits_snapshot": {
        "mode": "MARKUP_FIXED",
        "wholesale_ngn": "850000",
        "markup_ngn": "150000",
        "member_pays_ngn": "1000000",
        "hmo_line": { "role": "HMO", "amount_ngn": "850000", "settlement_tag": null },
        "lines": [
          { "role": "PIERFLOW", "amount_ngn": "20000", "settlement_tag": "pierflow:platform_fee", "is_remainder": false },
          { "role": "EMR_VENDOR", "amount_ngn": "30000", "settlement_tag": "emr_vendor:default", "is_remainder": false },
          { "role": "FINTECH", "amount_ngn": "100000", "settlement_tag": "fintech:self", "is_remainder": true }
        ]
      },
      "expires_at": "2026-06-09T12:00:00.000Z"
    }
  ]
}
Money fields are returned as strings to preserve BigInt precision. Treat them as integers in kobo and parse explicitly: BigInt(q.wholesale_ngn).

Rationale shape#

Every quote carries a rationale with three parts. Render any or all of it to the user — it's designed to be human-honest.

FieldDescription
reasonsPositive-signal strings. e.g. 'Fits your ₦10,000 monthly budget'. Show these to justify the recommendation.
warningsNegative-signal strings. e.g. 'Plan excludes: HIV'. Show alongside the price so the user sees what they're trading off.
signalsPer-signal score breakdown (0..1) for audit. Useful for debugging the ranking but rarely shown to end-users.

Pricing model#

The three pricing fields on a quote describe a layered model:

FieldMeaning
wholesale_ngnWhat the HMO charges Pierflow. This is the plan's catalogue price.
markup_ngnPlatform markup added on top. Zero in gross-share contracts, non-zero in markup contracts.
member_pays_ngnWhat the user actually pays. Always wholesale + markup.

Decide whether you show the breakdown to the user or just member_pays_ngn. Both are honest. The split per party is in splits_snapshot.lines.

Retrieve a quote#

GET/v1/quotes/:id

Accepts either a quote id or a quote request id. With a quote id you get one quote; with a request id you get the full ranked list. Both are scoped to your partner — you only see your own quotes.

bash
bash
curl https://sandbox.api.pierflow.com/v1/quotes/quote_a1b2c3d4 \
  -H "Authorization: Bearer $PIERFLOW_KEY"

Validity & expiry#

Quotes expire 24 hours after creation. After that the expires_at timestamp has elapsed and you must call POST /v1/quotes again. The numbers may change if the HMO updated their catalogue, or if you renegotiated the contract — that's why we freeze them per-quote rather than recomputing at enrollment.

If a user begins enrollment more than 24 hours after seeing a quote, re-quote and present the new numbers before charging. Otherwise the settlement step will fail because the snapshot has expired.

Next step#

Pass quote.id to POST /v1/enrollments when the user clicks Buy. Enrollment reads the frozen splits snapshot and instructs the settlement layer in your ledger.