Long-Running Requests - SMB Sales Boost API
Every request reaches the API through an edge network that gives our server about 100 seconds to start answering. Work that can take longer therefore runs as a background job, and your request never has to stay open while it runs. This applies to POST /api/v1/leads/export, POST /api/v1/email-schedules/:id/trigger, POST /api/v1/ai/suggest-categories and the three Lead Export History POST endpoints (refresh, refresh-and-export and re-export). Input errors (4xx) still answer at once.
- Send the request as usual. If the work finishes within about 75 seconds you get the normal answer, exactly as before. The answer always starts within about 90 seconds of the request's arrival.
- Otherwise the answer is 202 Accepted with a
jobId, aLocationheader and astatusUrl. The work keeps running. - Poll
GET /api/v1/jobs/{jobId}with the same API key (any key of the same account works) until it no longer answers 202. It then returns exactly what the original request would have returned: the same status code, headers and body, including an error answer.
HTTP/1.1 202 Accepted
Location: /api/v1/jobs/3f2a9c1e5b7d4a608e1f2c3b4d5e6f70
Retry-After: 5
{
"jobId": "3f2a9c1e5b7d4a608e1f2c3b4d5e6f70",
"status": "running",
"kind": "api_leads_export",
"phase": "searching",
"progress": { "done": 2000, "total": 7000, "label": "Loading leads" },
"elapsedMs": 75012,
"statusUrl": "/api/v1/jobs/3f2a9c1e5b7d4a608e1f2c3b4d5e6f70",
"retryAfterSeconds": 5,
"message": "Still working in the background. GET statusUrl with the same API key until it no longer answers 202; it then returns exactly what this request would have returned (kept up to 60 minutes after the job finishes, 24 hours for a schedule send). Poll statusUrl instead of repeating this request: a repeat with the same Idempotency-Key header returns this same job, a repeat without one may run the work again."
}
curl -H "Authorization: Bearer smbk_your_api_key_here" \
-H "Prefer: wait=30" \
https://smbsalesboost.com/api/v1/jobs/3f2a9c1e5b7d4a608e1f2c3b4d5e6f70
Headers
| Header | Description |
|---|---|
Prefer (request) | wait=N (0-75 seconds, counted from when the request arrived) answers within N seconds: the finished result, or 202. respond-async answers 202 at once. Default: up to 75 seconds. Use a shorter wait when your HTTP client times out sooner. On GET /api/v1/jobs/{jobId}, wait=N (0-60) waits for the job before answering 202 again (default: answer at once). |
Idempotency-Key (request) | 8-64 letters, numbers, underscores or dashes, accepted by every endpoint above. Send one with every export and schedule trigger. Repeating the request with the same key never runs it again: it returns the running job, its stored answer, or 410 job_result_expired once that answer is no longer kept. The key stays with the job for up to about 25 hours after it finished (about 48 hours for a schedule trigger); a server restart forgets it. An answer of 409, 429 or 503, and a 402 insufficient_credits from an export, does not use up the key, so a retry with it runs the request. Every other answer comes back again for the same key: after an error answer, or when you change any argument, use a new key. The same key with a different request answers 409 idempotency_key_reused. Without a key, an identical request returns the job that is still running. |
Location, Retry-After | On a 202: where to poll, and how many seconds to wait before the next poll |
X-SMBSB-Job-Id, X-SMBSB-Job-Status | The job id is on every answer from a job. The status is sent on 202 answers (running) and on GET /api/v1/jobs/{jobId} answers (completed, failed or, on a 410, expired); a request that finished within the wait carries X-SMBSB-Job-Id only. |
Preference-Applied | Echoes the Prefer value that was honored |
How Long Results Are Kept
Results are normally kept 60 minutes after a job finishes (24 hours for a schedule trigger). They can be dropped sooner under heavy load, and each account keeps at most 500 finished jobs (the oldest go first). After that GET /api/v1/jobs/{jobId} answers 410 job_result_expired for about a day, with a message that says where to look, and then 404 job_not_found. Never repeat an export or a schedule trigger just because its answer is gone: check what it already did first. Export files stay in Export History for 90 days and the leads are in Lead Export History; a re-run with maxCredits 0 returns leads you already paid for at no charge, while a normal re-run picks new leads first and charges for them. For a schedule send, check lastSent in GET /api/v1/email-schedules. A server restart interrupts running jobs and forgets kept answers and keys: what they already saved stays saved, and leads you already received are never charged twice.
Limits
Each account can run up to 3 exports, 5 schedule triggers, 3 category suggestions and 2 of each Lead Export History request at once; more answer 429 job_capacity_busy with Retry-After: 30. The request itself still counts toward its endpoint's rate limit (a retry that returns a running job too), while polls count only toward the normal limit of 600 requests per minute per key (see Rate Limits).
MCP
Over MCP, the same work returns {status: "running", jobId} and the get_job tool fetches the result (see MCP Server). The full contract is in the OpenAPI spec (tag Background Jobs).
API Documentation Sections
Introduction | Programmatic Purchase | Authentication | Rate Limits | Long-Running Requests | User Profile | Enrichments | Leads | Filter Presets | Keyword Lists | Email Schedules | Export Formats | Export History | Lead Export History | Account Settings | AI Features | Export Blacklist | Error Handling | Credits & Subscription | MCP Server | Integrations
Ready to Find Your Next Customers? Get access to growing local business leads updated every 5 minutes. See plans starting at $49/mo →