Bulk jobs and webhooks
A bulk job runs one engine over a list of inputs in the background. Each item is billed like a normal request, failed items are free, and the job stops cleanly if you run out of credits or hit your spend cap. You can also create jobs without code in the dashboard.
Create a job
Send either inputs (a list of values plus the parameter field they fill) or items (a list of full parameter objects). params is merged into every item. Up to 10,000 items per job.
curl -X POST "https://api.gridlode.com/v1/tasks" \
-H "Authorization: Bearer $GRIDLODE_KEY" -H "Content-Type: application/json" \
-d '{
"engine": "domain.tech",
"inputs": ["shopify.com", "wordpress.org", "vercel.com"],
"field": "domain",
"name": "Competitor stacks",
"webhook_url": "https://example.com/hooks/gridlode"
}'The response contains the job, the estimated credits and, when you pass a webhook URL, a one-time webhook_secret.
Check progress and download results
GET /v1/tasks/{id}: status (queued, running, done, failed, cancelled), counts and credits.GET /v1/tasks/{id}/results?format=csv: one row per input with flattened result columns. Alsoformat=jsonandformat=ndjson. Addoffsetandlimitto page through large jobs; JSON responses include apaginationobject withnext_offset.POST /v1/tasks/{id}/cancel: stops remaining items (they are not charged).GET /v1/tasks?limit=50&offset=0: your jobs, newest first, withpagination.has_more.
Webhooks
When a job ends we POST {"event":"task.completed","task":{...}} to your URL (https only, public addresses only), retrying up to three times. The event is task.completed, task.failed (for example when credits run out) or task.cancelled. Verify the X-Gridlode-Signature header: t=timestamp,v1=hex, where v1 = HMAC_SHA256(webhook_secret, t + "." + raw_body).
import hmac, hashlib, time
def verify(raw_body: bytes, header: str, secret: str) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
if abs(time.time() - int(parts["t"])) > 300:
return False
expected = hmac.new(secret.encode(), f"{parts['t']}.".encode() + raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts["v1"])