Skip to content

REST API

Base URL https://verify.orvel.dev. Interactive OpenAPI UI: /api. Machine-readable schema: /openapi.json.

Authentication

Authorization: Bearer ev.<your key>

X-API-Key: <key> works too. Without a key the verification endpoints still answer, limited to 20 requests per minute per IP. Get a key on the Pricing page.

Endpoints

Method Path Tool
GET /v1/vat/{vat} check_vat. Query: country_code, requester_vat.
GET /v1/siren/{q} lookup_siren. q = SIREN, SIRET or name.
GET /v1/siret/{siret}/normalize normalize_siret
GET /v1/iban/{iban} check_iban. Query: bic.
POST /v1/address/normalize normalize_address_eu. Body: address, country_code, postal_code, city.
GET /v1/phone/{phone} normalize_phone. Query: region.
GET /v1/email/{email} check_email. Query: mx (default true).
GET /v1/eori/{eori} check_eori
GET /v1/statuses What each status value means. Free.
GET /v1/usage Your monthly counter. Free.
GET /v1/plans Plan catalog and checkout links. Free.
GET /health Version and counter-store state. Free.

All of them return the envelope. Arguments are echoed in input.

Examples

# VAT, with audit proof
curl -H "Authorization: Bearer $EV_KEY" \
  "https://verify.orvel.dev/v1/vat/FR03552081317?requester_vat=FR40303265045"

# French business by name
curl -H "Authorization: Bearer $EV_KEY" \
  "https://verify.orvel.dev/v1/siren/electricite%20de%20france"

# IBAN plus the BIC the customer typed
curl -H "Authorization: Bearer $EV_KEY" \
  "https://verify.orvel.dev/v1/iban/DE89370400440532013000?bic=COBADEFFXXX"

# Address
curl -X POST -H "Authorization: Bearer $EV_KEY" -H "Content-Type: application/json" \
  -d '{"address":"22 avenue de wagram","postal_code":"75008","city":"Paris","country_code":"FR"}' \
  https://verify.orvel.dev/v1/address/normalize

# Email without the DNS lookup
curl -H "Authorization: Bearer $EV_KEY" \
  "https://verify.orvel.dev/v1/email/bob@example.com?mx=false"

Response headers

Header Meaning
X-Plan Plan behind the key, or anonymous.
X-Usage-Used, X-Usage-Quota, X-Usage-Remaining Monthly counter after this call.
Retry-After Only with upstream_unavailable: seconds to wait.

Errors

Errors are JSON, never the envelope:

{ "code": "quota_exceeded", "message": "Monthly quota of 500 calls reached for plan 'free'. Upgrade at /docs/pricing/", "used": 500, "quota": 500 }
Code HTTP Meaning
invalid_input 400 A required argument was empty.
validation_error 422 The request body does not match the schema; see details.
invalid_api_key 401 Unknown, expired or cancelled key.
api_key_required 401 The endpoint needs a key (/v1/usage, portal).
quota_exceeded 402 Monthly quota used up. Upgrade or wait for the reset.
rate_limited 429 Anonymous limit reached; use a key.

A wrong identifier is not an error: it is 200 with status: "invalid". A register being down is also 200, with status: "upstream_unavailable".

Billing rules

One successful call = one unit against the monthly quota. Not counted: upstream_unavailable, 4xx, 5xx, /v1/usage, /v1/plans, /v1/statuses, /health. Counters reset on the first of the month (UTC).