API ReferenceSubmit URLs
// Docs
Submit URLs
Submit a batch of URLs for processing. Requires the urls:write scope and an idempotency key.
POST /api/v1/urls accepts a batch of URLs, runs validation, and creates one task per accepted URL. The endpoint is idempotent: send a unique Idempotency-Key per logical request and the platform replays the stored response on a retry.
Request
| Field | Value |
|---|---|
| Method | POST |
| Path | /api/v1/urls |
| Auth | Authorization: Bearer shl_live_<key> with scope urls:write |
| Required header | Idempotency-Key: <unique string, up to 255 characters> |
| Body | JSON object with a urls array |
{
"urls": [
"https://example.com/page-a",
"https://example.com/page-b"
]
}Limits: at most 100 URLs per request and about 900 KB of request body.
curl -X POST https://shoulu.co/api/v1/urls \
-H "Authorization: Bearer shl_live_<key>" \
-H "Idempotency-Key: batch-2026-10-25-001" \
-H "Content-Type: application/json" \
-d '{"urls":["https://example.com/page-a"]}'Response
The endpoint returns 202 when at least part of the batch was accepted, and 429 when the whole batch hit a billing or account limit.
{
"accepted": 1,
"acceptedTasks": [
{
"id": "9b1d…",
"url": "https://example.com/page-a",
"status": "pending"
}
],
"rejectedUpfront": [
{
"url": "ftp://bad.example",
"reason": "unsupported_protocol"
}
],
"batchError": null
}acceptedcounts the tasks the platform created. It does not mean the provider accepted them or that search engines indexed the pages.acceptedTasks[].idis the task ID to poll withGET /api/v1/tasks/{id}.rejectedUpfrontlists URLs that failed validation before task creation, with one reason per entry.batchErroris set when no tasks could be created. See Errors and limits for the values.
Rejection reasons
reason | Cause |
|---|---|
invalid_url | The string does not parse as a URL |
unsupported_protocol | Only http: and https: are accepted |
invalid_domain | The hostname fails domain validation |
blacklisted_domain | The domain is on the platform blacklist |
duplicate | An identical URL is already pending for this account |
over_limit | The batch exceeded a per-account cap after validation |
Idempotency
The Idempotency-Key header is required. Keys are scoped to your API key and retained for 24 hours.
- A retry with the same key and the same body returns the stored response.
- A retry with the same key and a different body returns
409 idempotency conflict. - A retry while the first request still runs returns
425withRetry-After: 30.
Use a fresh key per submission batch. Reusing a key by accident replays the old response instead of creating new tasks.