Handling Reject Code 75: Prior Authorization Required
Reject code 75 is the one coverage reject that is not a dead end — it tells the pharmacy the drug is coverable, but only behind a prior-authorization gate that has not yet been satisfied. Where 70 Product/Service Not Covered closes the door, 75 opens a workflow: it signals that the plan will pay for this GPI once a PA is approved, or once the member completes a step-therapy sequence, so the pharmacist knows to initiate prior-authorization intake rather than send the member away. Emitting 75 correctly is therefore a routing decision as much as a coverage decision — the code has to fire only when there is a genuine PA path forward, and it has to carry the claim into the Prior Authorization Routing Automation pipeline. This guide, part of the NCPDP Reject Code Reference, specifies the trigger conditions and the Python handler that emits 75 and hands off to PA.
The Exact Decision
75 fires when a claim clears eligibility and formulary coverage but hits a gate the member has not passed. There are two distinct triggers behind the single code. The first is a PA-required drug: the GPI is flagged in the formulary as requiring prior authorization outright — common for specialty agents, high-cost biologics, and drugs with narrow approved indications. The second is unsatisfied step therapy: the GPI is coverable without a standing PA, but the plan requires the member to have tried and failed one or more preferred agents first, and the Step Therapy & Prior Auth Trigger Rules evaluation found the sequence incomplete. Both produce 75, but the handler tags which trigger fired so the PA workflow knows whether it is opening a clinical-review case or a step-therapy exception.
The disambiguation that matters most is 75 versus 70: the difference is whether a PA path exists at all. The table encodes the boundaries.
| Symptom on the claim | Correct code | Why not 75 |
|---|---|---|
| GPI requires prior authorization, none on file | 75 Prior Authorization Required |
This is the canonical 75 case |
| GPI coverable but step therapy incomplete | 75 Prior Authorization Required |
PA/exception path exists; sequence unmet |
| GPI is excluded from the formulary | 70 Product/Service Not Covered |
No PA path exists; the door is closed |
| GPI covered, no gate, quantity too high | 76 Plan Limitations Exceeded |
Coverable now; only the amount is wrong |
| An approved PA is already on file for this member+GPI | (pass) | The gate is satisfied; do not re-reject |
| A DUR safety edit hard-stops the claim | 88 DUR Reject Error |
Clinical safety, not a PA gate |
The operating rule the handler encodes: 75 means “coverable, but gated, and a path forward exists.” If no path exists it is 70; if the gate is already satisfied by an approved PA the claim passes; if the block is a hard clinical-safety edit it is 88, not 75.
Step-by-Step Implementation
The handler runs after coverage confirms the GPI is on formulary. It checks for an existing approved PA, then evaluates the PA-required flag and the step-therapy verdict, and on a gate miss it emits 75 and routes into intake.
1. Check for an existing approved PA first. A member+GPI with an active, in-window PA on file has already cleared the gate — passing this check must short-circuit before any 75 is raised, or the engine re-rejects an already-authorized fill.
2. Evaluate the PA-required flag from the versioned formulary snapshot. If the GPI is flagged PA-required and no approval exists, that is a 75 on the pa_required trigger.
3. Consult the step-therapy verdict. If step therapy is required and the sequence is unmet, that is a 75 on the step_therapy trigger. A satisfied or not-applicable sequence does not raise 75.
4. Build the 511-FB response and route to intake. Set 501-F1 Header Response Status to R, attach 511-FB = "75", and emit a routing envelope carrying the tokenized reference and the trigger tag into Prior Authorization Routing Automation.
5. Log the outcome PHI-safely. Only the tokenized 402-D2 reference, the 511-FB code, and the trigger reach the logger.
import json
import logging
import enum
from typing import Optional
from pydantic import BaseModel, ConfigDict
logging.basicConfig(format="%(message)s", level=logging.INFO)
logger = logging.getLogger("reject_75")
class PATrigger(str, enum.Enum):
NONE = "none"
PA_REQUIRED = "pa_required"
STEP_THERAPY = "step_therapy"
class StepVerdict(str, enum.Enum):
NOT_APPLICABLE = "not_applicable"
SATISFIED = "satisfied"
UNMET = "unmet"
class Reject75Input(BaseModel):
model_config = ConfigDict(frozen=True, extra="forbid")
gpi: str # resolved GPI (coverage already confirmed)
claim_ref: str # tokenized 402-D2, non-PHI
pa_required: bool # PA-required flag from formulary snapshot
approved_pa_on_file: bool # active, in-window PA for member+GPI
step_verdict: StepVerdict # from step-therapy evaluation
class Reject75Result(BaseModel):
status: str # "PASS" or "REJECT"
reject_511fb: Optional[str] = None
trigger: PATrigger = PATrigger.NONE
route: Optional[str] = None
def handle_reject_75(inp: Reject75Input) -> Reject75Result:
# 1. An approved PA already clears the gate -> never re-reject.
if inp.approved_pa_on_file:
result = Reject75Result(status="PASS")
# 2. PA-required drug, no approval on file.
elif inp.pa_required:
result = Reject75Result(
status="REJECT", reject_511fb="75", # 501-F1 = R downstream
trigger=PATrigger.PA_REQUIRED, route="pa_intake",
)
# 3. Step therapy required but the sequence is unmet.
elif inp.step_verdict is StepVerdict.UNMET:
result = Reject75Result(
status="REJECT", reject_511fb="75",
trigger=PATrigger.STEP_THERAPY, route="pa_intake",
)
else:
result = Reject75Result(status="PASS")
# PHI GUARDRAIL: tokenized ref + 511-FB + trigger only. Never 302-C2
# Cardholder ID, 310-CA Patient Name, prescriber PHI, or raw claim bytes.
logger.info(json.dumps({
"event": "reject_75_eval",
"claim_ref": inp.claim_ref,
"reject_511fb": result.reject_511fb,
"trigger": result.trigger.value,
"route": result.route,
}))
return resultThe handler is a pure function of its input contract, so it is thread-safe and replayable against the formulary snapshot and step verdict that were live at fill time. The approved_pa_on_file short-circuit is the single most important line: a race where an approval lands between two retries must resolve to a pass, not a stale 75, which is exactly the concern addressed in Resolving PA Pend Race Conditions.
Figure: An approved PA short-circuits to a pass; a PA-required flag or unmet step therapy yields 75 and routes into intake.
Verification and Testing Pattern
Test each trigger and, critically, the approved-PA short-circuit that must never re-reject an authorized fill.
import pytest
def _inp(**kw):
base = dict(gpi="6410001000XXYY", claim_ref="tok-xyz",
pa_required=False, approved_pa_on_file=False,
step_verdict=StepVerdict.NOT_APPLICABLE)
base.update(kw)
return Reject75Input(**base)
def test_pa_required_rejects_75():
r = handle_reject_75(_inp(pa_required=True))
assert r.reject_511fb == "75" and r.trigger is PATrigger.PA_REQUIRED
assert r.route == "pa_intake"
def test_unmet_step_therapy_rejects_75():
r = handle_reject_75(_inp(step_verdict=StepVerdict.UNMET))
assert r.reject_511fb == "75" and r.trigger is PATrigger.STEP_THERAPY
def test_approved_pa_passes_even_if_flagged():
# The short-circuit must win over the PA-required flag.
r = handle_reject_75(_inp(pa_required=True, approved_pa_on_file=True))
assert r.status == "PASS" and r.reject_511fb is None
def test_satisfied_step_passes():
r = handle_reject_75(_inp(step_verdict=StepVerdict.SATISFIED))
assert r.status == "PASS"test_approved_pa_passes_even_if_flagged is the load-bearing case: it pins that an on-file approval overrides the PA-required flag, the exact behavior that prevents a re-adjudicated claim from bouncing a member who already has authorization.
Gotchas and PHI Guardrails
- The approved-PA check must come first. Ordering the PA-required flag before the on-file check re-rejects authorized members on every retry. Evaluate
approved_pa_on_filebefore anything else. 75requires a real path forward. Never emit75for a formulary-excluded drug just because it looks high-cost — an exclusion is70, and sending a70case into PA intake floods the queue with claims that can never be approved.- Step-therapy
75versus a hard clinical stop. An unmet step sequence is a75(exception path exists); a drug-drug interaction or dose-safety hard-stop is88DUR Reject Error, which has no PA remedy. Keep them separate. - Tag the trigger. The PA workflow behaves differently for a standing PA-required drug versus a step-therapy exception; carrying the
PATriggertag lets intake open the right case type instead of guessing. - Watch the pend race. An approval landing mid-adjudication can produce a spurious
75; resolve on the tokenized reference as an idempotency key and reconcile via Resolving PA Pend Race Conditions. - Log only tokens and codes. The routing envelope and every log line carry the tokenized
402-D2reference, the511-FBcode, and the trigger — never302-C2Cardholder ID,310-CAPatient Name,411-DBprescriber identity, or raw claim bytes.
For the standard field and reject-code definitions this handler relies on, consult the official NCPDP Standards documentation.
Related
- NCPDP Reject Code Reference — the registry and dispatcher that rank
75against coverage and plan-limit codes. - Step Therapy & Prior Auth Trigger Rules — the clinical evaluation that produces the unmet-sequence trigger behind
75. - Prior Authorization Routing Automation — the intake pipeline every
75reject routes into. - Handling Reject Code 70: Product/Service Not Covered — the no-path-forward case
75must not absorb. - Handling Reject Code 76: Plan Limitations Exceeded — the sibling handler for coverable drugs blocked only on quantity or days supply.
← Back to NCPDP Reject Code Reference