Async enrich jobs
Use POST /api/v1/enrich/jobs for deferred billing after long-running enrich work.
Poll GET /api/v1/enrich/jobs/{job_id} with the poll_bearer from the 202 body (free).
When to use
- Lead-session or websearch runs that may exceed HTTP timeouts (lead-session sync: 30–180 s).
- Headless workers that prefer fire-and-poll over holding a connection.
- CDP x402 upto — anonymous buyers settle on-chain after the job completes.
Sync routes (POST /api/v1/enrich/websearch, POST /api/v1/enrich/lead-session) remain
unchanged for one-shot calls.
Supported routes
enrich/websearchenrich/lead-session
Spending ceiling (bill_up_to_usd)
| Value | |
|---|---|
| Default (omit field) | $1.50 (lead-session catalog price) |
| Client override | $0.05 – $50.00 (ENRICH_JOB_BILL_UP_TO_MAX_USD) |
| Charged | Actual vendor cost ≤ ceiling; unused precharge refunded |
| No-match | $0 on upto path; full refund on virtual precharge |
For async lead-session jobs, in-payload budget_usd is capped to the job’s
bill_up_to_usd (sync lead-session alone still caps budget_usd at $20 per call; session header budget up to $50).
Two billing paths
A — Virtual balance (wallet / xpay agents)
For agents with a bearer (411_… or 411k_…) and prepaid virtual_balance_usd:
POST /api/v1/enrich/jobswithAuthorization: Bearer <token>(noPAYMENT-SIGNATURE).- Server pre-charges
bill_up_to_usdfrom virtual balance (default $1.50). - Receive 202 with
job_id,poll_bearer,billing_mode: "virtual_balance". - Poll
GET /api/v1/enrich/jobs/{job_id}withAuthorization: Bearer <poll_bearer>. - On complete, server refunds unused precharge to virtual balance (full refund on no-match).
B — CDP x402 upto (anonymous or balance-exhausted)
When no bearer is sent (or balance cannot cover bill_up_to_usd):
POSTwithout payment → 402 withscheme: "upto"(CDP only),maxTimeoutSeconds: 1200.- Sign Permit2 upto and retry with
PAYMENT-SIGNATURE. - Receive 202 with
billing_mode: "x402_upto". - Poll with
poll_bearer. - Server settles on-chain after the job completes (actual ≤ max; $0 on no-match).
xpay does not advertise upto — do not expect xpay entries in accepts[].
Example — websearch job
{
"route": "enrich/websearch",
"payload": {
"business_name": "Acme Corp",
"city": "Tampa",
"state": "FL"
},
"bill_up_to_usd": 1.5,
"callback_url": "https://example.com/hooks/enrich"
}
Example — lead-session job
{
"route": "enrich/lead-session",
"payload": {
"lead": {
"contact_id": 81555753,
"company": "Haney Furniture Co",
"street": "30 N Beaver St",
"city": "New Castle",
"state": "PA",
"zip": "16101",
"number1": "7246547732"
},
"budget_usd": 2.0,
"max_rounds": 5,
"mode": "auto"
},
"bill_up_to_usd": 5.0
}
202 response fields
| Field | Meaning |
|---|---|
job_id |
ej_… — pass to poll URL |
poll_bearer |
411j_… — scoped poll token |
poll_interval_sec |
Suggested poll interval (default 2) |
billing_mode |
virtual_balance or x402_upto |
bill_up_to_usd |
Ceiling pre-charged / authorized |
max_timeout_seconds |
Upto timeout (default 1200) |
Poll response
Poll until status is completed or failed.
status |
Meaning |
|---|---|
queued |
Accepted, not started |
running |
Worker executing |
completing |
Finishing billing / persist |
completed |
Done — see result |
failed |
Error — see error |
billing_status |
Meaning |
|---|---|
settled_virtual |
Virtual precharge true-up complete |
settled |
On-chain upto settle complete |
settling |
Settlement in progress |
settle_failed |
Billing failed after run |
result mirrors the sync route JSON when complete.
Optional fields
callback_url— HTTPS webhook; firesenrich.job_completed(see event_callbacks).idempotency_key— dedupe key for the submit request.
MCP
submit_enrich_job and get_enrich_job wrap the same paths. Anonymous CDP upto is
REST only (MCP requires bearer for submit).
Smoke scripts
python3 scripts/smoke_enrich_upto_jobs.py --anon
BASE_URL=https://411data.io python3 scripts/smoke_enrich_upto_jobs.py --balance --route websearch
BASE_URL=https://411data.io python3 scripts/smoke_enrich_upto_jobs.py --upto --route websearch
Discovery
Listed at GET /discovery/resources and /.well-known/x402 as a separate upto
resource (not in sync PAID_ROUTES). Bazaar search: try “async”, “queue”, “jobs”.