For the complete documentation index, see llms.txt. This page is also available as Markdown.

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, a Location header, Retry-After, and the same idempotency behaviour. The difference is that the first poll answers 200 with the result rather than the transient 202 job_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/ultimate emits its sent event 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 full sent / done / error lifecycle. 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?