Aller au contenu
Docs

API

Read and manage your own graph over HTTP — the vendors you watch, what is beneath them, what changed, what your rules decided about it, and the configuration behind all of it. Included with Pro.

Ce document n'est publié qu'en anglais. Une traduction devrait être une traduction juridique, et nous préférons vous montrer le texte qui fait foi plutôt qu'une approximation.

The API returns the same records the console screens read, through the same boundary. There is no privileged path and no second dataset: what you can read here is what you can see there — the vendors on your account and everything beneath them. This page is the guide; the endpoint-by-endpoint shapes live in the API reference, generated from the API's own specification.

Authentication

Every request carries a bearer token. Create one at Settings, API keys; the token is shown once, at creation, and stored only as a SHA-256 digest. A lost token is reissued, never recovered.

curl -H "Authorization: Bearer npk_..." \
     https://nthparty.io/api/v1/vendors
The token is the tenant. A key belongs to one account and every request runs inside it. There is no account parameter, because an id in a query string would be an authorization decision made by the caller.

The token is only read from the Authorization header. A token in a query string ends up in access logs, in a Referer and in a browser history, so it is not accepted there.

Key scopes

A key is minted read-only or read-and-write, and the rule is one sentence: anything that is not a GET needs the write scope. A write attempted with a read-only key is refused with 403 and insufficient_scope. New keys default to read-only — the safe default for a credential that outlives the person who made it — and the write scope is an explicit choice at creation. A key's scope cannot be changed afterwards; mint a new key instead.

OAuth for delegated access

A bearer token is for scripts you run yourself. For a third-party platform reading your account on your behalf — a GRC tool pulling your monitoring evidence, say — the delegated alternative is OAuth 2.0: you approve a named application for named scopes on one account, and revoke it from Settings, API without touching anything else that key authenticates.

Authorization code with PKCE is the only flow this server issues. The application sends you to /oauth/authorize, you approve the scopes it asked for, and it exchanges the code at /oauth/token for an access token (npo_..., two hours) and a rotating refresh token. The token is scoped to the one account and the specific permissions — reading vendors, reading changes, managing rules, and so on — you saw on the consent screen, never to everything an npk_ key can reach. A request outside the granted scopes — a read included — is refused with 403 and insufficient_scope, and the message names the scope it needed and the ones the token holds.

Applications are registered with nthparty directly, not self-served — get in touch if you are building an integration that should offer this instead of asking customers to paste in a key.

Plan and rate limit

API access is included with Pro. A key on any other plan authenticates and is then refused with 403 and plan_required — on every endpoint, reads and writes alike, and before any scope check, so a read-only key on the wrong plan hears about the plan. Requests are metered at 60 a minute per token — not per address, so two teams behind one office network do not share a budget. Every reply carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (epoch seconds), so a client can pace itself without ever meeting the limit; a throttled request answers 429 with a Retry-After header besides.

Versioning

The version is a path segment, because the audience is a script written once and not revisited: a URL copied into a cron job carries its version with it. Fields may be added inside v1; nothing is removed or renamed. When something has to be, it is /api/v2 beside it rather than a flag. (Outbound webhook payloads are versioned differently — by a date pinned per endpoint — because an event pushed to a consumer cannot carry a path. See Webhooks.)

Pagination

Collections that can grow without bound — the change feed, the alert inbox, exports, and the vendor inventory when you ask for a page — paginate with an opaque cursor. Every collection reply carries a meta block:

{"changes": [...],
 "meta": {"count": 50, "has_more": true, "next_cursor": "chg_7f2..."}}

Pass meta.next_cursor back as ?cursor= to fetch the next page; next_cursor is null on the last page. The cursor is a position, not an offset — rows written between two requests do not shift your pages. A cursor the endpoint does not recognise is refused with invalid_parameter; restart from page one. Hand-maintained lists (rules, the watchlist, webhook endpoints) return whole and carry count only.

Languages

?locale= picks one of the eight launch languages on every endpoint whose reply carries something to translate — change summaries, data labels, rule summaries, export names — including the writes that answer with such a record; the reference lists it on exactly those. Change summaries are written per language when the change is detected, not translated on the request, and data labels (countries, categories) answer in the requested language beside their stable codes. An unsupported code is refused with invalid_parameter on any endpoint, rather than quietly answered in English.

Exports

An export is requested, polled and downloaded — POST /api/v1/exports answers 202 with a pending row. A change_history_csv file holds at most the 200 most recent changes matching its filters; for a longer history narrow it by vendor, or page the change feed instead. An export and its file are deleted 30 days after it completes, so download what you need to keep.

Errors

Every failure has the same shape, so a client writes one error handler and branches on the code. Codes are stable; messages are English prose and may be reworded. request_id is what support greps for — quote it. Multi-field writes (rules, webhook endpoints) add an errors object mapping each field to its messages.

{"error": {"code": "plan_required",
           "message": "The API is included with Pro, ...",
           "request_id": "3f2c8a1e-..."}}
Code
Status
When
unauthorized
401
Missing, malformed, unknown or revoked token. The reply is identical for all four, because a 401 that explained itself would be a way to test tokens.
plan_required
403
The credential is valid and the account's plan does not include this — the API itself (any endpoint, read or write), or a feature such as concentration reporting or the webhook channel. The message names the plan that does.
insufficient_scope
403
The credential lacks the scope — a read-only <code>npk_</code> key on a write, or an <code>npo_</code> token not granted the scope this endpoint needs, on a read as much as a write.
not_found
404
No such record on this account, or no such endpoint. An id you do not watch answers 404 rather than 403, so the endpoint cannot be used to enumerate the graph.
invalid_parameter
400
A parameter the endpoint cannot honour. The message names it and enumerates the accepted values.
limit_reached
403
The plan includes the feature and its allowance is used up — for example the vendor limit when adding a watch.
not_ready
409
An export's file is not available yet (or the export failed). Poll the export until it is done.
rate_limited
429
More than 60 requests in a minute on one token.
server_error
500
Something failed on our side. The body carries the request id and nothing of the failure; quote the id to support.

The machine-readable spec

The API describes itself in OpenAPI 3.1 at https://nthparty.io/api/v1/openapi.yml (also .json) — the same document the reference renders from. Import it into Postman, Insomnia, Bruno or a code generator directly; there is no separate collection to keep in sync.

What the API does not do

It reads and manages your account — your vendors, watchlist, rules, exports and webhook endpoints — and it does not export the dataset. The graph beneath your vendors is yours to read; the graph as a whole is the thing we maintain, and licensing it is a separate decision from shipping a customer API.

Commencez avec un fournisseur. Gratuit, sans carte.

Cherchez une entreprise, suivez-la et voyez la chaîne qui s'étend en dessous. Passez à l'offre supérieure quand un fournisseur ne suffit plus.