API keys: scopes, pace, quota and headers.
A key belongs to an organization rather than to a person, carries only the scopes it was given, and is metered on two things at once: the calls it makes and the rows they return. All of it is reported in the response headers on every call.
Making a key
Keys are created in the app. The secret is shown exactly once, at the moment it is minted, and is never recoverable afterwards — we hold a hash of it and the public prefix, which is what appears in the list of your keys. If it is lost, make another and revoke the old one.
A key can never hold a scope its creator does not hold themselves, so a key is a ceiling on what somebody could already do rather than a way around it. A key may be given an expiry date, or none. Revoking a key stops it working immediately and keeps the record of it, because the audit trail of what it did has to stay readable.
Send it as a bearer token:
Authorization: Bearer npi_live_<prefix>_<secret>
An invalid key always gets the same answer, whether it never existed, was revoked or has expired — a refusal that distinguishes those is a refusal that helps somebody guessing.
The scopes
Scopes are named for the thing they let a key do. A key asked to do something outside its scopes is refused by name, and keys cannot be widened after the fact: make a new one with the scopes you need.
| Scope | What it allows |
|---|---|
| providers.read | Search and read providers, organizations and facilities. |
| providers.export | Start provider exports and download the files. |
| contacts.reveal | Open the contact details of one provider at a time, metered as a reveal. |
| append.run | Submit files to the append tool and collect the results. |
| jobs.read | Read the status and results of jobs this key started. |
| usage.read | Read this organization's plan and what it has spent this month. |
Two limits, two reactions
Pace and volume are deliberately different answers, and telling them apart is most of writing a well-behaved client.
| Refusal | What to do |
|---|---|
| Too fast (429) | You are over the per-minute pace for your plan. Wait — the response says how long in whole seconds — and carry on. Nothing was metered against your month. |
| Out of quota (409) | You have spent an allowance, or the page you asked for is bigger than the rows you have left. The message says which allowance, and which window: the month, which resets on the first, or — on a paid plan — the day, which resets at midnight UTC, so waiting does help for that one. Nothing was half-served — ask for a page that fits and you get it whole. |
| Subscription not live (402) | Billing, not usage. Nothing is spent and nothing is lost while it is sorted out. |
| Scope missing (403) | The key cannot do this. Mint a new key with the scope; an existing key is never widened. |
The headers
Every response carries what it is allowed to say, so a client never has to guess where it stands.
| Header | What it reports |
|---|---|
| X-RateLimit-Limit | Calls allowed in the current minute for this key's plan. |
| X-RateLimit-Remaining | How many of them are left. |
| X-RateLimit-Reset | When the current minute clears, as a Unix timestamp. |
| X-RateLimit-Window | The length of the window, in seconds. |
| Retry-After | On a 429 only: whole seconds to wait. Never zero. |
| X-Quota-Limit | The month's call allowance. |
| X-Quota-Used | How much of it has been spent. |
| X-Quota-Remaining | What is left. |
| X-Quota-Period | The month those three figures are about. |
| X-Quota-Rows-Limit | The month's row allowance — the same one an export spends. |
| X-Quota-Rows-Used | How many rows have been spent this month, by any door. |
| X-Quota-Rows-Remaining | Rows left. As they stood when the request arrived, before this call's own rows were charged. |
| X-Request-ID | On every response, success or failure. Quote it when you ask us about a call and we can find that exact one. |
What is metered, and the one exception
A call the API answers adds one to the month's calls, and the records it returns are charged against the month's rows — the same allowance an export spends, because a row read through a key is the same row. Both are written in the same transaction as the read, before the answer leaves, and a refusal on either charges nothing at all.
A page costs one call and as many rows as it returned: fifty for a page of fifty, twelve for a page of twelve, none for a page that found nothing. One record costs one row. A lookup that finds nothing costs the call and no rows, because the lookup happened. Counts, place lists, specialty lists and published list pages name no record and cost no rows at all.
The page you ask for is checked against the rows you have left before anything is read, so a page bigger than your remaining allowance is a 409 rather than a short page. Ask for a page that fits and it is served whole.
The exception is the per-minute pace counter, which does count a call it refused. That is on purpose — a limiter that forgets the calls it turned away is a limiter a fast client can hammer for free. It affects only the minute you are in, never the monthly quota.
A reveal through the API spends a call and a reveal and no rows, for the reasons on the reveals page; charging the same disclosure twice under two names would make both numbers meaningless. The converse holds too — a work email arriving in an ordinary row is metered as a row and never touches your reveals. Starting an export costs a call and no rows, its rows are charged when the file is written, and downloading that file again costs neither. An unlimited allowance sends no header for itself rather than a made-up ceiling.
What the API will not do
Home address and cell phone are not available through the API at all. A call that asks for them is refused by name rather than returning an empty column, so a script can never quietly produce a file of blanks and call it coverage. They are revealed in the app, one provider at a time, under a contract — see home address and cell phone.
The full reference — every endpoint, the scope each needs, the filters, the shapes and the error codes — is public at the API reference. Version 1 changes only by adding.
Questions
Where do I find my API key?
In the app, under keys. The secret is shown once when the key is minted and cannot be retrieved afterwards — only a hash and the public prefix are stored. If it is lost, mint a new key and revoke the old one.
What is the difference between a 429 and a 409?
A 429 means you are going too fast: wait the seconds the response names and carry on. A 409 means an allowance is spent — the month's, which resets on the first, or a paid plan's daily cap, which resets at midnight UTC. The message says which. Neither one costs you anything against your quota.
Does a refused call count against my monthly quota?
No — neither the call nor any rows. Only a call the API answers is metered, and a lookup that answers “no such record” is an answer. The per-minute pace counter does count a refused call, so retrying immediately does not help, but that affects the current minute only.
Do the rows I read through the API come off my export allowance?
Yes, and that is deliberate: there is one row allowance and it counts every row that leaves the platform, whichever door it leaves by. X-Quota-Rows-Remaining reports what is left of it on every response.
Can I widen an existing key's scopes?
No. Keys are never widened after they are made, which is what makes one safe to hand to a script. Mint a new key with the scopes you need and revoke the old one.
Can I get home address or cell phone through the API?
No. Those fields are refused by name for every key, and a key is refused whatever the plan behind it says - a refusal rather than a column of blanks, because blanks read as poor coverage. They are reached in the app, on a contracted plan, and never over the API.
How do I know what my limits are?
From the headers on any response: one set reports the per-minute pace, one the month's calls, one the month's rows, and a usage endpoint reports the plan, its daily caps and everything spent against all of them. A limit that does not apply to your plan sends no header rather than a number you cannot trust.
Other help pages
- Reveals
- What a reveal is, what it costs, when it is free, and why a refused reveal is never counted.
- Plans and limits
- The four things every plan meters, how to see what you have left, and what happens when one runs out.
- Search and filters
- How the filters combine, and the difference between a classification and a specialisation.
- Email trust tiers
- What trusted, probable, doubtful and rejected mean, and what an unscored address counts as.
- Suppression and removal
- How an opt-out is applied everywhere, why nothing is deleted, and how someone gets removed.
- Exports and append
- What lands in a file, how rows are counted, how your own file is matched, and how files are marked.
- Accounts and sign-in
- Seats and invitations, two-step sign-in, signing other sessions out, and who can change billing.
- Home address and cell
- The contracted product: how it is matched, what the confidence score means, and where it never appears.