Batch jobs
[Bulk link data](/tools/batch-stats/) reads up to 2,000 links to posts or account pages as one batch job. You send the links once; the job reads them 50 at a time in the background, and you read the rows with its handle. Each row is charged as one call on its platform; dead links and rows that never ran cost nothing. Batches are for accounts that have bought credits.
https://api.socialtoai.com/v1/tools/batch_statsThe inputs and the credits of each platform are on Bulk link data in the documentation. This page is about the job.
Submit a batch
- Send
confirm: falsefirst to get the quote: the most the job is charged, free. A batch runs in the background, so a request withoutconfirm: trueis answered with the quote too. - Send it again with
confirm: true. The answer is HTTP 202 with ahandle; nothing is charged yet. The same batch sent again under the sameIdempotency-Keyreturns the same handle. - For an account that has bought credits, with a key that has the permission to start batches; otherwise HTTP 403. A link whose platform cannot be told refuses the whole request with
invalid_params, and nothing runs.
curl https://api.socialtoai.com/v1/tools/batch_stats \ -H "Authorization: Bearer $SOCIALTOAI_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "urls": ["https://x.com/NASA"], "confirm": true }'{ "request_id": "req_00000000-0000-4000-8000-000000000003", "schema_version": "v1", "status": "running", "handle": "res_00000000000040008000000000000003", "retry_after_seconds": 5, "billing": { "cost_credits": 0, "balance_credits": 100, "today_spend_credits": 0, "daily_limit_credits": null, "daily_remaining_credits": null, "display": "This call: 0 credits. Balance: 100 credits (≈ $0.33)." }}Read the rows
Read the job at GET /v1/results/{handle} with its handle, as often as you like, for free. While it runs the answer is HTTP 202 with the rows that are in so far and retry_after_seconds; once it has ended, HTTP 200. Add ?format=csv for a table. The result is kept for 24 hours after the job ended.
curl https://api.socialtoai.com/v1/results/res_00000000000040008000000000000003 \ -H "Authorization: Bearer $SOCIALTOAI_KEY"| Field | Type | What it is |
|---|---|---|
request_id | string | The id of the request that started the job. |
schema_version | "v1" | The version of the response format. |
tool | "batch_stats" | The tool the job runs. |
status | "running" | "done" | "stopped" | "cancelled" | "expired" | "refused" | running, then one of the end statuses below. |
stop_reason | string | null | Why it ended early: too_many_failed_rows, deadline, or the error code a wave was refused with. |
handle | string | The handle the job is read with. |
retry_after_seconds | integer | While it runs: when to read again. (may be absent) |
progress.rows | integer | The links sent. |
progress.rows_done | integer | The rows run so far. |
progress.waves | integer | The waves the job is cut into. |
progress.waves_done | integer | The waves run so far. |
charge.quote_credits | integer | The quote: the most the job is charged. |
charge.charged_credits | integer | What the rows that ran were charged so far. |
main_number.id | string | The job's main number: engagement_total. |
main_number.value | number | The engagement of the links that work, added up. |
result.ok | integer | Rows that came back. |
result.dead | integer | Links that lead nowhere: deleted, private or gone. |
result.failed | integer | Rows that did not come back. |
result.unrecognized | integer | Links whose post or account could not be read from the link. |
result.not_run | integer | Rows the job never reached. |
result.dead_links | string[] | The dead links themselves. |
rows | array | One row per link, in the order sent: see below. |
expires_at | string | null | Until when the result can be read; null while it runs. |
Each row:
| Field | Type | What it is |
|---|---|---|
row | integer | Its place in urls, from 0. |
url | string | The link as sent. |
platform | string | The platform the link is on. |
kind | "post" | "account" | null | post or account; null when the link does not say. |
status | "ok" | "dead" | "failed" | "unrecognized" | "not_run" | How the row ended. Only ok is charged. |
credits | integer | What the row was charged. |
item | object | any | null | The post or the account as it is now, in the response format. |
extra | array | Items of a second call some platforms need for a post's numbers. |
How a job ends
The job is cut into waves of 50 rows, run one after another. Whatever the end, the rows that ran stay charged and the rest cost nothing.
| status | What it means |
|---|---|
running | Waves are still being run. Reading answers HTTP 202 with the rows that are in so far. |
done | Every row was run. |
stopped | More than 30% of the rows run so far failed, so no new wave was opened: stop_reason is too_many_failed_rows. |
cancelled | You cancelled it in the console. |
expired | Its 6 hours ran out: stop_reason is deadline. |
refused | A wave could not be started, for example because the balance ran out: stop_reason is the error code. |
What is charged
- Each row is one call on its platform, at that platform's price for a post link or an account link. A row that came back is charged, numbers of zero and all.
- A dead link, a link that could not be read and a row that never ran cost nothing.
charge.charged_creditsis never above the quote. - A batch cannot be paused. It can be cancelled on the console's Tasks page, also when a key started it: no new wave opens, the wave in flight runs to its end and is charged, and the rows not run cost nothing. Cancelling cannot be taken back.
- When the job ends, a
batch.finishedevent goes to your webhooks.
Over MCP
Your AI runs it with the research tool, tool set to batch_stats, and reads the result by calling the same tool again with the handle. The tool list has the description it is given.
Last updated: