Blog

NDC formats, explained for developers

Every US drug package carries a National Drug Code. If your app takes a medication from a barcode, a claim, a pharmacy feed or a member’s typing, you will meet NDCs in at least three shapes. They all mean the same package, and a lookup only works if you normalize them the same way every time.

Three parts, three layouts

An NDC has three segments:

  1. Labeler: the company that makes, repackages or distributes the drug.
  2. Product: the drug, strength and dosage form, from that labeler.
  3. Package: the size and type of package.

The printed code is 10 digits, but the split between segments is not fixed. There are three layouts:

Layout Example
4-4-2 0002-1433-80
5-3-2 50580-488-10
5-4-1 12345-6789-1

The first two segments together (0002-1433) are the product NDC. Every package size of that product shares it.

The 11-digit form

Billing systems want one fixed layout, so the claims world settled on 11 digits in 5-4-2. You get there by adding a leading zero to whichever segment is short:

10-digit 11-digit
0002-1433-80 00002-1433-80
50580-488-10 50580-0488-10
12345-6789-1 12345-6789-01

Most databases, and most APIs, key on the 11-digit form. Store that, and keep the 10-digit form the label shows next to it if your users need to read it back.

Where conversions go wrong

Stripping hyphens too early. 0002143380 is 10 digits with no layout. It could be 0002-1433-80, 00021-433-80 or 00021-4338-0, and each of those pads to a different 11-digit code. Keep the hyphens until you have converted, or ask for the 11-digit form at the source.

Assuming 11 → 10 has one answer. An 11-digit code can have more than one 10-digit reading when more than one segment starts with zero. 00002-0143-08 could have been 0002-0143-08, 00002-143-08 or 00002-0143-8. Only the product listing says which one is real.

Storing NDCs as numbers. A number drops the leading zero, and the leading zero is the whole point. Store NDCs as strings.

Treating a barcode as an NDC. The barcode on a package is usually a 12-digit UPC-A: a 3, the 10-digit NDC, then a check digit. Pull the middle 10 digits out, and remember they arrive with no hyphens, so you are back to three possible layouts.

A converter in a few lines

// 10-digit, hyphenated → 11-digit 5-4-2.
function toEleven(ndc10) {
  const [lab, prod, pkg] = ndc10.split("-");
  return `${lab.padStart(5, "0")}-${prod.padStart(4, "0")}-${pkg.padStart(2, "0")}`;
}

toEleven("50580-488-10"); // "50580-0488-10"

That is the easy direction. The hard parts are the unhyphenated input and the reverse direction, and both need the listing.

Or let the API do it

Our NDC lookup and converter does all of the above in the browser, including barcodes, and looks the package up. In your app, send whatever you have to the lookup endpoint: 11 digits, 10 with hyphens, or 10 without:

GET /v1/drugs/ndc/50580-488-10
Authorization: Bearer pw_test_…

The answer is the package and the drug it belongs to, with the date it was true. A bare 10-digit code is matched against the codes as they are listed, never padded by guesswork, and a code that matches more than one drug gets a 409, not a guess.

Get a sandbox key and try it with the NDCs you already have.

Ship the medication field this sprint. Keep a drug catalog forever.

Sandbox is 500 lookups a month with no card. When you go live, Launch is $99 a month for one production app.