WebExtrator Task Query API Integration Guide
POST https://api.acedata.cloud/webextrator/tasks
The WebExtrator Task Query API is used to query the results of historical render / extract tasks. Common usages include:
- Callback to check the complete envelope after an asynchronous task is completed (besides
callback_urlpush or active polling). - Audit what has been submitted — task records store both the original
requestand the finalresponse. - Batch refill — pull multiple records at once by
idortrace_id.
Task records are retained in Redis for 7 days.
The task query interface is free (not counted towards Credits usage).
¶ Authentication
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
You can only query tasks under your own AceDataCloud account.
¶ Request Parameters
The request body is a discriminative union based on action, with two types of actions:
¶ action: "retrieve" — Single Query
| Field | Type | Required | Description |
|---|---|---|---|
action |
const | ✅ | Fixed "retrieve". |
id |
string | One of | Task ID (appears in the task_id field of each render/extract envelope). |
trace_id |
string | One of | Call chain ID (the trace_id field of the envelope). |
Either id or trace_id must be provided.
¶ action: "retrieve_batch" — Batch Query
| Field | Type | Required | Description |
|---|---|---|---|
action |
const | ✅ | Fixed "retrieve_batch". |
ids |
string[] | One of | List of task IDs. |
trace_ids |
string[] | One of | List of call chain IDs. |
offset |
number | ❌ | Pagination offset (default 0). |
limit |
number | ❌ | Page size, 1–100 (default 50). |
Either ids or trace_ids must be provided.
¶ Single Response
{
"task": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"trace_id": "550e8400-e29b-41d4-a716-446655440001",
"type": "extract",
"created_at": 1777717800.05,
"started_at": 1777717800.123,
"finished_at": 1777717802.535,
"elapsed": 2.412,
"request": {
"url": "https://en.wikipedia.org/wiki/Diffbot",
"expected_type": "article"
},
"response": {
"success": true,
"data": { /* complete extract envelope */ }
}
}
}
If not found, it returns { "task": null } (HTTP 200, not 404).
The timing fields of the task object are described as follows.
created_at, task creation time, Unix timestamp (seconds, float).started_at, task execution start time, Unix timestamp (seconds, float). It isnullwhen the task has not started.finished_at, task completion time, Unix timestamp (seconds, float). It isnullwhen the task is not completed.elapsed, task execution duration, in seconds (float, rounded to 3 decimal places). It isnullwhen the task is not completed.
¶ Batch Response
{
"tasks": [
{ /* same structure as single .task */ },
{ /* ... */ }
],
"offset": 0,
"limit": 50
}
Non-existent IDs will not cause an error, they will simply be missing from tasks.
¶ Examples
¶ Query Single by task_id
curl -X POST https://api.acedata.cloud/webextrator/tasks \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"action": "retrieve",
"id": "550e8400-e29b-41d4-a716-446655440000"
}'
¶ Query Single by trace_id
curl -X POST https://api.acedata.cloud/webextrator/tasks \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"action": "retrieve",
"trace_id": "550e8400-e29b-41d4-a716-446655440001"
}'
¶ Batch Query
curl -X POST https://api.acedata.cloud/webextrator/tasks \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"action": "retrieve_batch",
"ids": [
"550e8400-e29b-41d4-a716-446655440000",
"550e8400-e29b-41d4-a716-446655440002"
],
"limit": 50
}'
¶ Python (requests) — Polling Until Completion
import os, time, requests
API_KEY = os.environ["ACEDATA_API_KEY"]
BASE = "https://api.acedata.cloud"
# 1) Submit asynchronous extraction
queue = requests.post(
f"{BASE}/webextrator/extract",
headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"},
json={"url": "https://example.com", "mode": "async"},
).json()
job_id = queue["jobId"]
# 2) Use Tasks API to poll until the task is completed
while True:
r = requests.post(
f"{BASE}/webextrator/tasks",
headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"},
json={"action": "retrieve", "id": job_id},
).json()
task = r.get("task")
if task and task.get("finished_at"):
print("Elapsed time", task["elapsed"], "seconds")
print(task["response"]["data"]["title"])
break
time.sleep(2)
¶ Node.js (fetch) — Pull Complete Envelope After Receiving Callback
// In your callback_url handler:
app.post('/hooks/webextrator', async (req, res) => {
res.status(200).end(); // Quick ack first
const taskId = req.body?.task_id;
if (!taskId) return;
const fetchRes = await fetch('https://api.acedata.cloud/webextrator/tasks', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.ACEDATA_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ action: 'retrieve', id: taskId }),
});
const { task } = await fetchRes.json();
console.log('Complete envelope:', task.response.data);
});
¶ Error Responses
| HTTP | error.code |
Meaning |
|---|---|---|
| 400 | bad_request |
Validation failed (missing action, both id and trace_id provided, etc.). |
| 401 | unauthorized |
Missing or invalid Authorization: Bearer …. |
{ "error": { "code": "bad_request", "message": "..." } }
¶ Tips and Pitfalls
- If you can customize
trace_id, then do so. Upload it in the original render/extract request?trace_id=…(QueryString), aligning it with your own business ID (workflow run id, etc.), and then you can query tasks using the business ID. If not provided, the server will automatically generate a UUID. - Retention period is 7 days. Tasks older than this will return
task: null— if long-term archiving is needed, please store it in your own database. - Task queries are free. You can query as many times as you want; the fees for the original render/extract calls have already been paid.
- Prefer using asynchronous + callbacks instead of polling. If business allows, pass
callback_urlin the original request, allowing the platform to push the envelope to you, which is more efficient than polling every 2 seconds.
