Requires API key

Add Formulary Checking to Your Prescribing Workflow

Your telehealth app needs to check drug coverage before the provider writes the prescription. This guide walks through looking up formulary data, checking step therapy requirements against a patient's medication history, and parsing the result into a clear prescribing decision.

Estimated integration time: 20 minutes. The formulary lookup endpoint is free and unauthenticated. The readiness check requires an API key -- use a sandbox key (tln_test_) while developing.

1

Look up formulary data

The GET /api/v1/formulary endpoint is free and does not require authentication. It returns tier, prior auth requirements, step therapy drugs, quantity limits, and clinical criteria for a payer + drug combination.

curl
curl "https://talonapi.dev/api/v1/formulary?payer=aetna&drug=humira"
Key fields in the response
{
  "formulary": [
    {
      "payer_name": "Aetna",
      "drug_name": "Humira",
      "generic_name": "adalimumab",
      "formulary_tier": "specialty",
      "prior_auth_required": true,
      "step_therapy_required": true,
      "step_therapy_drugs": [
        { "drug": "methotrexate", "status": "must_have_tried" },
        { "drug": "sulfasalazine", "status": "must_have_tried" }
      ],
      "quantity_limit": "2 pens per 28 days",
      "clinical_criteria": "Diagnosis of RA, PsA, or Crohn disease with documented failure of conventional DMARDs"
    }
  ]
}

If step_therapy_required is true, the patient must have tried (and failed) the listed drugs before the payer will approve this one. This is the key piece of information for the prescribing workflow.

2

Check step therapy requirements

Before submitting a readiness check, review the step therapy drugs from the formulary response. Each entry in step_therapy_drugs has a status field:

must_have_tried -- The patient must have a documented trial of this drug before the target drug can be approved.

preferred_alternative -- The payer prefers this drug but it is not a hard requirement. Documenting why it was not used strengthens the case.

Map each step therapy drug against the patient's medication history from your EHR. Build an array of medication history objects:

Building the medication history
// From your EHR's medication records
const medicationHistory = [
  {
    drug: "methotrexate",
    status: "failed",
    reason: "Inadequate response after 12 weeks at max tolerated dose"
  },
  {
    drug: "sulfasalazine",
    status: "failed",
    reason: "Discontinued due to GI intolerance after 4 weeks"
  }
];
Tip
Valid status values are "failed", "intolerant", "contraindicated", and "current". Always include a reason -- the check uses it to evaluate whether the trial was adequate.
3

Submit the formulary readiness check

Post the payer, drug, and medication history to POST /api/v1/formulary/check. This endpoint requires an API key.

curl
curl -X POST "https://talonapi.dev/api/v1/formulary/check" \
  -H "X-API-Key: tln_test_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "payer": "Aetna",
    "drug_name": "Humira",
    "patient_medication_history": [
      {
        "drug": "methotrexate",
        "status": "failed",
        "reason": "Inadequate response after 12 weeks"
      },
      {
        "drug": "sulfasalazine",
        "status": "failed",
        "reason": "GI intolerance after 4 weeks"
      }
    ]
  }'
4

Parse the prescribing verdict

The response gives you a clear answer and the details to act on:

Response -- all steps completed
{
  "covered": true,
  "prior_auth_required": true,
  "step_therapy_required": true,
  "step_therapy_status": {
    "steps_required": [
      { "drug": "methotrexate", "status": "must_have_tried" },
      { "drug": "sulfasalazine", "status": "must_have_tried" }
    ],
    "steps_completed": ["methotrexate", "sulfasalazine"],
    "steps_remaining": []
  },
  "quantity_limits": "2 pens per 28 days",
  "ready_to_prescribe": true,
  "recommendation": "All step therapy requirements satisfied. Prior authorization required -- submit with documentation of failed methotrexate and sulfasalazine trials.",
  "metadata": {
    "source": "Aetna Formulary",
    "last_verified": "2026-02-20T00:00:00.000Z"
  }
}

When steps remain, the response looks different:

Response -- steps remaining
{
  "covered": true,
  "prior_auth_required": true,
  "step_therapy_required": true,
  "step_therapy_status": {
    "steps_required": [
      { "drug": "methotrexate", "status": "must_have_tried" },
      { "drug": "sulfasalazine", "status": "must_have_tried" }
    ],
    "steps_completed": ["methotrexate"],
    "steps_remaining": [
      { "drug": "sulfasalazine", "action": "Trial of sulfasalazine required before Humira" }
    ]
  },
  "ready_to_prescribe": false,
  "recommendation": "Step therapy required: complete trial of sulfasalazine before requesting Humira."
}

ready_to_prescribe -- Boolean. If false, the provider should not prescribe yet.

steps_remaining -- Array of drugs the patient still needs to try, each with a human-readable action string you can show directly in the UI.

recommendation -- A plain-English summary suitable for displaying to the prescribing provider.

5

Complete TypeScript integration

A full prescribing workflow function that combines the lookup and check:

TypeScript — checkFormulary.ts
const TALON_BASE = "https://talonapi.dev";

interface MedHistory {
  drug: string;
  status: "failed" | "intolerant" | "contraindicated" | "current";
  reason: string;
}

interface FormularyResult {
  covered: boolean;
  ready_to_prescribe: boolean;
  prior_auth_required: boolean;
  steps_remaining: { drug: string; action: string }[];
  recommendation: string;
  quantity_limits: string | null;
}

export async function checkFormulary(
  apiKey: string,
  payer: string,
  drugName: string,
  medHistory: MedHistory[]
): Promise<FormularyResult> {
  // 1. Quick lookup (free, no auth needed)
  const lookupRes = await fetch(
    `${TALON_BASE}/api/v1/formulary?payer=${encodeURIComponent(payer)}&drug=${encodeURIComponent(drugName)}`
  );
  if (!lookupRes.ok) {
    throw new Error(`Formulary lookup failed: ${lookupRes.statusText}`);
  }
  const lookupData = await lookupRes.json();

  if (lookupData.count === 0) {
    return {
      covered: false,
      ready_to_prescribe: false,
      prior_auth_required: false,
      steps_remaining: [],
      recommendation: `${drugName} not found in ${payer}'s formulary. Consider an alternative or submit an exception request.`,
      quantity_limits: null,
    };
  }

  // 2. If no step therapy, shortcut
  const entry = lookupData.formulary[0];
  if (!entry.step_therapy_required && !entry.prior_auth_required) {
    return {
      covered: true,
      ready_to_prescribe: true,
      prior_auth_required: false,
      steps_remaining: [],
      recommendation: `${drugName} is covered with no restrictions. Proceed with prescribing.`,
      quantity_limits: entry.quantity_limit,
    };
  }

  // 3. Full readiness check
  const checkRes = await fetch(`${TALON_BASE}/api/v1/formulary/check`, {
    method: "POST",
    headers: {
      "X-API-Key": apiKey,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      payer,
      drug_name: drugName,
      patient_medication_history: medHistory,
    }),
  });
  if (!checkRes.ok) {
    const err = await checkRes.json();
    throw new Error(`Formulary check failed: ${err.error?.message ?? checkRes.statusText}`);
  }
  const data = await checkRes.json();

  return {
    covered: data.covered,
    ready_to_prescribe: data.ready_to_prescribe,
    prior_auth_required: data.prior_auth_required,
    steps_remaining: data.step_therapy_status?.steps_remaining ?? [],
    recommendation: data.recommendation,
    quantity_limits: data.quantity_limits,
  };
}

// Usage
const result = await checkFormulary(
  "tln_test_abc123",
  "Aetna",
  "Humira",
  [
    { drug: "methotrexate", status: "failed", reason: "Inadequate response after 12 weeks" },
    { drug: "sulfasalazine", status: "intolerant", reason: "GI side effects" },
  ]
);

if (result.ready_to_prescribe) {
  console.log("Ready to prescribe.", result.recommendation);
} else {
  console.log("Not ready:", result.steps_remaining);
}
6

Python equivalent

Python — check_formulary.py
import requests
from dataclasses import dataclass, field

TALON_BASE = "https://talonapi.dev"


@dataclass
class FormularyResult:
    covered: bool
    ready_to_prescribe: bool
    prior_auth_required: bool
    steps_remaining: list[dict] = field(default_factory=list)
    recommendation: str = ""
    quantity_limits: str | None = None


def check_formulary(
    api_key: str,
    payer: str,
    drug_name: str,
    med_history: list[dict],
) -> FormularyResult:
    # 1. Free formulary lookup
    lookup_res = requests.get(
        f"{TALON_BASE}/api/v1/formulary",
        params={"payer": payer, "drug": drug_name},
    )
    lookup_res.raise_for_status()
    lookup_data = lookup_res.json()

    if lookup_data["count"] == 0:
        return FormularyResult(
            covered=False,
            ready_to_prescribe=False,
            prior_auth_required=False,
            recommendation=f"{drug_name} not found in {payer}'s formulary.",
        )

    entry = lookup_data["formulary"][0]
    if not entry["step_therapy_required"] and not entry["prior_auth_required"]:
        return FormularyResult(
            covered=True,
            ready_to_prescribe=True,
            prior_auth_required=False,
            recommendation=f"{drug_name} is covered with no restrictions.",
            quantity_limits=entry.get("quantity_limit"),
        )

    # 2. Full readiness check
    check_res = requests.post(
        f"{TALON_BASE}/api/v1/formulary/check",
        headers={"X-API-Key": api_key},
        json={
            "payer": payer,
            "drug_name": drug_name,
            "patient_medication_history": med_history,
        },
    )
    check_res.raise_for_status()
    data = check_res.json()

    return FormularyResult(
        covered=data["covered"],
        ready_to_prescribe=data["ready_to_prescribe"],
        prior_auth_required=data["prior_auth_required"],
        steps_remaining=data.get("step_therapy_status", {}).get("steps_remaining", []),
        recommendation=data["recommendation"],
        quantity_limits=data.get("quantity_limits"),
    )


# Usage
result = check_formulary(
    api_key="tln_test_abc123",
    payer="Aetna",
    drug_name="Humira",
    med_history=[
        {"drug": "methotrexate", "status": "failed", "reason": "Inadequate response after 12 weeks"},
        {"drug": "sulfasalazine", "status": "intolerant", "reason": "GI side effects"},
    ],
)

if result.ready_to_prescribe:
    print("Ready to prescribe.", result.recommendation)
else:
    for step in result.steps_remaining:
        print(f"Remaining: {step['drug']} -- {step['action']}")
7

Tips for production

Warning
Handle "not found" drugs. If the formulary lookup returns count: 0, the drug is not in Talon's database for that payer. Show the provider a "coverage unknown" state and suggest they verify with the payer directly or submit a formulary exception request.
Tip
Build a UI around step therapy status. Use steps_completed and steps_remaining to render a progress indicator. Providers appreciate seeing exactly where the patient is in the step therapy sequence at a glance.
Tip
Cache the formulary lookup. The GET /api/v1/formulary endpoint is free. Cache the result for 24 hours to speed up repeat lookups for the same drug.
Tip
Show quantity limits early. Display the quantity_limits field alongside the prescribing form so the provider writes a compliant quantity from the start, avoiding pharmacy rejections.
Tip
Try NDC codes for precision. If your EHR stores NDC codes, use the ndc parameter instead of drug for exact matches. Drug name matching is fuzzy and may return multiple results.