Test mode
An API key is created in one of two modes — live or test mode — at Developer → API keys. A test-mode key calls the same host, the same operations and the same schemas as a live one, and is answered from a published table of canned results. The wire value of the mode is sandbox: that is what the response header and the webhook marker below carry.
The mode is fixed when the key is created. It cannot be edited afterwards, and rotating a key preserves it. To change mode, create another key.
Nothing in the credential tells you its mode. The
dlp_live_/dlp_test_prefix records the environment that issued the key, never its mode. The two signals are the Test mode badge beside the key in the console and the response header below.A test-mode call costs nothing. It reserves no credits and settles none, so it never reaches your balance, your ledger or your usage figures — and it queries no provider, no datalake and no verification backend. The answer is computed from your request alone.
Every response the API renders to a test-mode call carries
X-Delpha-Mode: sandbox, success and error alike. A live response carries no such header — absence means live. The exceptions are the responses answered before the API sees the request (401, 403, and the shared per-operation floor's 429), which carry none of the per-request headers.A test-mode job is complete the moment it is accepted. The submit is production's: 202 with a
job_id, aLocationheader,Retry-After, and the same idempotency behaviour. The difference is that the first poll answers 200 with the result rather than the transient 202job_running. A production polling loop therefore works unchanged against test mode; it simply ends on its first turn.Every operation behaves the same way. A test-mode key is refused by the MCP server alone, with
403 sandbox_key_unsupported— use a live key there.Webhooks fire as they do in production, and a test-mode job's events carry
data.mode: "sandbox"so a subscriber can tell them apart. Absence means live. One operation differs:POST /v1/ultimateemits itssentevent and no completion event, because in production that completion is announced by the resolution engine a test-mode request never reaches. Its batch form is unaffected, and every other operation emits the fullsent/done/errorlifecycle. Poll the job for the result.Latency is not representative. A canned answer comes back immediately, while a live job takes as long as the work takes (each operation publishes its band in
x-typical-latency). A timeout or poll interval measured against test mode therefore describes nothing about live behaviour.Test-mode and live jobs are isolated. A test-mode key polling a live job id — or a live key polling a test-mode one — is answered 404
not_found, the same answer it would get for another team's job id.Rate limits are the published ones, counted in a window of their own. A test-mode loop cannot consume the allowance your production traffic is counted against, and it is not exempt from the limits themselves.
Which answer you get. One request field per use case decides the verdict. When the value of that field contains invalid, in any casing, the answer is that use case's negative verdict; anything else returns the positive answer, which describes Delpha's own public record. POST /v1/{usecase}/batch applies the same rule to each item — and every item succeeds, because the marker chooses a verdict rather than a failure, so test mode does not reproduce a partially failed batch.
Operations
Field that decides
Carrying invalid
Otherwise
POST /v1/email
the local part of email (an address with no @ is always negative)
label: "No", email_status: "Invalid", email_domain: null.
label: "OK", email_status: "Valid", the domain resolved.
POST /v1/legal-id
legal_id
label: "Unknown", legal_id_type: null, no suggestions.
label: "OK", the published identifier, one suggestion.
POST /v1/linkedin-profile, POST /v1/linkedin-company-page
url
label: "No", no recommendations.
label: "OK", one recommendation: Delpha's own company page.
POST /v1/name
first_name (else last_name)
label: "No", the submitted name echoed, no suggestions.
label: "OK", every score filled, one suggestion per part.
POST /v1/phone
phone
normalized_value: null (this result carries no label).
zone: "FR", normalised to the published number.
POST /v1/website
website
label: "No", no recommendations.
label: "OK", the published site, one recommendation.
POST /v1/ultimate
company_name
the synthetic group with confidence: 0, no ownership chain.
the synthetic group with confidence: 0.95 and a two-step chain.
GET /v1/company
account_name (else search_str)
no companies, total: 0, has_more: false.
one company carrying its identifier and website.
GET /v1/phone
phone
valid: false, nothing normalised.
valid: true, zone: "FR", normalised to the published number.
Two details the table does not have room for. The ultimate-parent answers name a synthetic group under the reserved documentation domain rather than a real company. And both LinkedIn verifications answer with Delpha's own company page, including the profile operation, so that no individual's profile is part of a permanently published fixture; job_title is therefore always null.
Last updated
Was this helpful?