Docs / REST API

REST API

JSON over HTTPS. One bearer key. The same routes the desktop app uses, so nothing here is second class.

Base URLhttps://api.nvoke.run/v1
AuthAuthorization: Bearer nvk_sk_...

Authentication

Every route except the public ones wants Authorization: Bearer with an API key. Make keys in the desktop app under Account, or with POST /v1/api-keys once you hold one. An agent without an account gets its first key from agent sign-up.

OAuth access tokens from nvoke’s sign-in work too. That is how MCP clients connect, see MCP.

Errors

Failures answer with a 4xx or 5xx status and { "error": "code" }. Validation failures add details. Branch on the code, not on the message.

unauthorized
No valid token. Send Authorization: Bearer <key>.
claim_required
An agent created this account more than 7 days ago and nobody claimed it. The human claims it from the emailed link.
invalid_request
The body or query failed validation. details lists the problems.
not_found
No such search, key or webhook on this account.
quota_exceeded
This month’s verified emails are used up. A human upgrades at billingUrl from GET /v1/me.
source_unavailable
Web search is paused on our side. Local and launch searches still work.
not_cancelable
The search already finished.
api_key_limit
The account holds 20 live keys. Revoke one first.
account_exists
An account with this email exists. Ask the human for an API key.
email_not_accepted
Disposable inbox, an opted-out address, or a domain that receives no mail.
rate_limited
Too many sign-ups. Try again later.
signup_unavailable
Agent sign-up is switched off right now.
too_many_webhooks
The account holds 10 webhooks. Delete one first.
webhook_url_not_allowed
Webhook URLs must be HTTPS on a public address that resolves.
database_unavailable
Our database is unreachable. Retry with backoff.

Account

Who you are, your plan and this month’s usage

GET/v1/meAPI key

Returns the account behind the token: profile, plan, verified emails used this month and the allowance. ?sync=1 re-reads the plan from billing first. billingUrl is where a human upgrades.

shell
curl "https://api.nvoke.run/v1/me" \
  -H "Authorization: Bearer $NVOKE_API_KEY"
Show the 200 response

200 response

userobject
user.idstring
user.emailstring | null
user.namestring | null
user.imageUrlstring | null
via"device" | "clerk" | "api_key" | "oauth"
plan"free" | "emails_1000" | "emails_2500" | "emails_7500" | "emails_20000" | "emails_50000" | "emails_100000"
usageobject
usage.periodstring
usage.emailsVerifiedinteger
usage.emailsLimitinteger
maxSearchLimitinteger
accountobject
account.createdBy"human" | "agent"
account.agentNamestring | null
account.claimedAtdatetime | null
billingUrlstring

Errors:unauthorized

The plan ladder

GET/v1/plansPublic

Every plan with its monthly allowance of verified emails and its price in USD. One product, every feature on every plan.

shell
curl "https://api.nvoke.run/v1/plans"
Show the 200 response

200 response

plansobject[]

Searches

List your searches

GET/v1/searchesAPI key

All your searches, newest first, with their counters.

shell
curl "https://api.nvoke.run/v1/searches" \
  -H "Authorization: Bearer $NVOKE_API_KEY"
Show the 200 response

200 response

searchesobject[]

Errors:unauthorized

Leads

List companies with their emails

GET/v1/searches/:id/companiesAPI key

The companies a search found, each with its checked email addresses, 50 to a page. Filter by verification (valid is what you usually want), by kind (generic like info@, or personal) and by q (name, domain or address). Pass nextCursor back as cursor for the next page. Addresses appear once their check has run.

Query

verification?"valid" | "invalid" | "risky" | "catch_all" | "unknown"
kind?"generic" | "personal"
q?stringup to 200 characters
cursor?stringup to 200 characters
limit?integer1 to 200. default 50
shell
curl "https://api.nvoke.run/v1/searches/$SEARCH_ID/companies?verification=valid&limit=50" \
  -H "Authorization: Bearer $NVOKE_API_KEY"
Show the 200 response

200 response

companiesobject[]
nextCursorstring | null
totalinteger

Errors:unauthorizednot_foundinvalid_request

Export as CSV

GET/v1/searches/:id/export.csvAPI key

One row per email: company, domain, website, email, kind, verification, source_url, location, phone. Takes the same filters as the company list.

Query

verification?"valid" | "invalid" | "risky" | "catch_all" | "unknown"
kind?"generic" | "personal"
q?stringup to 200 characters
shell
curl "https://api.nvoke.run/v1/searches/$SEARCH_ID/export.csv?verification=valid" \
  -H "Authorization: Bearer $NVOKE_API_KEY"

Returns 200 with text/csv.

Errors:unauthorizednot_foundinvalid_request

Webhooks

List webhooks

GET/v1/webhooksAPI key

Your webhooks with the outcome of their last deliveries. A webhook we turned off after a day of failures has enabled: false and disabledReason failing.

shell
curl "https://api.nvoke.run/v1/webhooks" \
  -H "Authorization: Bearer $NVOKE_API_KEY"
Show the 200 response

200 response

webhooksobject[]

Errors:unauthorized

Create a webhook

POST/v1/webhooksAPI key

We POST lead.ready for every company with a valid address once its checks settle, and search.finished when a search ends. scope drops or a dropId limits it to searches drops made. Requests are signed the Standard Webhooks way (webhook-id, webhook-timestamp, webhook-signature); the response holds the signing secret, and it is never shown again. HTTPS on a public address only. At most 10 webhooks.

Body

urlstringWhere to POST events. HTTPS on a public address.. up to 2000 characters
events?("lead.ready" | "search.finished")[]The events to send.
scope?"all" | "drops"`all`: every search. `drops`: only searches a drop made.
dropId?uuidOnly searches this drop made. Implies scope `drops`.
shell
curl -X POST "https://api.nvoke.run/v1/webhooks" \
  -H "Authorization: Bearer $NVOKE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/hooks/nvoke","events":["lead.ready"],"scope":"drops"}'
Show the 201 response

201 response

iduuid
urlstring
events("lead.ready" | "search.finished")[]
scope"all" | "drops"
dropIduuid | null
enabledboolean
disabledReason"failing" | null
lastSuccessAtdatetime | null
lastFailureAtdatetime | null
lastErrorstring | null
createdAtdatetime
secretstring

Errors:unauthorizedinvalid_requesttoo_many_webhookswebhook_url_not_allowed

Change a webhook

PATCH/v1/webhooks/:idAPI key

Change the URL, events or scope, or pause and resume it with enabled. dropId: null widens it to the whole scope again.

Body

url?stringWhere to POST events. HTTPS on a public address.. up to 2000 characters
events?("lead.ready" | "search.finished")[]The events to send.
scope?"all" | "drops"`all`: every search. `drops`: only searches a drop made.
dropId?uuid | null
enabled?boolean
shell
curl -X PATCH "https://api.nvoke.run/v1/webhooks/$WEBHOOK_ID" \
  -H "Authorization: Bearer $NVOKE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"enabled":true}'
Show the 200 response

200 response

iduuid
urlstring
events("lead.ready" | "search.finished")[]
scope"all" | "drops"
dropIduuid | null
enabledboolean
disabledReason"failing" | null
lastSuccessAtdatetime | null
lastFailureAtdatetime | null
lastErrorstring | null
createdAtdatetime

Errors:unauthorizednot_foundinvalid_requestwebhook_url_not_allowed

Delete a webhook

DELETE/v1/webhooks/:idAPI key

Stops it at once and drops its pending deliveries.

shell
curl -X DELETE "https://api.nvoke.run/v1/webhooks/$WEBHOOK_ID" \
  -H "Authorization: Bearer $NVOKE_API_KEY"

Returns 204 with no body.

Errors:unauthorizednot_found

Send a test event

POST/v1/webhooks/:id/testAPI key

Sends a signed ping event right now and tells you how your server answered.

shell
curl -X POST "https://api.nvoke.run/v1/webhooks/$WEBHOOK_ID/test" \
  -H "Authorization: Bearer $NVOKE_API_KEY"
Show the 200 response

200 response

okboolean
statusinteger | null
errorstring | null
durationMsinteger

Errors:unauthorizednot_foundwebhook_url_not_allowed

Recent deliveries

GET/v1/webhooks/:id/deliveriesAPI key

The last 50 deliveries with their status, attempts and the last answer from your server. Kept 30 days.

shell
curl "https://api.nvoke.run/v1/webhooks/$WEBHOOK_ID/deliveries" \
  -H "Authorization: Bearer $NVOKE_API_KEY"
Show the 200 response

200 response

deliveriesobject[]

Errors:unauthorizednot_found

API keys

List API keys

GET/v1/api-keysAPI key

Your live API keys. Only the prefix of each key is shown.

shell
curl "https://api.nvoke.run/v1/api-keys" \
  -H "Authorization: Bearer $NVOKE_API_KEY"
Show the 200 response

200 response

apiKeysobject[]

Errors:unauthorized

Create an API key

POST/v1/api-keysAPI key

Makes a new key. The response holds the full key, and it is never shown again. At most 20 live keys.

Body

namestringup to 60 characters
shell
curl -X POST "https://api.nvoke.run/v1/api-keys" \
  -H "Authorization: Bearer $NVOKE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"CRM sync"}'
Show the 201 response

201 response

iduuid
namestring
prefixstring
origin"user" | "agent_signup"
createdAtdatetime
lastUsedAtdatetime | null
keystring

Errors:unauthorizedinvalid_requestapi_key_limit

Revoke an API key

DELETE/v1/api-keys/:idAPI key

The key stops working at once. A key may revoke itself.

shell
curl -X DELETE "https://api.nvoke.run/v1/api-keys/$KEY_ID" \
  -H "Authorization: Bearer $NVOKE_API_KEY"

Returns 204 with no body.

Errors:unauthorizednot_found

Agents

Sign up as an agent

POST/v1/agents/signupPublic

Creates an nvoke account for the person you work for and returns an API key at once. No browser, no human needed. The free plan applies: 50 verified emails a month. We send that person one email with a link to claim the account. Unclaimed accounts work for 7 days, then answer 403 claim_required until claimed, and are deleted after 30 days. Rate limited per IP, per email domain and per day.

Body

emailemailup to 320 characters
agentName?stringup to 60 characters
shell
curl -X POST "https://api.nvoke.run/v1/agents/signup" \
  -H "Content-Type: application/json" \
  -d '{"email":"ada@example.com","agentName":"Claude"}'
Show the 201 response

201 response

apiKeystring
accountobject
account.emailstring
account.status"unclaimed"
account.claimEmailSentboolean
account.activeUntildatetime
apiBasestring
mcpUrlstring
docsUrlstring
nextStepsstring[]

Errors:invalid_requestaccount_existsemail_not_acceptedrate_limitedsignup_unavailable

Privacy

Opt an address or domain out

POST/v1/privacy/opt-outPublic

Stops collection of an address or a whole domain and deletes what we hold. Always answers { ok: true }.

Body

emailemailup to 320 characters
domainstringup to 253 characters
shell
curl -X POST "https://api.nvoke.run/v1/privacy/opt-out"
Show the 200 response

200 response

oktrue

Errors:invalid_request

Meta

This API as OpenAPI 3.1

GET/v1/openapi.jsonPublic

Machine readable description of every endpoint above.

shell
curl "https://api.nvoke.run/v1/openapi.json"
Show the 200 response

200 response

openapistring

Health check

GET/healthPublic

Answers 200 when the API is up.

shell
curl "https://api.nvoke.run/health"
Show the 200 response

200 response

status"ok"
servicestring
versionstring
uptimeSecondsnumber