Health-system integration

NDC-to-cash-price API

Send an exact NDC, dispensed quantity, and either prescribed units per day or known days supply. Receive both cash-price rates with fees, source freshness and a patient verification link. No patient identifiers or API key are needed.

Endpoint and price field

POST https://price.blueberrypharmacy.com/api/v1/quotes · JSON · backend-to-backend.

Read prices.nonMember.total for the regular cash estimate in currency: "USD". prices.member.total is the existing-member comparison; it excludes membership purchase. These are estimates, not insurance adjudication, orders, guaranteed stock, or a guaranteed final charge.

Two quantity input modes

Use exactly one of dailyDose or daysSupply. These examples are illustrative integration inputs, not prescribing recommendations. Replace the NDC and inputs with your confirmed prescription values. Example product: Atorvastatin (generic Lipitor) 10 Mg Tab.

Quantity and prescribed units per day

curl --request POST 'https://price.blueberrypharmacy.com/api/v1/quotes' \
  --header 'Content-Type: application/json' \
  --data '{"ndc":"72205002299","quantity":90,"dailyDose":1}'

Quantity and known days supply

curl --request POST 'https://price.blueberrypharmacy.com/api/v1/quotes' \
  --header 'Content-Type: application/json' \
  --data '{"ndc":"72205002299","quantity":90,"daysSupply":90}'

EA fees use explicit daysSupply directly. In dose mode, EA fee days are quantity ÷ supplied dose, rounded to the nearest whole day (minimum 1). We do not manufacture a dose from supplied days.

Units and stock packages

dailyDose uses the same physical unit as quantity: tablets/count per day, mL/day or grams/day. It is not medication strength in mg or insulin clinical units. No strength-to-dose conversion is performed; prefer known daysSupply when your prescription dose uses different units.

Dispensed quantity is not automatically a package count
Catalog unitMeaningSupported quantity
eaCount of dispensing units, such as tablets1–10000
mlMilliliters0.001–10000; whole stock packages only
gmGrams0.001–10000; whole stock packages only

For GM/ML, quantity ÷ medication.packageSize must represent 1–100 whole packages. For a confirmed 10 mL vial, quantity 20 means 2 vials; quantity 15 is rejected, not rounded to 2 vials. A fractional amount such as 1.2 mL is valid for a confirmed 0.4 mL package (3 packages). Do not assume every injection is cataloged as mL; use the returned dispensing unit.

GM/ML fees preserve the existing package policy: 1 package uses 30 fee days; 2+ packages use a single 90-day fee. These fee days are not clinical days supply, even when the caller supplies a different days supply. Supplied clinical inputs are echoed separately. More than 3 packages may require additional service fees or membership.

Legacy GM/ML requests {"ndc":"NDC_FROM_CATALOG","packages":2} still work, without quantity, dose or days supply. Do not combine that mode with clinical or quantity fields.

Response interpretation

Current illustrative response excerpt

This excerpt is calculated from the current snapshot. Production responses additionally contain membership costs, exclusions, warnings, disclaimers and verification links; retain those fields in your integration.

{
  "currency": "USD",
  "medication": {
    "id": "72205002299",
    "ndc": "72205002299",
    "ndc11": "72205002299",
    "name": "Atorvastatin (generic Lipitor) 10 Mg Tab",
    "strength": "10 Mg",
    "form": null,
    "identityNote": "Strength/form are extracted only when explicit in the source name; null means unknown. Verify the full source name and NDC.",
    "packageSize": 1000,
    "dispensingUnit": "ea",
    "pricingPageUrl": "https://price.blueberrypharmacy.com/medications/72205002299"
  },
  "inputs": {
    "ndc": "72205002299",
    "quantity": 90,
    "daysSupply": 90
  },
  "normalizedInputs": {
    "ndc": "72205002299",
    "mode": "quantity",
    "quantity": 90,
    "quantityUnit": "ea",
    "stockPackages": 1,
    "suppliedDaysSupply": 90
  },
  "clinicalInputs": {
    "dailyDose": null,
    "daysSupply": 90,
    "source": "caller_supplied"
  },
  "prices": {
    "nonMember": {
      "total": 16.74,
      "medicationAndMarkup": 0.59,
      "includedFillAndSupplyFees": 16.15,
      "numberOfFills": 1
    },
    "member": {
      "total": 6.74,
      "medicationAndMarkup": 0.59,
      "includedFillAndSupplyFees": 6.15,
      "numberOfFills": 1
    }
  },
  "feeAssumptions": {
    "feeDays": 90,
    "isClinicalDaysSupply": true,
    "explanation": "Fee days use the caller-supplied daysSupply directly. No daily dose is inferred or recommended.",
    "medicationMarkupPercent": 8,
    "feeSchedule": "Up to 30 fee days: non-member $11.15 / member $4.15. 31–91: $16.15 / $6.15. EA >91 uses 90-day chunks plus remainder. GM/ML uses a single package-based fee."
  },
  "freshness": {
    "refreshedAt": "2026-10-15T06:17:46.636Z",
    "isStale": false,
    "source": "upstream",
    "refreshInProgress": false,
    "timestampMeaning": "Last successful retrieval of the source pricing feed; not a guarantee of when the pharmacy changed each price.",
    "warning": null
  }
}

Validation and errors

NDC must be an exact 11-digit or 5-4-2 identifier, including leading zeros. Ambiguous unsegmented 10-digit and malformed identifiers are rejected, never guessed or silently substituted. dailyDose: 0.001–1000 dispensing units/day. daysSupply: whole number 1–3650. Quantity/dose-derived days also cannot exceed 3650. Reject string-encoded numbers, missing/both timing fields, mixed package/quantity modes, extra fields and non-finite values.

HTTP status handling
StatusMeaning
200Estimate; still inspect freshness, exclusions and warnings.
400Invalid input, wrong mode, safety bound or unsupported partial-package quantity. Inspect error.code and error.message; malformed JSON may return a parser message.
404Unknown or unpriceable NDC; no prices, never a zero-price quote.
403Browser origin not approved; call through your backend.
413JSON exceeds 32 KB.
429Rate limit; honor Retry-After.
5xx / network failureNo usable quote. Do not substitute zero or reuse a cached price as current.

Error codes include invalid_input, quantity_mode_mismatch, quantity_out_of_range, unsupported_dispensing_quantity, medication_not_found and rate_limited. Errors contain no successful price estimate.

Lists, privacy and operational limits

POST /api/v1/quotes/batch accepts {"items":[...]} with 1–20 inputs using the same modes. Keep individual failures visible; if complete is false, totals is null. A successful-items subtotal is not a complete-list price. Totals round the sum of unrounded line estimates.

Public, read-only access currently has no partner credentials or patient identity fields. Extra patient data is rejected. Do not send names, identifiers, dates of birth, prescription documents or credentials. Native server-to-server clients normally omit Origin; third-party browser origins are not allowed. Application pricing logs omit medication inputs; infrastructure may still log URLs.

Limits: 240 requests/minute per network peer and 1200/minute per process, shared by API and MCP. Proxy clients may share a peer. These are local controls, not distributed quotas or an uptime/throughput guarantee. Honor 429 Retry-After and avoid automatic retry loops.

Excluded costs

Optional membership purchase: $18/quarter or $60/year, separate from medication estimates.

OpenAPI specification · MCP and agent guide · Pricing methodology