---
title: "Prescription defaults and previews"
description: "Prefill a prescription, customize directions, and preview shipping before creating an order."
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.affinityrx.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Prescription defaults and previews

Use prescribing options to build your form. Use an order preview to resolve defaults for a patient before creating an unsigned order.
These operations require an SDK version generated from the prescribing-options API contract. Keep your API key on your server.

## Medication images

Render `imageUrl` from a catalog item or the prescribing options' `catalog` object.
Affinity returns the primary product photo, or dosage-form artwork when no product photo exists.
If neither is available, `imageUrl` is `null`.
`imageUrls` contains product photos only; it does not include fallback artwork.
Your integration does not need to choose default images.

## When to call preview

For one-click defaults, call `orders.preview` after the user selects a product and patient.
Send the product ID and `preset: "default"`. Omit fields that Affinity should resolve.
Display the returned values and issues in your form.

For a patient with complete demographics, a delivery address, and reviewed allergy history, the normal flow is select patient, select medication, then review and sign/send. Keep customization optional. Configure the clinician once and supply their NPI when signing.
This flow requires a complete product preset. Affinity preserves its directions, resolves quantity and refills, calculates days supply where supported or uses the unchanged preset's days supply, and selects eligible shipping using the requested strategy. Missing clinical values remain explicit issues rather than guessed defaults.

For a completed form, send the entered values as explicit overrides.
Preview checks current product requirements, shipping eligibility, and estimated prices. It does not replace explicit values with defaults.
Call preview again after relevant edits if your form needs updated resolved values.
Preview is optional when your integration already supplies a complete order. Order creation performs its own validation.

Clinic currently loads `prescribing-options` when preparing prescription details and calculates supported days supply locally.
It calls `order-previews` once per patient order containing prescriptions, immediately before saving drafts from checkout.
Clinic does not call preview on every edit or use it to fill the whole form in one request.
An EMR can use preview earlier without waiting for this Clinic workflow to change.

Clinic and preview use the same days-supply calculation. They preserve pharmacy-provided defaults and manual overrides, and calculate from the selected dispense amount and complete directions when the units are comparable.
For pens, a total in mL does not establish the number of pens. Automatic pen-based days supply requires an explicit quantity in pens or catalog package contents per pen. Strength selection remains separate from dispense quantity.

## Understand a complete result

`status: "complete"` means that the resolved input passed draft preparation checks at the time of the request.
It does not mean that Affinity verified the regimen's clinical appropriateness or calculated every supplied value.

- `daysSupplySource: "manual"` means Affinity preserved the days supply you submitted.
- As-needed directions with a fixed dose and frequency can resolve days supply. For example, 30 troches with directions to use 1 troche once daily as needed resolves to 30 days at that frequency. Actual use may be lower. An explicit maximum daily amount takes precedence; directions without a usable frequency or maximum require manual days supply or an unchanged preset with days supply.
- A quantity of one vial does not establish days supply without sufficient dose, volume, and schedule information.
- Default presets retain their structured dosing fields when available. Explicit free-text overrides remain free text. A complete, unambiguous regimen can support days-supply arithmetic without replacing the supplied directions or adding structured dosing fields. Review the complete returned `directions`, including any additional instructions.
- Medication and shipping amounts are estimates, not a payment or a guaranteed final order total.

For example, a completed form with quantity, days supply, refills, SIG, and shipping mainly uses preview for validation and pricing.
The default-resolution benefit appears when the request omits those fields.

## Apply defaults

Select an existing patient or supply inline patient details. Test mode requires synthetic patient data.

```typescript
const preview = await affinity.forPractice(practiceId).orders.preview({
  patientId,
  prescriptions: [{ medicationId: catalogItemId, preset: "default" }],
  shipping: { selection: "lowest_cost" },
});

if (preview.status === "incomplete") {
  // Show each issue beside its field. Nothing has been created.
  return { issues: preview.issues, prescriptions: preview.prescriptions };
}

// Display the resolved prescription and shipping selection for review.
// After the user accepts these exact values:
const { practiceId: resolvedPracticeId, ...params } = preview.orderInput;
const order = await affinity.forPractice(resolvedPracticeId).orders.create(params, {
  idempotencyKey: persistedOrderCreationKey,
});
```

A complete preview passes draft preparation checks at that moment. It does not establish signing authority or guarantee pharmacy acceptance.
Order creation validates current requirements again. Signing requires the clinician's attestation and every exact prescription version.

### Preview before creating a patient

Supply exactly one of `patientId`, `patientExternalId`, or `patient`.
`patientExternalId` resolves your integration's patient identity within the selected practice and mode. It requires `patients:read`.
An unknown external ID returns `404`; use inline details to preview a new patient.

```ts
const preview = await affinity.forPractice(practiceId).orders.preview({
  patient: {
externalId: "synthetic-emr-patient-123",
name: { first: "Synthetic", last: "Patient" },
dateOfBirth: "1990-01-01",
email: "patient@example.test",
phone: "+12025550199",
address: {
  line1: "100 Test St",
  city: "Austin",
  state: "TX",
  postalCode: "78701",
  country: "US",
},
  },
  prescriptions: [{ medicationId, preset: "default" }],
  shipping: { selection: "lowest_cost" },
});
```

Inline details require `patients:write`, but preview creates no patient, address, or external-identity records.
Matching external identities use stored demographics and delivery addresses, not submitted replacements. Conflicting identifiers return `409`.
A complete preview returns either the resolved `patientId` or the new inline `patient` in `orderInput`.
Order creation resolves the identity again and creates any new patient atomically with the draft.
Do not supply saved address IDs for a new patient.

## Build a custom form

```typescript
const options = await affinity.catalog.prescribingOptions.get(catalogItemId, {
  practiceId,
});
```

The response contains the preferred preset, alternative directions, guided templates, quantity constraints, product requirements, and a revision.
Defaults come from reviewed Affinity directions or a single complete, compatible pharmacy regimen. When the pharmacy supplies several regimens, show them as choices; do not select the first. A reviewed Affinity default takes precedence. Missing clinical values remain empty.
Cache options by practice, mode, and catalog item. Use the revision to detect changes. Do not share patient previews between users or practices.

Supply `expectedRevision` to require the same options during the next preview.

```typescript
const preview = await affinity.forPractice(practiceId).orders.preview({
  patientId,
  shippingAddressId,
  prescriptions: [
{
  medicationId: catalogItemId,
  preset: options.defaultPresetId ?? undefined,
  expectedRevision: options.revision,
  overrides: {
    sig: {
      format: "free_text",
      text: clinicianEnteredDirections,
    },
    quantity: clinicianSelectedQuantity,
    daysSupply: clinicianEnteredDaysSupply,
    refills: clinicianSelectedRefills,
    dispensing: {
      shippingOptionId: selectedShippingOptionId,
      substitutionPermitted: false,
    },
  },
},
  ],
});
```

Explicit overrides take precedence. Set quantity or days supply to `null` to clear the field. Omit an override to use automatic resolution.
When a regimen changes, days supply is recalculated only when the units and schedule support the calculation.
An explicit days-supply value remains unchanged. Pharmacy limits still apply.

## Dispense quantity and packages

Use `quantityConstraint` for the permitted dispense quantities and units. Strength, patient dose,
dispense quantity, physical packaging, and price basis are separate facts.

For example, a pen product offered at `0.8`, `1.6`, `2.4`, `3.2`, and `4 mL` supplies choices for
total dispense volume. Selecting `1.6 mL` does not establish one pen or a volume per pen. Show
**Dispense volume** and transmit `1.6` in the catalog's dispense unit. A different strength requires
a different catalog selection.

`catalogDetails.packageComponents`, when present, supplies recorded container counts and contents
per container. Only show a container-count control when those facts establish the conversion and
every offered quantity remains valid. For example, two confirmed `1 mL` vials correspond to a
`2 mL` dispense quantity. Multi-component kits keep their package identity. Do not infer container
contents from a price basis, quantity increment, product photo, or the instruction “Inject one pen.”

Show prices using the returned `priceBasis`. A price per item is not a price per mL. Use preview
for the medication total after a quantity change.

## Compounding reasons

Use the typed `CompoundingReason` constants from the TypeScript SDK.
`catalog.prescribingOptions.get` returns accepted categories and context requirements for the selected medication.

```ts
import { CompoundingReason } from "@affinity-health/sdk";

const clinical = {
  compoundingReason: {
category: CompoundingReason.ConcentrationAdjustment,
// Include context when the medication requires a patient-specific explanation.
  },
};
```

Pass `clinical` in preview overrides or directly on a prescription in `orders.create`.
The clinician must select a category accepted for the medication. Do not preselect a clinical reason from medication defaults.
See [Compounding reasons](/guides/compounding-reasons/) for typed choices, context prompts, pharmacy translation, and a complete order example.

## Directions formats

- `structured`: Supply `fields` with dose, dose unit, route, frequency, and optional regimen details.
- `template`: Supply `templateId`, `templateRevision`, and values for the selected pattern's placeholders.
- `free_text`: Supply the complete directions in `text`.

Always show the returned `directions` for review. The response includes structured fields only when they faithfully represent the directions.
Tapers and other complex instructions remain free text. Product strength never supplies an assumed patient dose.
Do not infer a diagnosis, allergy review, or patient-specific compounding rationale from defaults.

## Prescriber selection

Drafts can remain unassigned. Add `prescriber: { npi: "1234567893" }` to a Test preview or order creation to attribute the draft.
Alternatively, supply `prescriber` when calling `orders.signAndSubmit`. Signing inherits the prescriber when the draft already has one.
Use exactly one selector: `{ npi }`, `{ id }` with an Affinity provider ID, or `{ externalId }` with your registered integration identity.
Preview carries this selection into `orderInput` without creating a prescriber. Creation or signing resolves the identity.
First-use registration requires `team:write`; NPI selection does not restore revoked access or authenticate a clinician.
Legacy `userId` remains supported, but cannot be combined with `prescriber`.

## Shipping and prices

Previews use the patient's selected delivery address. Set `shippingAddressId` to select a saved address.
Shipping must match the product, destination, temperature requirements, and mode.

- `manual` selects the only eligible service, or asks for a selection when several services exist.
- `lowest_cost` selects the eligible service with the lowest published cost.
- `fastest` selects the eligible service with the shortest known maximum transit time, with cost breaking ties.

An explicit shipping option overrides the selection preference. An ineligible explicit option produces an issue instead of a replacement.
`shippingGroups` combines delivery estimates within one patient order by pharmacy, exact shipping option, temperature, and destination. Two services labeled Ground can have different identifiers and must not be combined by label or speed. Ambient and refrigerated prescriptions remain separate groups.
Each group includes `prescriptionIndexes`, zero-based positions in the returned `prescriptions` array. Use these positions instead of medication IDs because an order can contain more than one prescription for the same medication. Treat the group `key` as opaque and preview-scoped, not as a shipment ID.
Display `totals.shippingTotalCents` as the order shipping estimate. Do not sum the individual prescriptions' `shippingAmountCents`, which can repeat a shared group rate.
Shipping charge groups are not a promise of one physical package. Pharmacy transmission groups and actual shipments can differ. Compatible Pharmetika prescriptions can be transmitted in one medication-order request; differing shipping or order-level clinical context requires separate requests. A successful submission response is not pharmacy acceptance or shipment confirmation.
`totals` includes medication, supply, shipping, and estimated order totals. Unavailable prices produce null totals instead of zero prices.
Line prices are estimates. A preview does not reserve prices, charge a payment method, or transmit an order.

Preview includes the selected customer shipping rate in each prescription's `orderInput.dispensing.shippingAmountCents`.
Pass `preview.orderInput` unchanged to `orders.create` after review. This field is a rate assertion, not a custom price.
Draft creation rejects a changed rate with `409`. If omitted on direct creation, the server records the current rate.
Signing and submission recheck the recorded rate. A changed or missing rate requires a refreshed draft and renewed review and signing.
Existing signed orders with no recorded rate must also be refreshed and signed again before submission.
Read prices from the API instead of hard-coding the standard Ground, 2-Day, or Overnight prices.
Changing a priced fulfillment's service or destination requires support to reconcile billing.

## Add supplies and OTC items

Supplies use the same catalog as prescriptions. Filter `catalog.items.list` with `catalogKind: "otc"` to find them.
Read each item's `ordering` requirements. Currently, PerfectRx supplies require an accompanying PerfectRx prescription in the same patient order.
They attach to that prescription's shipment without a separate delivery charge. Standalone OTC orders are not supported.

```ts
const preview = await affinity.forPractice(practiceId).orders.preview({
  patientId,
  prescriptions: [{ medicationId, preset: "default" }],
  otcItems: [{ catalogItemId: supplyId, quantity: 1 }],
  shipping: { selection: "lowest_cost" },
});

if (preview.status === "complete") {
  // Review prescriptions, supplies, shipping groups, and totals before creating the draft.
  const { practiceId: resolvedPracticeId, ...params } = preview.orderInput;
  const order = await affinity.forPractice(resolvedPracticeId).orders.create(params, {
idempotencyKey: crypto.randomUUID(),
  });
}
```

`otcItems` is optional on preview, order creation, and each patient order in a batch.
Use whole-number quantities from 1 to 100, with at most 20 distinct supply items per order.
Order responses include purchased supplies. Retrieved orders identify the prescription carrying each supply item.
Do not add a purchased supply merely because the pharmacy includes it automatically with a prescription.

## Endpoints

`GET /v1/catalog/items/{catalogItemId}/prescribing-options` requires `catalog:read`.

`POST /v1/order-previews` requires `orders:write` and `catalog:read`. It accepts 1–20 prescriptions for one patient, identified by ID, external ID, or inline details.
It does not require an idempotency key because it creates no persistent order or preview resource.

## Pharmacy clinical requirements

Read `catalog.prescriptionRequirements` from prescribing options. Do not branch on pharmacy names.
Affinity combines documented pharmacy requirements with requirements for the selected product.

| Requirement                    | Meaning                                                        |
| ------------------------------ | -------------------------------------------------------------- |
| `diagnosis: "required"`        | Supply at least one ICD-10-CM diagnosis for this prescription. |
| `diagnosisReview: "required"`  | Supply diagnoses or explicitly confirm no known diagnoses.     |
| `medicationReview: "required"` | Supply current medications or explicitly confirm none.         |

An omitted review requirement is optional. Supplied clinical information is still sent through supported pharmacy mappings.
Allergy review remains required for every pharmacy before signing.
A pharmacy request for additional information does not automatically make an actual diagnosis mandatory for every product.

Send reviews in each prescription's `clinical` object. Reuse the patient's reviewed medication list across prescriptions in that order.
Keep diagnoses specific to each prescription. An empty list without a review status means the information was not reviewed.

```json
{
  "clinical": {
"currentMedications": [],
"medicationReviewStatus": "none",
"diagnoses": [],
"diagnosisReviewStatus": "none"
  }
}
```

For populated lists, use `"recorded"`. Existing integrations that supply populated lists may omit the review status.
Do not send `"none"` alongside populated lists. Use the patient allergies endpoint to record allergies or `reviewStatus: "no_known"`.

Preview returns `clinicalRequirements`, `clinicalIssues`, and `clinicalRequirementsSatisfied` separately from draft preparation issues.
A `"complete"` preview can produce a saveable draft while `clinicalRequirementsSatisfied` is `false`.
The clinical flag does not establish signing authority, billing readiness, or Live eligibility.

```json
{
  "status": "complete",
  "clinicalRequirementsSatisfied": false,
  "clinicalRequirements": [
{
  "field": "prescriptions.0.clinical.medicationReviewStatus",
  "label": "Current medications",
  "type": "medication_review",
  "required": true,
  "status": "missing"
}
  ],
  "clinicalIssues": [
{
  "code": "medication_review_required",
  "path": "prescriptions.0.clinical.medicationReviewStatus",
  "message": "Review current medications or confirm the patient takes none."
}
  ]
}
```

This example shows only the clinical portion of the preview response.
Affinity rechecks current requirements before signing and transmission, including queued pharmacy submissions.
A missing clinical requirement returns HTTP `422` with `code: "clinical_requirements_unmet"`.
Read the issues in the problem response's `data.issues` array. Signing issues include the affected `prescriptionId` and pharmacy name.
Use issue codes and paths for application logic. Show messages beside the affected fields.
After changing a signed prescription, review and sign its new version before submitting it.

Integrations need an SDK generated from this contract to use the new review fields and typed preview results.
Subsequent pharmacy changes using these supported requirements do not require pharmacy-specific code.
Notify integration operators before activating a newly mandatory requirement. Treat a new input type as an API and SDK change.

### When to request requirements

Fetch prescribing options when the user selects a medication. Use `catalog.prescriptionRequirements` to mark required fields. Call `POST /v1/order-previews` before saving or signing to validate the assembled order. Requirements can change, so always handle signing errors even after a successful preview.

The Clinic dashboard fetches prescribing options when opening a selected medication. It checks fields locally while editing and calls order preview during **Save draft** or **Sign & send**, once per patient. Incomplete clinical reviews can be saved as drafts; signing requires them to be completed.

Source: https://docs.affinityrx.com/guides/prescribing-defaults/index.mdx
