A create request that is perfectly well-formed can still be refused, because most of what decides whether a listing is allowed lives in data rather than in the shape of your request: flags on the drug, settings on the selling pharmacy, and the pharmacy’s state. Two consequences worth designing around:

The same request can pass and fail

Identical payloads for two of your pharmacies can get different answers, because the rules key off the seller. State restrictions in particular follow the seller’s shipping address.

The rules move

Blocked lots are added automatically when a buyer reports a shipment damaged or warm, and the certification thresholds are admin settings. Treat all of this as a live answer, not a table to cache.

Four rules v1 cannot satisfy

These are hard stops, not validation noise. There is no field in the v1 contract that satisfies them, so no retry and no payload change will get the listing through.
Route these to a message telling the pharmacist to complete the listing in the InStockRx web interface, where the certification upload and the scanner are available. Showing the raw error leaves them with an instruction they cannot act on.Everything else on this page is worth surfacing directly — the messages are written to be read by a pharmacist.

Driven by the NDC

Flags carried on the drug package. They apply to every pharmacy.

How the certification cadence works

Two admin settings drive it: a price threshold and a cadence count.
  • At or below the threshold, a listing is never gated and never counted.
  • Above it, with a cadence of N, at most N − 1 consecutive uncertified listings are allowed for that pharmacy and NDC before the next one must be certified. N = 1 means every above-threshold listing needs certification.
  • With no cadence set, the pharmacy needs at least one certified listing for that NDC before it can create uncertified above-threshold ones.
Both settings can change, and the count is per pharmacy and NDC, so whether a given listing needs certification is a live question. There is no public endpoint to ask it ahead of time in v1 — the web interface uses an internal one to grey out the form before submission, and exposing that on the public API is planned rather than available.

Driven by the selling pharmacy

Driven by the pharmacy’s state

Some states restrict selling partial, unsealed, non-original or torn-label packages. This keys off the seller’s shipping address, so the same request can pass for one of your pharmacies and fail for another.
On 500114 the message text is configured per state rather than fixed. Treat the string as display-only and branch on the code.

Keying off the code

Codes come in two kinds, in two different error bodies:
  • Integer codes such as 500111 arrive in the business-rule body, alongside message and projectType. These are stable and safe to branch on.
  • String codes such as ndcSellLimitReached arrive in the field-validation body, inside errors.$values[].
Not every rule has a code yet. The ones left blank in the tables above come back with an internal validator name in errorCode instead, which is not a stable identifier and should not be branched on. Giving every rule on this path a documented code is planned.Until then: branch on errorCode where you recognise it, fall back to showing errorMessage where you don’t, and treat anything unrecognised as show the message and point the user at the web interface.

What this page does not cover

Rules about the shape of your request — required fields, types, string lengths, the quantity and fullPackage relationship — are in the generated API reference and on Listings and offers. This page is only about the refusals that depend on data rather than on what you sent.