Crawlers
Operations tagged Crawlers in the public API.
About Crawlers
A crawler collects a website's pages into knowledge, one dataset per page. There are two kinds, each with its own paths and ids: a website crawler (/crawlers) follows links from a start URL within the depth and page limits you set; a sitemap crawler (/sitemap_crawlers) fetches the pages a sitemap.xml lists, and is the better choice when the site has one.
Lifecycle. Creating a crawler checks and probes the URL, queues the first run and emits crawler.created. status moves pending → running → completed or failed, emitting crawl.completed or crawl.failed; pause, resume, cancel and retry move it by hand and emit nothing. A recurring crawler (crawl_frequency, scan_frequency) waits as pending between runs. With chatbot_id and auto_train (on by default) every collected page trains into the chatbot, and each page's dataset emits its own knowledge.dataset.trained or .failed.
Limits and duplicates. An account runs at most 5 website and 10 sitemap crawls at once by default; one more is 429 CRAWLER_LIMIT_REACHED, and resuming, retrying or re-scanning at the cap is refused the same way. Creating a crawler for a URL and chatbot that already has one pending or running returns that crawler with 200 instead of a second one, and emits nothing. A page a crawler already saved in its collection is updated in place on a later run, not added twice.
URLs. Only public http(s) addresses are crawled: a private, loopback, link-local or otherwise blocked address is refused before anything is fetched, every redirect is checked the same way, and the connection is pinned to the address that was checked. respect_robots_txt (on by default) obeys the site's robots.txt. POST /crawlers/validate_url and POST /sitemap_crawlers/validate_url run the pre-flight without creating anything.
Webhooks. crawler.* and crawl.* events carry only {object, id}, and website and sitemap crawlers are numbered separately: keep each id with its kind.
IDs you will meet.
id— a crawler id, an integer, in every/crawlers/{id}(website) or/sitemap_crawlers/{id}(sitemap) path.crawler_idwithcrawler_type— howPOST /crawlers/queue/cancelnames a crawler of either kind.
IDs on this page
- Knowledge collection id
<COLLECTION_ID> - Integer.
Get it from
- POST /v1/knowledge/collections returns it as
id - GET /v1/knowledge/collections returns it as
data[].id - POST /v1/knowledge/collections/auto_create returns it as
id - GET /v1/knowledge/{id} returns it as
collection_id - Webhook knowledge.collection.created carries it as
data.object.id - Adding knowledge or a crawl with only
chatbot_idfiles it in the chatbot's default collection, created on first use: read its id ascollection_idon any of the chatbot's datasets.
- POST /v1/knowledge/collections returns it as
- Chatbot id
<CHATBOT_ID> - Integer.
Get it from
- GET /v1/chatbots returns it as
data[].id - POST /v1/chatbots returns it as
id - GET /v1/chatbots/by_handle/{handle} returns it as
id - Webhook chatbot.created carries it as
data.object.id - In the dashboard, it is the number in a chatbot's address:
/dashboard/chatbots/{id}.
- GET /v1/chatbots returns it as
- Website crawler id
<CRAWLER_ID> - Integer. Website and sitemap crawlers are numbered separately, so the same number can name one of each.
Get it from
- POST /v1/crawlers returns it as
id - GET /v1/crawlers returns it as
data[].id - GET /v1/crawlers/queue returns it as
data[].id - Webhook crawler.created carries it as
data.object.id crawler.*andcrawl.*events carry only{object, id}, not the crawler kind: keep the kind with the id when you create the crawler.
- POST /v1/crawlers returns it as
- Sitemap crawler id
<SITEMAP_CRAWLER_ID> - Integer. Website and sitemap crawlers are numbered separately, so the same number can name one of each.
Get it from
- POST /v1/sitemap_crawlers returns it as
id - GET /v1/sitemap_crawlers returns it as
data[].id - Webhook crawler.created carries it as
data.object.id crawler.*andcrawl.*events carry only{object, id}, not the crawler kind: keep the kind with the id when you create the crawler.
- POST /v1/sitemap_crawlers returns it as
- Crawler id
<CRAWLER_ID> - Integer: a website crawler id with
crawler_type: url, a sitemap crawler id withcrawler_type: sitemap.Get it from
- GET /v1/crawlers/queue returns it as
data[].id - POST /v1/crawlers returns it as
id - POST /v1/sitemap_crawlers returns it as
id - GET /v1/sitemap_crawlers returns it as
data[].id
- GET /v1/crawlers/queue returns it as
List queued and running website crawlers
pending or running, newest first and cursor-paginated — including a recurring crawler waiting for its next run. Paused, finished and sitemap crawlers are not listed. Cancel one with POST /crawlers/queue/cancel or POST /crawlers/{id}/cancel.- Required scope
- crawlers:read
- Idempotency
- Read-only
- Rate limits
Query parameters
limitintegerOptionalPage size, clamped to 1–100.Default:
20Minimum:1Maximum:100starting_afterstringOptionalCursor from a previous page'snext_cursor: returns the page after it. A cursor minted for another list,sortororderis 422INVALID_CURSOR.ending_beforestringOptionalCursor from a previous page'sprevious_cursor: returns the page before it. Wins when both cursors are sent.created[gte]stringOptionalOnly rows created on or after this instant:YYYY-MM-DD(whole UTC day) or an RFC 3339 timestamp with a zone. Anything else is 422INVALID_PARAMETER.created[lte]stringOptionalOnly rows created on or before this instant:YYYY-MM-DD(whole UTC day) or an RFC 3339 timestamp with a zone. Anything else is 422INVALID_PARAMETER.
Responses
- 200Success.
objectstringRequiredAlways
listdataarray of CrawlerResourceRequiredhas_morebooleanRequirednext_cursorstringnullableRequiredprevious_cursorstringnullableRequiredurlstringRequiredAlways
/v1/crawlers/queue
- 400A tenant selector header named a tenant other than the API key's own (
ACCOUNT_SELECTOR_NOT_SUPPORTED): an all-digitX-Account-Idother than the key owner's id or, whileworkspaces.context_enabledis on, anX-Workspace-Idother than the key's workspace (ws_prefix optional, case-insensitive). A header naming the key's own tenant, or a non-numericX-Account-Id, is ignored; a key cannot switch tenants, so send neither.Error codesACCOUNT_SELECTOR_NOT_SUPPORTED
- 401Missing or invalid API key.
Error codesUNAUTHENTICATED
- 403The API key is missing a required scope.
Error codesACCOUNT_SUSPENDEDINSUFFICIENT_SCOPE
- 422Validation failed. See
error.details.Error codesINVALID_CURSORINVALID_PARAMETER
- 429Rate limited. Honour the Retry-After header before retrying.
Error codesRATE_LIMITED
- 500Unexpected server error. Retry with the same Idempotency-Key.
Error codesSERVER_ERROR
Request
curl -X GET 'https://api.agentency.com/v1/crawlers/queue' \
-H "Authorization: Bearer <YOUR_KEY>" \
-H "Content-Type: application/json"Response
Example 200 response
{
"object": "list",
"data": [
{
"object": "website_crawler",
"id": 1,
"name": "Product catalogue",
"url": "https://shop.example.com/products",
"status": "running",
"chatbot_id": 1,
"error_code": null,
"created_at": "2026-01-01T00:00:00+00:00",
"updated_at": "2026-01-01T00:00:00+00:00"
}
],
"has_more": false,
"next_cursor": null,
"previous_cursor": null,
"url": "/v1/crawlers/queue"
}List website crawlers
status narrows the list (an unknown value is 422 VALIDATION_FAILED). Sitemap crawlers are listed by GET /sitemap_crawlers.- Required scope
- crawlers:read
- Idempotency
- Read-only
- Rate limits
Query parameters
statusstringnullableOptionalCrawl status:pending,running,paused,completed,failedorcancelled.Possible values
pendingrunningpausedcompletedfailedcancellednulllimitintegerOptionalPage size, clamped to 1–100.Default:
20Minimum:1Maximum:100starting_afterstringOptionalCursor from a previous page'snext_cursor: returns the page after it. A cursor minted for another list,sortororderis 422INVALID_CURSOR.ending_beforestringOptionalCursor from a previous page'sprevious_cursor: returns the page before it. Wins when both cursors are sent.created[gte]stringOptionalOnly rows created on or after this instant:YYYY-MM-DD(whole UTC day) or an RFC 3339 timestamp with a zone. Anything else is 422INVALID_PARAMETER.created[lte]stringOptionalOnly rows created on or before this instant:YYYY-MM-DD(whole UTC day) or an RFC 3339 timestamp with a zone. Anything else is 422INVALID_PARAMETER.
Responses
- 200Success.
objectstringRequiredAlways
listdataarray of CrawlerResourceRequiredhas_morebooleanRequirednext_cursorstringnullableRequiredprevious_cursorstringnullableRequiredurlstringRequiredAlways
/v1/crawlers
- 400A tenant selector header named a tenant other than the API key's own (
ACCOUNT_SELECTOR_NOT_SUPPORTED): an all-digitX-Account-Idother than the key owner's id or, whileworkspaces.context_enabledis on, anX-Workspace-Idother than the key's workspace (ws_prefix optional, case-insensitive). A header naming the key's own tenant, or a non-numericX-Account-Id, is ignored; a key cannot switch tenants, so send neither.Error codesACCOUNT_SELECTOR_NOT_SUPPORTED
- 401Missing or invalid API key.
Error codesUNAUTHENTICATED
- 403The API key is missing a required scope.
Error codesACCOUNT_SUSPENDEDINSUFFICIENT_SCOPE
- 422Validation failed. See
error.details. - 429Rate limited. Honour the Retry-After header before retrying.
Error codesRATE_LIMITED
- 500Unexpected server error. Retry with the same Idempotency-Key.
Error codesSERVER_ERROR
Request
curl -X GET 'https://api.agentency.com/v1/crawlers' \
-H "Authorization: Bearer <YOUR_KEY>" \
-H "Content-Type: application/json"Response
Example 200 response
{
"object": "list",
"data": [
{
"object": "website_crawler",
"id": 1,
"name": "Product catalogue",
"url": "https://shop.example.com/products",
"status": "running",
"chatbot_id": 1,
"error_code": null,
"created_at": "2026-01-01T00:00:00+00:00",
"updated_at": "2026-01-01T00:00:00+00:00"
},
{
"object": "website_crawler",
"id": 1,
"name": "Help centre",
"url": "https://shop.example.com/help",
"status": "completed",
"chatbot_id": 1,
"error_code": null,
"created_at": "2026-01-01T00:00:00+00:00",
"updated_at": "2026-01-01T00:00:00+00:00"
}
],
"has_more": false,
"next_cursor": null,
"previous_cursor": null,
"url": "/v1/crawlers"
}Create a website crawler
base_url and saves each page it collects as a knowledge dataset in knowledge_collection_id (or the chatbot's default collection), and returns it with 201, status: pending. The first run starts on its own within seconds; crawl.completed or crawl.failed tells you when it ends, and with auto_train the collected pages are trained into chatbot_id, each dataset emitting its own knowledge.dataset.trained or .failed.
Before anything is created the URL is checked (only public http(s) addresses) and probed: a blocked address or a site that does not answer is 422 VALIDATION_FAILED. A chatbot already at its plan's knowledge allowance is 402 KNOWLEDGE_PLAN_SIZE_EXCEEDED; an account already running its maximum of concurrent website crawls (5 by default) is 429 CRAWLER_LIMIT_REACHED. When the same URL already has a pending or running crawler for the same chatbot, that crawler is returned with 200 and no event, instead of a second one.- Required scope
- crawlers:write
- Idempotency
- Accepts Idempotency-Key
- Webhook events
- crawler.created
- Rate limits
Integer.knowledge_collection_id(body)Knowledge collection idPlaceholder in the samples:
<COLLECTION_ID>Get it from
- POST /v1/knowledge/collections returns it as
id - GET /v1/knowledge/collections returns it as
data[].id - POST /v1/knowledge/collections/auto_create returns it as
id - GET /v1/knowledge/{id} returns it as
collection_id - Webhook knowledge.collection.created carries it as
data.object.id - Adding knowledge or a crawl with only
chatbot_idfiles it in the chatbot's default collection, created on first use: read its id ascollection_idon any of the chatbot's datasets.
- POST /v1/knowledge/collections returns it as
Integer.chatbot_id(body)Chatbot idPlaceholder in the samples:
<CHATBOT_ID>Get it from
- GET /v1/chatbots returns it as
data[].id - POST /v1/chatbots returns it as
id - GET /v1/chatbots/by_handle/{handle} returns it as
id - Webhook chatbot.created carries it as
data.object.id - In the dashboard, it is the number in a chatbot's address:
/dashboard/chatbots/{id}.
- GET /v1/chatbots returns it as
Header parameters
Idempotency-KeystringOptionalMakes a retry safe. The first 2xx answer is stored for 24 h and replayed for the same key withIdempotency-Replayed: true; a retry while the first request runs is 409IDEMPOTENCY_IN_FLIGHT; the same key with a different payload is 422IDEMPOTENCY_KEY_REUSED; a malformed key is 400INVALID_IDEMPOTENCY_KEY.Min length:
16Max length:128Pattern:^[A-Za-z0-9_-]+$
Request body
/v1 start website crawling payload. Field set is pinned on this class so a
dashboard FormRequest tweak cannot silently widen the public contract.namestringRequiredDisplay name, at most 255 characters.Max length:
255descriptionstringnullableOptionalOptional longer description, at most 1000 characters.Max length:
1000base_urlstringRequiredThe publichttp(s)page the crawl starts from, at most 2048 characters. Checked before anything is fetched — a private, loopback, link-local or otherwise blocked address is 422VALIDATION_FAILEDon this field — then probed once: a site that does not answer is 422VALIDATION_FAILED.POST /crawlers/validate_urlruns the same probe without creating anything.Format:
uriMax length:2048crawl_modestringnullableOptionalwebsite(default) follows links frombase_url;single_pagecollectsbase_urlalone (max_depthandmax_pagesare then 1).Possible values
single_pagewebsitenullmax_depthintegernullableOptionalHow many links deep to follow frombase_url: 1 to 10 by default. Required unlesscrawl_modeissingle_page.Minimum:
1Maximum:10max_pagesintegernullableOptionalThe most pages to collect: 1 to 100,000 by default. Required unlesscrawl_modeissingle_page.Minimum:
1Maximum:100000crawl_delay_secondsintegernullableOptionalSeconds between requests to the site: 1 (default) to 60.Minimum:
1Maximum:60crawl_concurrencyintegernullableOptionalPages fetched at once: 1 (default, one at a time) to 5.Minimum:
1Maximum:5follow_external_linksbooleanOptionalWhether to follow links to other hosts. Defaults tofalse.respect_robots_txtbooleanOptionalWhether to obey the site'srobots.txt(defaulttrue). A page it disallows is left out witherror_code: robots_blocked.include_patternsarray of stringnullableOptionalOnly collect URLs matching one of these patterns (a glob or a plain substring, each at most 255 characters).exclude_patternsarray of stringnullableOptionalNever collect URLs matching one of these patterns (a glob or a plain substring, each at most 255 characters), for example a tag or category archive.content_selectorsobjectOptionalCSS selectors that pick each page's content. Omit for the platform defaults.knowledge_collection_idintegernullableOptionalThe collection to file the collected pages in. Optional withchatbot_id, when the chatbot's default collection is used (created on first use); required without it.chatbot_idintegernullableOptionalThe chatbot the collected pages train. A crawler of the samebase_urlfor the same chatbot that is still pending or running is returned instead of a new one.auto_trainbooleannullableOptionalTrain each collected page intochatbot_id(defaulttrue).crawl_frequencystringnullableOptionalonce(default), or re-crawl the sitedaily,weeklyormonthly.Possible values
oncedailyweeklymonthlynullenable_javascriptbooleanOptionalJavaScript rendering is not available:trueis 422VALIDATION_FAILED.user_agentstringnullableOptionalTheUser-Agentto send, at most 500 characters. Defaults to the platform crawler's.Max length:
500training_optionsobjectOptionalHow collected pages become knowledge. Omitted keys take the platform defaults.
Responses
- 200
CrawlerResourceobjectstringRequiredThe crawler kind:website_crawler(/crawlers) orsitemap_crawler(/sitemap_crawlers). The two kinds are numbered separately.Possible values
sitemap_crawlerwebsite_crawleridintegerRequiredThe crawler id, unique within its kind.namestringnullableRequiredDisplay name.urlstringnullableRequiredThe start URL of a website crawler, or the sitemap URL of a sitemap crawler.statusstringRequiredpending(queued, or a recurring crawler waiting for its next run),running,paused,completed,failedorcancelled. Reachingcompletedorfailedemitscrawl.completedorcrawl.failed.Possible values
pendingrunningpausedcompletedfailedcancelledchatbot_idstringnullableRequiredThe chatbot the collected pages train;nullwhen the crawler only fills a collection.error_codestringnullableRequiredWhy the crawler last failed, as a stable code;nullwhen it has not.Possible values
unreachablehttp_errortoo_many_redirectsinvalid_sitemaptoo_largerobots_blockednever_startedknowledge_limit_reachedunsupported_content_encodingcorrupt_content_encodingunsupported_content_typecontent_too_shortnot_knowledge_indexnot_knowledge_mediaexcluded_by_patternduplicatecanonical_duplicatenear_duplicatesoft_404redirect_externalredirect_other_pagestalledextraction_failedremoved_from_knowledge_basechallenge_blockedunknownnullcreated_atstringnullableRequiredWhen the crawler was created (ISO 8601, UTC).updated_atstringnullableRequiredWhen the crawler last changed (ISO 8601, UTC).
- 201
CrawlerResourceobjectstringRequiredThe crawler kind:website_crawler(/crawlers) orsitemap_crawler(/sitemap_crawlers). The two kinds are numbered separately.Possible values
sitemap_crawlerwebsite_crawleridintegerRequiredThe crawler id, unique within its kind.namestringnullableRequiredDisplay name.urlstringnullableRequiredThe start URL of a website crawler, or the sitemap URL of a sitemap crawler.statusstringRequiredpending(queued, or a recurring crawler waiting for its next run),running,paused,completed,failedorcancelled. Reachingcompletedorfailedemitscrawl.completedorcrawl.failed.Possible values
pendingrunningpausedcompletedfailedcancelledchatbot_idstringnullableRequiredThe chatbot the collected pages train;nullwhen the crawler only fills a collection.error_codestringnullableRequiredWhy the crawler last failed, as a stable code;nullwhen it has not.Possible values
unreachablehttp_errortoo_many_redirectsinvalid_sitemaptoo_largerobots_blockednever_startedknowledge_limit_reachedunsupported_content_encodingcorrupt_content_encodingunsupported_content_typecontent_too_shortnot_knowledge_indexnot_knowledge_mediaexcluded_by_patternduplicatecanonical_duplicatenear_duplicatesoft_404redirect_externalredirect_other_pagestalledextraction_failedremoved_from_knowledge_basechallenge_blockedunknownnullcreated_atstringnullableRequiredWhen the crawler was created (ISO 8601, UTC).updated_atstringnullableRequiredWhen the crawler last changed (ISO 8601, UTC).
- 400A tenant selector header named a tenant other than the API key's own (
ACCOUNT_SELECTOR_NOT_SUPPORTED): an all-digitX-Account-Idother than the key owner's id or, whileworkspaces.context_enabledis on, anX-Workspace-Idother than the key's workspace (ws_prefix optional, case-insensitive). A header naming the key's own tenant, or a non-numericX-Account-Id, is ignored; a key cannot switch tenants, so send neither. A mutation that honoursIdempotency-Keyalso returnsINVALID_IDEMPOTENCY_KEYwhen that header is not 16–128[A-Za-z0-9_-]characters.Error codesACCOUNT_SELECTOR_NOT_SUPPORTEDINVALID_IDEMPOTENCY_KEY
- 401Missing or invalid API key.
Error codesUNAUTHENTICATED
- 402A billing gate refused the request (plan limit, monthly AI budget or message credits). See
error.code.Error codesKNOWLEDGE_PLAN_SIZE_EXCEEDED
- 403The API key is missing a required scope.
Error codesACCOUNT_SUSPENDEDINSUFFICIENT_SCOPE
- 404The resource does not exist on this account.
Error codesNOT_FOUND
- 409The request conflicts with the current resource state.
Error codesIDEMPOTENCY_IN_FLIGHT
- 422Validation failed. See
error.details.Error codesBLOCKED_DOMAINCHALLENGE_BLOCKEDCONTENT_TOO_LARGECORRUPT_CONTENT_ENCODINGCRAWLING_ERRORIDEMPOTENCY_KEY_REUSEDINVALID_SITEMAPROBOTS_BLOCKEDUNSUPPORTED_CONTENT_ENCODINGUNSUPPORTED_CONTENT_TYPEUPSTREAM_HTTP_ERRORVALIDATION_FAILED
- 429Rate limited. Honour Retry-After.
Error codesCRAWLER_LIMIT_REACHEDRATE_LIMITED
- 500Unexpected server error. Retry with the same Idempotency-Key.
Error codesSERVER_ERROR
Request
curl -X POST 'https://api.agentency.com/v1/crawlers' \
-H "Authorization: Bearer <YOUR_KEY>" \
-H "Content-Type: application/json"
-d '{
"name": "name",
"description": "description",
"base_url": "base_url",
"crawl_mode": "crawl_mode",
"max_depth": "max_depth",
"max_pages": "max_pages",
"crawl_delay_seconds": "crawl_delay_seconds",
"crawl_concurrency": "crawl_concurrency"
}'Response
Example 200 response
{
"object": "sitemap_crawler",
"id": 0,
"name": "string",
"url": "string",
"status": "pending",
"chatbot_id": "string",
"error_code": "unreachable",
"created_at": "string",
"updated_at": "string"
}Built from the response schema, not recorded from a live call.
Retrieve a website crawler
url, its status and, after a failure, an error_code. Poll it while a crawl runs, or subscribe to crawl.completed and crawl.failed. The pages it collected are listed by GET /crawlers/{id}/pages.- Required scope
- crawlers:read
- Idempotency
- Read-only
- Rate limits
Integer. Website and sitemap crawlers are numbered separately, so the same number can name one of each.id(path)Website crawler idPlaceholder in the samples:
<CRAWLER_ID>Get it from
- POST /v1/crawlers returns it as
id - GET /v1/crawlers returns it as
data[].id - GET /v1/crawlers/queue returns it as
data[].id - Webhook crawler.created carries it as
data.object.id crawler.*andcrawl.*events carry only{object, id}, not the crawler kind: keep the kind with the id when you create the crawler.
- POST /v1/crawlers returns it as
Path parameters
idintegerRequiredThe website crawler id.
Responses
- 200
CrawlerResourceobjectstringRequiredThe crawler kind:website_crawler(/crawlers) orsitemap_crawler(/sitemap_crawlers). The two kinds are numbered separately.Possible values
sitemap_crawlerwebsite_crawleridintegerRequiredThe crawler id, unique within its kind.namestringnullableRequiredDisplay name.urlstringnullableRequiredThe start URL of a website crawler, or the sitemap URL of a sitemap crawler.statusstringRequiredpending(queued, or a recurring crawler waiting for its next run),running,paused,completed,failedorcancelled. Reachingcompletedorfailedemitscrawl.completedorcrawl.failed.Possible values
pendingrunningpausedcompletedfailedcancelledchatbot_idstringnullableRequiredThe chatbot the collected pages train;nullwhen the crawler only fills a collection.error_codestringnullableRequiredWhy the crawler last failed, as a stable code;nullwhen it has not.Possible values
unreachablehttp_errortoo_many_redirectsinvalid_sitemaptoo_largerobots_blockednever_startedknowledge_limit_reachedunsupported_content_encodingcorrupt_content_encodingunsupported_content_typecontent_too_shortnot_knowledge_indexnot_knowledge_mediaexcluded_by_patternduplicatecanonical_duplicatenear_duplicatesoft_404redirect_externalredirect_other_pagestalledextraction_failedremoved_from_knowledge_basechallenge_blockedunknownnullcreated_atstringnullableRequiredWhen the crawler was created (ISO 8601, UTC).updated_atstringnullableRequiredWhen the crawler last changed (ISO 8601, UTC).
- 400A tenant selector header named a tenant other than the API key's own (
ACCOUNT_SELECTOR_NOT_SUPPORTED): an all-digitX-Account-Idother than the key owner's id or, whileworkspaces.context_enabledis on, anX-Workspace-Idother than the key's workspace (ws_prefix optional, case-insensitive). A header naming the key's own tenant, or a non-numericX-Account-Id, is ignored; a key cannot switch tenants, so send neither.Error codesACCOUNT_SELECTOR_NOT_SUPPORTED
- 401Missing or invalid API key.
Error codesUNAUTHENTICATED
- 403The API key is missing a required scope.
Error codesACCOUNT_SUSPENDEDINSUFFICIENT_SCOPE
- 404The resource does not exist on this account.
Error codesNOT_FOUND
- 429Rate limited. Honour the Retry-After header before retrying.
Error codesRATE_LIMITED
- 500Unexpected server error. Retry with the same Idempotency-Key.
Error codesSERVER_ERROR
Request
curl -X GET 'https://api.agentency.com/v1/crawlers/<CRAWLER_ID>' \
-H "Authorization: Bearer <YOUR_KEY>" \
-H "Content-Type: application/json"Response
Example 200 response
{
"object": "website_crawler",
"id": 1,
"name": "Help centre",
"url": "https://shop.example.com/help",
"status": "completed",
"chatbot_id": 1,
"error_code": null,
"created_at": "2026-01-01T00:00:00+00:00",
"updated_at": "2026-01-01T00:00:00+00:00"
}Update a website crawler
name, max_pages or crawl_delay_seconds for its next run, and emits crawler.updated. Nothing is re-crawled until you call POST /crawlers/{id}/retry or the next scheduled run. A crawler that is running is 409 CRAWLER_RUNNING. Other settings (start URL, patterns, chatbot) are fixed: create a new crawler to change them.- Required scope
- crawlers:write
- Idempotency
- Accepts Idempotency-Key
- Webhook events
- crawler.updated
- Rate limits
Integer. Website and sitemap crawlers are numbered separately, so the same number can name one of each.id(path)Website crawler idPlaceholder in the samples:
<CRAWLER_ID>Get it from
- POST /v1/crawlers returns it as
id - GET /v1/crawlers returns it as
data[].id - GET /v1/crawlers/queue returns it as
data[].id - Webhook crawler.created carries it as
data.object.id crawler.*andcrawl.*events carry only{object, id}, not the crawler kind: keep the kind with the id when you create the crawler.
- POST /v1/crawlers returns it as
Path parameters
idintegerRequiredThe website crawler id.
Header parameters
Idempotency-KeystringOptionalMakes a retry safe. The first 2xx answer is stored for 24 h and replayed for the same key withIdempotency-Replayed: true; a retry while the first request runs is 409IDEMPOTENCY_IN_FLIGHT; the same key with a different payload is 422IDEMPOTENCY_KEY_REUSED; a malformed key is 400INVALID_IDEMPOTENCY_KEY.Min length:
16Max length:128Pattern:^[A-Za-z0-9_-]+$
Request body
PATCH /v1/crawlers/{id} (website crawlers).
is_active is deliberately NOT accepted (HI-22): flipping it through an
edit left a pending row the jobs silently skip. Deactivation is the
DELETE / cancel transition. Ceilings come from config/crawling.php
so the public contract cannot drift from the dashboard's (ME-27).namestringOptionalDisplay name, at most 255 characters.Max length:
255max_pagesintegerOptionalThe most pages to collect: 1 to 100,000 by default. Applies from the next run.Minimum:
1Maximum:100000crawl_delay_secondsintegerOptionalSeconds between requests to the site: 1 to 60 by default. Applies from the next run.Minimum:
1Maximum:60
Responses
- 200
CrawlerResourceobjectstringRequiredThe crawler kind:website_crawler(/crawlers) orsitemap_crawler(/sitemap_crawlers). The two kinds are numbered separately.Possible values
sitemap_crawlerwebsite_crawleridintegerRequiredThe crawler id, unique within its kind.namestringnullableRequiredDisplay name.urlstringnullableRequiredThe start URL of a website crawler, or the sitemap URL of a sitemap crawler.statusstringRequiredpending(queued, or a recurring crawler waiting for its next run),running,paused,completed,failedorcancelled. Reachingcompletedorfailedemitscrawl.completedorcrawl.failed.Possible values
pendingrunningpausedcompletedfailedcancelledchatbot_idstringnullableRequiredThe chatbot the collected pages train;nullwhen the crawler only fills a collection.error_codestringnullableRequiredWhy the crawler last failed, as a stable code;nullwhen it has not.Possible values
unreachablehttp_errortoo_many_redirectsinvalid_sitemaptoo_largerobots_blockednever_startedknowledge_limit_reachedunsupported_content_encodingcorrupt_content_encodingunsupported_content_typecontent_too_shortnot_knowledge_indexnot_knowledge_mediaexcluded_by_patternduplicatecanonical_duplicatenear_duplicatesoft_404redirect_externalredirect_other_pagestalledextraction_failedremoved_from_knowledge_basechallenge_blockedunknownnullcreated_atstringnullableRequiredWhen the crawler was created (ISO 8601, UTC).updated_atstringnullableRequiredWhen the crawler last changed (ISO 8601, UTC).
- 400A tenant selector header named a tenant other than the API key's own (
ACCOUNT_SELECTOR_NOT_SUPPORTED): an all-digitX-Account-Idother than the key owner's id or, whileworkspaces.context_enabledis on, anX-Workspace-Idother than the key's workspace (ws_prefix optional, case-insensitive). A header naming the key's own tenant, or a non-numericX-Account-Id, is ignored; a key cannot switch tenants, so send neither. A mutation that honoursIdempotency-Keyalso returnsINVALID_IDEMPOTENCY_KEYwhen that header is not 16–128[A-Za-z0-9_-]characters.Error codesACCOUNT_SELECTOR_NOT_SUPPORTEDINVALID_IDEMPOTENCY_KEY
- 401Missing or invalid API key.
Error codesUNAUTHENTICATED
- 403The API key is missing a required scope.
Error codesACCOUNT_SUSPENDEDINSUFFICIENT_SCOPE
- 404The resource does not exist on this account.
Error codesNOT_FOUND
- 409The request conflicts with the current resource state.
Error codesCRAWLER_RUNNINGIDEMPOTENCY_IN_FLIGHT
- 422Validation failed. See
error.details.Error codesIDEMPOTENCY_KEY_REUSEDVALIDATION_FAILED
- 429Rate limited. Honour the Retry-After header before retrying.
Error codesRATE_LIMITED
- 500Unexpected server error. Retry with the same Idempotency-Key.
Error codesSERVER_ERROR
Request
curl -X PATCH 'https://api.agentency.com/v1/crawlers/<CRAWLER_ID>' \
-H "Authorization: Bearer <YOUR_KEY>" \
-H "Content-Type: application/json"
-d '{
"name": "name",
"max_pages": 1,
"crawl_delay_seconds": 1
}'Response
Example 200 response
{
"object": "website_crawler",
"id": 1,
"name": "Help centre (EN)",
"url": "https://example.com/help",
"status": "pending",
"chatbot_id": 1,
"error_code": null,
"created_at": "2026-01-01T00:00:00+00:00",
"updated_at": "2026-01-01T00:00:00+00:00"
}Delete a website crawler
crawler.deleted. The pages it already saved stay as knowledge datasets: remove them with POST /knowledge/remove_from_system if you no longer want them.- Required scope
- crawlers:write
- Idempotency
- Accepts Idempotency-Key
- Webhook events
- crawler.deleted
- Rate limits
Integer. Website and sitemap crawlers are numbered separately, so the same number can name one of each.id(path)Website crawler idPlaceholder in the samples:
<CRAWLER_ID>Get it from
- POST /v1/crawlers returns it as
id - GET /v1/crawlers returns it as
data[].id - GET /v1/crawlers/queue returns it as
data[].id - Webhook crawler.created carries it as
data.object.id crawler.*andcrawl.*events carry only{object, id}, not the crawler kind: keep the kind with the id when you create the crawler.
- POST /v1/crawlers returns it as
Path parameters
idintegerRequiredThe website crawler id.
Header parameters
Idempotency-KeystringOptionalMakes a retry safe. The first 2xx answer is stored for 24 h and replayed for the same key withIdempotency-Replayed: true; a retry while the first request runs is 409IDEMPOTENCY_IN_FLIGHT; the same key with a different payload is 422IDEMPOTENCY_KEY_REUSED; a malformed key is 400INVALID_IDEMPOTENCY_KEY.Min length:
16Max length:128Pattern:^[A-Za-z0-9_-]+$
Responses
- 200Success.
objectstringRequiredAlways
website_crawleridintegerRequiredThe crawler id.deletedbooleanRequiredAlwaystrue.
- 400A tenant selector header named a tenant other than the API key's own (
ACCOUNT_SELECTOR_NOT_SUPPORTED): an all-digitX-Account-Idother than the key owner's id or, whileworkspaces.context_enabledis on, anX-Workspace-Idother than the key's workspace (ws_prefix optional, case-insensitive). A header naming the key's own tenant, or a non-numericX-Account-Id, is ignored; a key cannot switch tenants, so send neither. A mutation that honoursIdempotency-Keyalso returnsINVALID_IDEMPOTENCY_KEYwhen that header is not 16–128[A-Za-z0-9_-]characters.Error codesACCOUNT_SELECTOR_NOT_SUPPORTEDINVALID_IDEMPOTENCY_KEY
- 401Missing or invalid API key.
Error codesUNAUTHENTICATED
- 403The API key is missing a required scope.
Error codesACCOUNT_SUSPENDEDINSUFFICIENT_SCOPE
- 404The resource does not exist on this account.
Error codesNOT_FOUND
- 409The request conflicts with the current resource state.
Error codesIDEMPOTENCY_IN_FLIGHT
- 422Validation failed. See
error.details.Error codesIDEMPOTENCY_KEY_REUSED
- 429Rate limited. Honour the Retry-After header before retrying.
Error codesRATE_LIMITED
- 500Unexpected server error. Retry with the same Idempotency-Key.
Error codesSERVER_ERROR
Request
curl -X DELETE 'https://api.agentency.com/v1/crawlers/<CRAWLER_ID>' \
-H "Authorization: Bearer <YOUR_KEY>" \
-H "Content-Type: application/json"Response
Example 200 response
{
"object": "website_crawler",
"id": 1,
"deleted": true
}List a website crawler's pages
processed pages are knowledge datasets now, failed ones carry the error_code that explains why (unreachable, blocked by robots.txt, a duplicate of another page, too short, …). The datasets themselves are listed by GET /chatbots/{id}/knowledge.- Required scope
- crawlers:read
- Idempotency
- Read-only
- Rate limits
Integer. Website and sitemap crawlers are numbered separately, so the same number can name one of each.id(path)Website crawler idPlaceholder in the samples:
<CRAWLER_ID>Get it from
- POST /v1/crawlers returns it as
id - GET /v1/crawlers returns it as
data[].id - GET /v1/crawlers/queue returns it as
data[].id - Webhook crawler.created carries it as
data.object.id crawler.*andcrawl.*events carry only{object, id}, not the crawler kind: keep the kind with the id when you create the crawler.
- POST /v1/crawlers returns it as
Path parameters
idintegerRequiredThe website crawler id.
Query parameters
limitintegerOptionalPage size, clamped to 1–100.Default:
20Minimum:1Maximum:100starting_afterstringOptionalCursor from a previous page'snext_cursor: returns the page after it. A cursor minted for another list,sortororderis 422INVALID_CURSOR.ending_beforestringOptionalCursor from a previous page'sprevious_cursor: returns the page before it. Wins when both cursors are sent.created[gte]stringOptionalOnly rows created on or after this instant:YYYY-MM-DD(whole UTC day) or an RFC 3339 timestamp with a zone. Anything else is 422INVALID_PARAMETER.created[lte]stringOptionalOnly rows created on or before this instant:YYYY-MM-DD(whole UTC day) or an RFC 3339 timestamp with a zone. Anything else is 422INVALID_PARAMETER.
Responses
- 200Success.
objectstringRequiredAlways
listdataarray of CrawledPageResourceRequiredhas_morebooleanRequirednext_cursorstringnullableRequiredprevious_cursorstringnullableRequiredurlstringRequired
- 400A tenant selector header named a tenant other than the API key's own (
ACCOUNT_SELECTOR_NOT_SUPPORTED): an all-digitX-Account-Idother than the key owner's id or, whileworkspaces.context_enabledis on, anX-Workspace-Idother than the key's workspace (ws_prefix optional, case-insensitive). A header naming the key's own tenant, or a non-numericX-Account-Id, is ignored; a key cannot switch tenants, so send neither.Error codesACCOUNT_SELECTOR_NOT_SUPPORTED
- 401Missing or invalid API key.
Error codesUNAUTHENTICATED
- 403The API key is missing a required scope.
Error codesACCOUNT_SUSPENDEDINSUFFICIENT_SCOPE
- 404The resource does not exist on this account.
Error codesNOT_FOUND
- 422Validation failed. See
error.details.Error codesINVALID_CURSORINVALID_PARAMETER
- 429Rate limited. Honour the Retry-After header before retrying.
Error codesRATE_LIMITED
- 500Unexpected server error. Retry with the same Idempotency-Key.
Error codesSERVER_ERROR
Request
curl -X GET 'https://api.agentency.com/v1/crawlers/<CRAWLER_ID>/pages' \
-H "Authorization: Bearer <YOUR_KEY>" \
-H "Content-Type: application/json"Response
Example 200 response
{
"object": "list",
"data": [
{
"object": "crawled_page",
"id": 1,
"url": "https://shop.example.com/help/refunds",
"status": "processed",
"error_code": null
}
],
"has_more": false,
"next_cursor": null,
"previous_cursor": null,
"url": "/v1/crawlers/1/pages"
}Check a website crawler's outcome
status and failure error_code, without the rest of the crawler. It carries no page counts: count the pages of GET /crawlers/{id}/pages by status for those.- Required scope
- crawlers:read
- Idempotency
- Read-only
- Rate limits
Integer. Website and sitemap crawlers are numbered separately, so the same number can name one of each.id(path)Website crawler idPlaceholder in the samples:
<CRAWLER_ID>Get it from
- POST /v1/crawlers returns it as
id - GET /v1/crawlers returns it as
data[].id - GET /v1/crawlers/queue returns it as
data[].id - Webhook crawler.created carries it as
data.object.id crawler.*andcrawl.*events carry only{object, id}, not the crawler kind: keep the kind with the id when you create the crawler.
- POST /v1/crawlers returns it as
Path parameters
idintegerRequiredThe website crawler id.
Responses
- 200Success.
objectstringRequiredAlways
crawler_statisticsidintegerRequiredThe crawler id.statusstringRequiredpending,running,paused,completed,failedorcancelled.error_codestringnullableRequiredWhy the crawler last failed, as a stable code;nullwhen it has not.
- 400A tenant selector header named a tenant other than the API key's own (
ACCOUNT_SELECTOR_NOT_SUPPORTED): an all-digitX-Account-Idother than the key owner's id or, whileworkspaces.context_enabledis on, anX-Workspace-Idother than the key's workspace (ws_prefix optional, case-insensitive). A header naming the key's own tenant, or a non-numericX-Account-Id, is ignored; a key cannot switch tenants, so send neither.Error codesACCOUNT_SELECTOR_NOT_SUPPORTED
- 401Missing or invalid API key.
Error codesUNAUTHENTICATED
- 403The API key is missing a required scope.
Error codesACCOUNT_SUSPENDEDINSUFFICIENT_SCOPE
- 404The resource does not exist on this account.
Error codesNOT_FOUND
- 429Rate limited. Honour the Retry-After header before retrying.
Error codesRATE_LIMITED
- 500Unexpected server error. Retry with the same Idempotency-Key.
Error codesSERVER_ERROR
Request
curl -X GET 'https://api.agentency.com/v1/crawlers/<CRAWLER_ID>/statistics' \
-H "Authorization: Bearer <YOUR_KEY>" \
-H "Content-Type: application/json"Response
Example 200 response
{
"object": "crawler_statistics",
"id": 1,
"status": "completed",
"error_code": null
}List sitemap crawlers
GET /crawlers.- Required scope
- crawlers:read
- Idempotency
- Read-only
- Rate limits
Query parameters
limitintegerOptionalPage size, clamped to 1–100.Default:
20Minimum:1Maximum:100starting_afterstringOptionalCursor from a previous page'snext_cursor: returns the page after it. A cursor minted for another list,sortororderis 422INVALID_CURSOR.ending_beforestringOptionalCursor from a previous page'sprevious_cursor: returns the page before it. Wins when both cursors are sent.created[gte]stringOptionalOnly rows created on or after this instant:YYYY-MM-DD(whole UTC day) or an RFC 3339 timestamp with a zone. Anything else is 422INVALID_PARAMETER.created[lte]stringOptionalOnly rows created on or before this instant:YYYY-MM-DD(whole UTC day) or an RFC 3339 timestamp with a zone. Anything else is 422INVALID_PARAMETER.
Responses
- 200Success.
objectstringRequiredAlways
listdataarray of CrawlerResourceRequiredhas_morebooleanRequirednext_cursorstringnullableRequiredprevious_cursorstringnullableRequiredurlstringRequiredAlways
/v1/sitemap_crawlers
- 400A tenant selector header named a tenant other than the API key's own (
ACCOUNT_SELECTOR_NOT_SUPPORTED): an all-digitX-Account-Idother than the key owner's id or, whileworkspaces.context_enabledis on, anX-Workspace-Idother than the key's workspace (ws_prefix optional, case-insensitive). A header naming the key's own tenant, or a non-numericX-Account-Id, is ignored; a key cannot switch tenants, so send neither.Error codesACCOUNT_SELECTOR_NOT_SUPPORTED
- 401Missing or invalid API key.
Error codesUNAUTHENTICATED
- 403The API key is missing a required scope.
Error codesACCOUNT_SUSPENDEDINSUFFICIENT_SCOPE
- 422Validation failed. See
error.details.Error codesINVALID_CURSORINVALID_PARAMETER
- 429Rate limited. Honour the Retry-After header before retrying.
Error codesRATE_LIMITED
- 500Unexpected server error. Retry with the same Idempotency-Key.
Error codesSERVER_ERROR
Request
curl -X GET 'https://api.agentency.com/v1/sitemap_crawlers' \
-H "Authorization: Bearer <YOUR_KEY>" \
-H "Content-Type: application/json"Response
Example 200 response
{
"object": "list",
"data": [
{
"object": "sitemap_crawler",
"id": 1,
"name": "Shop sitemap",
"url": "https://shop.example.com/sitemap.xml",
"status": "completed",
"chatbot_id": 1,
"error_code": null,
"created_at": "2026-01-01T00:00:00+00:00",
"updated_at": "2026-01-01T00:00:00+00:00"
}
],
"has_more": false,
"next_cursor": null,
"previous_cursor": null,
"url": "/v1/sitemap_crawlers"
}Create a sitemap crawler
sitemap_url lists (following a sitemap index into its sitemaps) and saves each as a knowledge dataset in knowledge_collection_id (or the chatbot's default collection), and returns it with 201, status: pending. The first scan starts on its own within seconds — there is no need to call POST /sitemap_crawlers/{id}/scan — and later scans follow scan_frequency; a page whose content has not changed since the last scan is marked unchanged and not retrained. With auto_train the collected pages are trained into chatbot_id, each dataset emitting its own knowledge.dataset.trained or .failed.
Before anything is created the URL is checked (only public http(s) addresses) and read: a blocked address or a URL that is not a usable sitemap is 422 VALIDATION_FAILED (details.errors says why; POST /sitemap_crawlers/validate_url runs the same check alone). A chatbot already at its plan's knowledge allowance is 402 KNOWLEDGE_PLAN_SIZE_EXCEEDED; an account already running its maximum of concurrent sitemap crawls (10 by default) is 429 CRAWLER_LIMIT_REACHED. When the same sitemap already has a pending or running crawler for the same chatbot, that crawler is returned with 200 and no event, instead of a second one.- Required scope
- crawlers:write
- Idempotency
- Accepts Idempotency-Key
- Webhook events
- crawler.created
- Rate limits
Integer.chatbot_id(body)Chatbot idPlaceholder in the samples:
<CHATBOT_ID>Get it from
- GET /v1/chatbots returns it as
data[].id - POST /v1/chatbots returns it as
id - GET /v1/chatbots/by_handle/{handle} returns it as
id - Webhook chatbot.created carries it as
data.object.id - In the dashboard, it is the number in a chatbot's address:
/dashboard/chatbots/{id}.
- GET /v1/chatbots returns it as
Integer.knowledge_collection_id(body)Knowledge collection idPlaceholder in the samples:
<COLLECTION_ID>Get it from
- POST /v1/knowledge/collections returns it as
id - GET /v1/knowledge/collections returns it as
data[].id - POST /v1/knowledge/collections/auto_create returns it as
id - GET /v1/knowledge/{id} returns it as
collection_id - Webhook knowledge.collection.created carries it as
data.object.id - Adding knowledge or a crawl with only
chatbot_idfiles it in the chatbot's default collection, created on first use: read its id ascollection_idon any of the chatbot's datasets.
- POST /v1/knowledge/collections returns it as
Header parameters
Idempotency-KeystringOptionalMakes a retry safe. The first 2xx answer is stored for 24 h and replayed for the same key withIdempotency-Replayed: true; a retry while the first request runs is 409IDEMPOTENCY_IN_FLIGHT; the same key with a different payload is 422IDEMPOTENCY_KEY_REUSED; a malformed key is 400INVALID_IDEMPOTENCY_KEY.Min length:
16Max length:128Pattern:^[A-Za-z0-9_-]+$
Request body
/v1 start sitemap crawling payload. Field set is pinned on this class so a
dashboard FormRequest tweak cannot silently widen the public contract.
Authorization is inherited: the SitemapCrawlPolicy::create gate (HI-15)
applies to API-key callers too, so a member-bound key without
knowledge.manage cannot start crawls the dashboard would refuse.namestringRequiredDisplay name, at most 255 characters.Max length:
255sitemap_urlstringRequiredThe publichttp(s)URL of asitemap.xmlor sitemap index, at most 2048 characters. Checked before it is fetched — a private, loopback, link-local or otherwise blocked address is 422VALIDATION_FAILEDon this field — then read once: a URL that is not a usable sitemap is 422VALIDATION_FAILEDwith the reasons indetails.errors.Format:
uriMax length:2048chatbot_idintegernullableOptionalThe chatbot the collected pages train. A sitemap crawler of the same URL for the same chatbot that is still pending or running is returned instead of a new one.knowledge_collection_idintegernullableOptionalThe collection to file the collected pages in. Optional withchatbot_id, when the chatbot's default collection is used (created on first use); required without it.auto_trainbooleannullableOptionalTrain each collected page intochatbot_id(defaulttrue).urls_per_scanintegernullableOptionalSitemap URLs fetched per batch of a scan: 1 to 1000, default 500.Minimum:
1Maximum:1000max_total_urlsintegernullableOptionalThe most sitemap URLs to collect: 1 to 100,000 by default. Omit it for no cap of its own.Minimum:
1Maximum:100000crawl_delay_secondsintegernullableOptionalSeconds between requests to the site: 0 to 60, default 1.Minimum:
0Maximum:60respect_robots_txtbooleannullableOptionalWhether to obey the site'srobots.txt(defaulttrue). A URL it disallows isskippedwitherror_code: robots_blocked.user_agentstringnullableOptionalTheUser-Agentto send, at most 255 characters. Defaults to the platform crawler's.Max length:
255scan_frequencystringnullableOptionalHow often the sitemap is scanned again for new and changed pages:hourly(default),daily,weekly, ormanual(only when you callPOST /sitemap_crawlers/{id}/scan).Possible values
hourlydailyweeklymanualnullcontent_selectorsobjectOptionalCSS selectors that pick each page's content. Omit for the platform defaults.exclude_patternsarray of stringnullableOptionalNever collect URLs matching one of these patterns (a glob or a plain substring), at most 50 of 255 characters each — for example a tag or category archive.Max items:
50training_optionsobjectOptionalHow collected pages become knowledge. Omitted keys take the platform defaults.
Responses
- 200
CrawlerResourceobjectstringRequiredThe crawler kind:website_crawler(/crawlers) orsitemap_crawler(/sitemap_crawlers). The two kinds are numbered separately.Possible values
sitemap_crawlerwebsite_crawleridintegerRequiredThe crawler id, unique within its kind.namestringnullableRequiredDisplay name.urlstringnullableRequiredThe start URL of a website crawler, or the sitemap URL of a sitemap crawler.statusstringRequiredpending(queued, or a recurring crawler waiting for its next run),running,paused,completed,failedorcancelled. Reachingcompletedorfailedemitscrawl.completedorcrawl.failed.Possible values
pendingrunningpausedcompletedfailedcancelledchatbot_idstringnullableRequiredThe chatbot the collected pages train;nullwhen the crawler only fills a collection.error_codestringnullableRequiredWhy the crawler last failed, as a stable code;nullwhen it has not.Possible values
unreachablehttp_errortoo_many_redirectsinvalid_sitemaptoo_largerobots_blockednever_startedknowledge_limit_reachedunsupported_content_encodingcorrupt_content_encodingunsupported_content_typecontent_too_shortnot_knowledge_indexnot_knowledge_mediaexcluded_by_patternduplicatecanonical_duplicatenear_duplicatesoft_404redirect_externalredirect_other_pagestalledextraction_failedremoved_from_knowledge_basechallenge_blockedunknownnullcreated_atstringnullableRequiredWhen the crawler was created (ISO 8601, UTC).updated_atstringnullableRequiredWhen the crawler last changed (ISO 8601, UTC).
- 201
CrawlerResourceobjectstringRequiredThe crawler kind:website_crawler(/crawlers) orsitemap_crawler(/sitemap_crawlers). The two kinds are numbered separately.Possible values
sitemap_crawlerwebsite_crawleridintegerRequiredThe crawler id, unique within its kind.namestringnullableRequiredDisplay name.urlstringnullableRequiredThe start URL of a website crawler, or the sitemap URL of a sitemap crawler.statusstringRequiredpending(queued, or a recurring crawler waiting for its next run),running,paused,completed,failedorcancelled. Reachingcompletedorfailedemitscrawl.completedorcrawl.failed.Possible values
pendingrunningpausedcompletedfailedcancelledchatbot_idstringnullableRequiredThe chatbot the collected pages train;nullwhen the crawler only fills a collection.error_codestringnullableRequiredWhy the crawler last failed, as a stable code;nullwhen it has not.Possible values
unreachablehttp_errortoo_many_redirectsinvalid_sitemaptoo_largerobots_blockednever_startedknowledge_limit_reachedunsupported_content_encodingcorrupt_content_encodingunsupported_content_typecontent_too_shortnot_knowledge_indexnot_knowledge_mediaexcluded_by_patternduplicatecanonical_duplicatenear_duplicatesoft_404redirect_externalredirect_other_pagestalledextraction_failedremoved_from_knowledge_basechallenge_blockedunknownnullcreated_atstringnullableRequiredWhen the crawler was created (ISO 8601, UTC).updated_atstringnullableRequiredWhen the crawler last changed (ISO 8601, UTC).
- 400A tenant selector header named a tenant other than the API key's own (
ACCOUNT_SELECTOR_NOT_SUPPORTED): an all-digitX-Account-Idother than the key owner's id or, whileworkspaces.context_enabledis on, anX-Workspace-Idother than the key's workspace (ws_prefix optional, case-insensitive). A header naming the key's own tenant, or a non-numericX-Account-Id, is ignored; a key cannot switch tenants, so send neither. A mutation that honoursIdempotency-Keyalso returnsINVALID_IDEMPOTENCY_KEYwhen that header is not 16–128[A-Za-z0-9_-]characters.Error codesACCOUNT_SELECTOR_NOT_SUPPORTEDINVALID_IDEMPOTENCY_KEY
- 401Missing or invalid API key.
Error codesUNAUTHENTICATED
- 402A billing gate refused the request (plan limit, monthly AI budget or message credits). See
error.code.Error codesKNOWLEDGE_PLAN_SIZE_EXCEEDED
- 403The API key is missing a required scope.
Error codesACCOUNT_SUSPENDEDINSUFFICIENT_SCOPE
- 404The resource does not exist on this account.
Error codesNOT_FOUND
- 409The request conflicts with the current resource state.
Error codesIDEMPOTENCY_IN_FLIGHT
- 422Validation failed. See
error.details.Error codesBLOCKED_DOMAINCHALLENGE_BLOCKEDCONTENT_TOO_LARGECORRUPT_CONTENT_ENCODINGCRAWLING_ERRORIDEMPOTENCY_KEY_REUSEDINVALID_SITEMAPROBOTS_BLOCKEDUNSUPPORTED_CONTENT_ENCODINGUNSUPPORTED_CONTENT_TYPEUPSTREAM_HTTP_ERRORVALIDATION_FAILED
- 429Rate limited. Honour Retry-After.
Error codesCRAWLER_LIMIT_REACHEDRATE_LIMITED
- 500Unexpected server error. Retry with the same Idempotency-Key.
Error codesSERVER_ERROR
Request
curl -X POST 'https://api.agentency.com/v1/sitemap_crawlers' \
-H "Authorization: Bearer <YOUR_KEY>" \
-H "Content-Type: application/json"
-d '{
"name": "name",
"sitemap_url": "sitemap_url",
"chatbot_id": 1,
"knowledge_collection_id": 1,
"auto_train": "auto_train",
"urls_per_scan": "urls_per_scan",
"max_total_urls": "max_total_urls",
"crawl_delay_seconds": "crawl_delay_seconds"
}'Response
Example 200 response
{
"object": "sitemap_crawler",
"id": 0,
"name": "string",
"url": "string",
"status": "pending",
"chatbot_id": "string",
"error_code": "unreachable",
"created_at": "string",
"updated_at": "string"
}Built from the response schema, not recorded from a live call.
Retrieve a sitemap crawler
url, its status and, after a failure, an error_code. A recurring crawler reads pending while it waits for its next scan. Each URL the sitemap lists is reported by GET /sitemap_crawlers/{id}/pages.- Required scope
- crawlers:read
- Idempotency
- Read-only
- Rate limits
Integer. Website and sitemap crawlers are numbered separately, so the same number can name one of each.id(path)Sitemap crawler idPlaceholder in the samples:
<SITEMAP_CRAWLER_ID>Get it from
- POST /v1/sitemap_crawlers returns it as
id - GET /v1/sitemap_crawlers returns it as
data[].id - Webhook crawler.created carries it as
data.object.id crawler.*andcrawl.*events carry only{object, id}, not the crawler kind: keep the kind with the id when you create the crawler.
- POST /v1/sitemap_crawlers returns it as
Path parameters
idintegerRequiredThe sitemap crawler id.
Responses
- 200
CrawlerResourceobjectstringRequiredThe crawler kind:website_crawler(/crawlers) orsitemap_crawler(/sitemap_crawlers). The two kinds are numbered separately.Possible values
sitemap_crawlerwebsite_crawleridintegerRequiredThe crawler id, unique within its kind.namestringnullableRequiredDisplay name.urlstringnullableRequiredThe start URL of a website crawler, or the sitemap URL of a sitemap crawler.statusstringRequiredpending(queued, or a recurring crawler waiting for its next run),running,paused,completed,failedorcancelled. Reachingcompletedorfailedemitscrawl.completedorcrawl.failed.Possible values
pendingrunningpausedcompletedfailedcancelledchatbot_idstringnullableRequiredThe chatbot the collected pages train;nullwhen the crawler only fills a collection.error_codestringnullableRequiredWhy the crawler last failed, as a stable code;nullwhen it has not.Possible values
unreachablehttp_errortoo_many_redirectsinvalid_sitemaptoo_largerobots_blockednever_startedknowledge_limit_reachedunsupported_content_encodingcorrupt_content_encodingunsupported_content_typecontent_too_shortnot_knowledge_indexnot_knowledge_mediaexcluded_by_patternduplicatecanonical_duplicatenear_duplicatesoft_404redirect_externalredirect_other_pagestalledextraction_failedremoved_from_knowledge_basechallenge_blockedunknownnullcreated_atstringnullableRequiredWhen the crawler was created (ISO 8601, UTC).updated_atstringnullableRequiredWhen the crawler last changed (ISO 8601, UTC).
- 400A tenant selector header named a tenant other than the API key's own (
ACCOUNT_SELECTOR_NOT_SUPPORTED): an all-digitX-Account-Idother than the key owner's id or, whileworkspaces.context_enabledis on, anX-Workspace-Idother than the key's workspace (ws_prefix optional, case-insensitive). A header naming the key's own tenant, or a non-numericX-Account-Id, is ignored; a key cannot switch tenants, so send neither.Error codesACCOUNT_SELECTOR_NOT_SUPPORTED
- 401Missing or invalid API key.
Error codesUNAUTHENTICATED
- 403The API key is missing a required scope.
Error codesACCOUNT_SUSPENDEDINSUFFICIENT_SCOPE
- 404The resource does not exist on this account.
Error codesNOT_FOUND
- 429Rate limited. Honour the Retry-After header before retrying.
Error codesRATE_LIMITED
- 500Unexpected server error. Retry with the same Idempotency-Key.
Error codesSERVER_ERROR
Request
curl -X GET 'https://api.agentency.com/v1/sitemap_crawlers/<SITEMAP_CRAWLER_ID>' \
-H "Authorization: Bearer <YOUR_KEY>" \
-H "Content-Type: application/json"Response
Example 200 response
{
"object": "sitemap_crawler",
"id": 1,
"name": "Shop sitemap",
"url": "https://shop.example.com/sitemap.xml",
"status": "completed",
"chatbot_id": 1,
"error_code": null,
"created_at": "2026-01-01T00:00:00+00:00",
"updated_at": "2026-01-01T00:00:00+00:00"
}Update a sitemap crawler
name, urls_per_scan, max_total_urls, crawl_delay_seconds or scan_frequency for its next scan, and emits crawler.updated. A crawler with a scan running is 409 CRAWLER_RUNNING. The sitemap URL, patterns and chatbot are fixed: create a new crawler to change them.- Required scope
- crawlers:write
- Idempotency
- Accepts Idempotency-Key
- Webhook events
- crawler.updated
- Rate limits
Integer. Website and sitemap crawlers are numbered separately, so the same number can name one of each.id(path)Sitemap crawler idPlaceholder in the samples:
<SITEMAP_CRAWLER_ID>Get it from
- POST /v1/sitemap_crawlers returns it as
id - GET /v1/sitemap_crawlers returns it as
data[].id - Webhook crawler.created carries it as
data.object.id crawler.*andcrawl.*events carry only{object, id}, not the crawler kind: keep the kind with the id when you create the crawler.
- POST /v1/sitemap_crawlers returns it as
Path parameters
idintegerRequiredThe sitemap crawler id.
Header parameters
Idempotency-KeystringOptionalMakes a retry safe. The first 2xx answer is stored for 24 h and replayed for the same key withIdempotency-Replayed: true; a retry while the first request runs is 409IDEMPOTENCY_IN_FLIGHT; the same key with a different payload is 422IDEMPOTENCY_KEY_REUSED; a malformed key is 400INVALID_IDEMPOTENCY_KEY.Min length:
16Max length:128Pattern:^[A-Za-z0-9_-]+$
Request body
PATCH /v1/sitemap_crawlers/{id}.
Split from {@see UpdateCrawlerRequest} (ME-27): that request accepted
max_pages, which is not a sitemap_crawls column — a
MassAssignmentException off production and a silent no-op on it. The
field set here is the sitemap crawl's own tunables, with ceilings read
from config/crawling.php like the dashboard StartSitemapCrawlingRequest.
is_active is not accepted (HI-22) — deactivation is the DELETE transition.namestringOptionalDisplay name, at most 255 characters.Max length:
255urls_per_scanintegerOptionalSitemap URLs fetched per batch of a scan: 1 to 1000.Minimum:
1Maximum:1000max_total_urlsintegernullableOptionalThe most sitemap URLs to collect: 1 to 100,000 by default;nullremoves the cap of its own.Minimum:
1Maximum:100000crawl_delay_secondsintegerOptionalSeconds between requests to the site: 0 to 60 by default.Minimum:
0Maximum:60scan_frequencystringOptionalHow often the sitemap is scanned again:hourly,daily,weeklyormanual(only when you callPOST /sitemap_crawlers/{id}/scan).Possible values
hourlydailyweeklymanual
Responses
- 200
CrawlerResourceobjectstringRequiredThe crawler kind:website_crawler(/crawlers) orsitemap_crawler(/sitemap_crawlers). The two kinds are numbered separately.Possible values
sitemap_crawlerwebsite_crawleridintegerRequiredThe crawler id, unique within its kind.namestringnullableRequiredDisplay name.urlstringnullableRequiredThe start URL of a website crawler, or the sitemap URL of a sitemap crawler.statusstringRequiredpending(queued, or a recurring crawler waiting for its next run),running,paused,completed,failedorcancelled. Reachingcompletedorfailedemitscrawl.completedorcrawl.failed.Possible values
pendingrunningpausedcompletedfailedcancelledchatbot_idstringnullableRequiredThe chatbot the collected pages train;nullwhen the crawler only fills a collection.error_codestringnullableRequiredWhy the crawler last failed, as a stable code;nullwhen it has not.Possible values
unreachablehttp_errortoo_many_redirectsinvalid_sitemaptoo_largerobots_blockednever_startedknowledge_limit_reachedunsupported_content_encodingcorrupt_content_encodingunsupported_content_typecontent_too_shortnot_knowledge_indexnot_knowledge_mediaexcluded_by_patternduplicatecanonical_duplicatenear_duplicatesoft_404redirect_externalredirect_other_pagestalledextraction_failedremoved_from_knowledge_basechallenge_blockedunknownnullcreated_atstringnullableRequiredWhen the crawler was created (ISO 8601, UTC).updated_atstringnullableRequiredWhen the crawler last changed (ISO 8601, UTC).
- 400A tenant selector header named a tenant other than the API key's own (
ACCOUNT_SELECTOR_NOT_SUPPORTED): an all-digitX-Account-Idother than the key owner's id or, whileworkspaces.context_enabledis on, anX-Workspace-Idother than the key's workspace (ws_prefix optional, case-insensitive). A header naming the key's own tenant, or a non-numericX-Account-Id, is ignored; a key cannot switch tenants, so send neither. A mutation that honoursIdempotency-Keyalso returnsINVALID_IDEMPOTENCY_KEYwhen that header is not 16–128[A-Za-z0-9_-]characters.Error codesACCOUNT_SELECTOR_NOT_SUPPORTEDINVALID_IDEMPOTENCY_KEY
- 401Missing or invalid API key.
Error codesUNAUTHENTICATED
- 403The API key is missing a required scope.
Error codesACCOUNT_SUSPENDEDINSUFFICIENT_SCOPE
- 404The resource does not exist on this account.
Error codesNOT_FOUND
- 409The request conflicts with the current resource state.
Error codesCRAWLER_RUNNINGIDEMPOTENCY_IN_FLIGHT
- 422Validation failed. See
error.details.Error codesIDEMPOTENCY_KEY_REUSEDVALIDATION_FAILED
- 429Rate limited. Honour the Retry-After header before retrying.
Error codesRATE_LIMITED
- 500Unexpected server error. Retry with the same Idempotency-Key.
Error codesSERVER_ERROR
Request
curl -X PATCH 'https://api.agentency.com/v1/sitemap_crawlers/<SITEMAP_CRAWLER_ID>' \
-H "Authorization: Bearer <YOUR_KEY>" \
-H "Content-Type: application/json"
-d '{
"name": "name",
"urls_per_scan": 1,
"max_total_urls": "max_total_urls",
"crawl_delay_seconds": 1,
"scan_frequency": "scan_frequency"
}'Response
Example 200 response
{
"object": "sitemap_crawler",
"id": 1,
"name": "Product pages",
"url": "https://example.com/sitemap.xml",
"status": "pending",
"chatbot_id": 1,
"error_code": null,
"created_at": "2026-01-01T00:00:00+00:00",
"updated_at": "2026-01-01T00:00:00+00:00"
}Delete a sitemap crawler
crawler.deleted. No further scans run. The pages it already saved stay as knowledge datasets: remove them with POST /knowledge/remove_from_system if you no longer want them.- Required scope
- crawlers:write
- Idempotency
- Accepts Idempotency-Key
- Webhook events
- crawler.deleted
- Rate limits
Integer. Website and sitemap crawlers are numbered separately, so the same number can name one of each.id(path)Sitemap crawler idPlaceholder in the samples:
<SITEMAP_CRAWLER_ID>Get it from
- POST /v1/sitemap_crawlers returns it as
id - GET /v1/sitemap_crawlers returns it as
data[].id - Webhook crawler.created carries it as
data.object.id crawler.*andcrawl.*events carry only{object, id}, not the crawler kind: keep the kind with the id when you create the crawler.
- POST /v1/sitemap_crawlers returns it as
Path parameters
idintegerRequiredThe sitemap crawler id.
Header parameters
Idempotency-KeystringOptionalMakes a retry safe. The first 2xx answer is stored for 24 h and replayed for the same key withIdempotency-Replayed: true; a retry while the first request runs is 409IDEMPOTENCY_IN_FLIGHT; the same key with a different payload is 422IDEMPOTENCY_KEY_REUSED; a malformed key is 400INVALID_IDEMPOTENCY_KEY.Min length:
16Max length:128Pattern:^[A-Za-z0-9_-]+$
Responses
- 200Success.
objectstringRequiredAlways
sitemap_crawleridintegerRequiredThe crawler id.deletedbooleanRequiredAlwaystrue.
- 400A tenant selector header named a tenant other than the API key's own (
ACCOUNT_SELECTOR_NOT_SUPPORTED): an all-digitX-Account-Idother than the key owner's id or, whileworkspaces.context_enabledis on, anX-Workspace-Idother than the key's workspace (ws_prefix optional, case-insensitive). A header naming the key's own tenant, or a non-numericX-Account-Id, is ignored; a key cannot switch tenants, so send neither. A mutation that honoursIdempotency-Keyalso returnsINVALID_IDEMPOTENCY_KEYwhen that header is not 16–128[A-Za-z0-9_-]characters.Error codesACCOUNT_SELECTOR_NOT_SUPPORTEDINVALID_IDEMPOTENCY_KEY
- 401Missing or invalid API key.
Error codesUNAUTHENTICATED
- 403The API key is missing a required scope.
Error codesACCOUNT_SUSPENDEDINSUFFICIENT_SCOPE
- 404The resource does not exist on this account.
Error codesNOT_FOUND
- 409The request conflicts with the current resource state.
Error codesIDEMPOTENCY_IN_FLIGHT
- 422Validation failed. See
error.details.Error codesIDEMPOTENCY_KEY_REUSED
- 429Rate limited. Honour the Retry-After header before retrying.
Error codesRATE_LIMITED
- 500Unexpected server error. Retry with the same Idempotency-Key.
Error codesSERVER_ERROR
Request
curl -X DELETE 'https://api.agentency.com/v1/sitemap_crawlers/<SITEMAP_CRAWLER_ID>' \
-H "Authorization: Bearer <YOUR_KEY>" \
-H "Content-Type: application/json"Response
Example 200 response
{
"object": "sitemap_crawler",
"id": 1,
"deleted": true
}List a sitemap crawler's URLs
crawled or updated pages are knowledge datasets, unchanged ones were re-fetched with the same content, skipped and failed ones carry the error_code that explains why (excluded by a pattern, blocked by robots.txt, a duplicate, unreachable, …).- Required scope
- crawlers:read
- Idempotency
- Read-only
- Rate limits
Integer. Website and sitemap crawlers are numbered separately, so the same number can name one of each.id(path)Sitemap crawler idPlaceholder in the samples:
<SITEMAP_CRAWLER_ID>Get it from
- POST /v1/sitemap_crawlers returns it as
id - GET /v1/sitemap_crawlers returns it as
data[].id - Webhook crawler.created carries it as
data.object.id crawler.*andcrawl.*events carry only{object, id}, not the crawler kind: keep the kind with the id when you create the crawler.
- POST /v1/sitemap_crawlers returns it as
Path parameters
idintegerRequiredThe sitemap crawler id.
Query parameters
limitintegerOptionalPage size, clamped to 1–100.Default:
20Minimum:1Maximum:100starting_afterstringOptionalCursor from a previous page'snext_cursor: returns the page after it. A cursor minted for another list,sortororderis 422INVALID_CURSOR.ending_beforestringOptionalCursor from a previous page'sprevious_cursor: returns the page before it. Wins when both cursors are sent.created[gte]stringOptionalOnly rows created on or after this instant:YYYY-MM-DD(whole UTC day) or an RFC 3339 timestamp with a zone. Anything else is 422INVALID_PARAMETER.created[lte]stringOptionalOnly rows created on or before this instant:YYYY-MM-DD(whole UTC day) or an RFC 3339 timestamp with a zone. Anything else is 422INVALID_PARAMETER.
Responses
- 200Success.
objectstringRequiredAlways
listdataarray of SitemapUrlResourceRequiredhas_morebooleanRequirednext_cursorstringnullableRequiredprevious_cursorstringnullableRequiredurlstringRequired
- 400A tenant selector header named a tenant other than the API key's own (
ACCOUNT_SELECTOR_NOT_SUPPORTED): an all-digitX-Account-Idother than the key owner's id or, whileworkspaces.context_enabledis on, anX-Workspace-Idother than the key's workspace (ws_prefix optional, case-insensitive). A header naming the key's own tenant, or a non-numericX-Account-Id, is ignored; a key cannot switch tenants, so send neither.Error codesACCOUNT_SELECTOR_NOT_SUPPORTED
- 401Missing or invalid API key.
Error codesUNAUTHENTICATED
- 403The API key is missing a required scope.
Error codesACCOUNT_SUSPENDEDINSUFFICIENT_SCOPE
- 404The resource does not exist on this account.
Error codesNOT_FOUND
- 422Validation failed. See
error.details.Error codesINVALID_CURSORINVALID_PARAMETER
- 429Rate limited. Honour the Retry-After header before retrying.
Error codesRATE_LIMITED
- 500Unexpected server error. Retry with the same Idempotency-Key.
Error codesSERVER_ERROR
Request
curl -X GET 'https://api.agentency.com/v1/sitemap_crawlers/<SITEMAP_CRAWLER_ID>/pages' \
-H "Authorization: Bearer <YOUR_KEY>" \
-H "Content-Type: application/json"Response
Example 200 response
{
"object": "list",
"data": [
{
"object": "sitemap_url",
"id": 1,
"url": "https://shop.example.com/shipping",
"status": "crawled",
"error_code": null
}
],
"has_more": false,
"next_cursor": null,
"previous_cursor": null,
"url": "/v1/sitemap_crawlers/1/pages"
}Check a sitemap crawler's outcome
status and failure error_code, without the rest of the crawler. It carries no page counts: count the rows of GET /sitemap_crawlers/{id}/pages by status for those.- Required scope
- crawlers:read
- Idempotency
- Read-only
- Rate limits
Integer. Website and sitemap crawlers are numbered separately, so the same number can name one of each.id(path)Sitemap crawler idPlaceholder in the samples:
<SITEMAP_CRAWLER_ID>Get it from
- POST /v1/sitemap_crawlers returns it as
id - GET /v1/sitemap_crawlers returns it as
data[].id - Webhook crawler.created carries it as
data.object.id crawler.*andcrawl.*events carry only{object, id}, not the crawler kind: keep the kind with the id when you create the crawler.
- POST /v1/sitemap_crawlers returns it as
Path parameters
idintegerRequiredThe sitemap crawler id.
Responses
- 200Success.
objectstringRequiredAlways
crawler_statisticsidintegerRequiredThe crawler id.statusstringRequiredpending,running,paused,completed,failedorcancelled.error_codestringnullableRequiredWhy the crawler last failed, as a stable code;nullwhen it has not.
- 400A tenant selector header named a tenant other than the API key's own (
ACCOUNT_SELECTOR_NOT_SUPPORTED): an all-digitX-Account-Idother than the key owner's id or, whileworkspaces.context_enabledis on, anX-Workspace-Idother than the key's workspace (ws_prefix optional, case-insensitive). A header naming the key's own tenant, or a non-numericX-Account-Id, is ignored; a key cannot switch tenants, so send neither.Error codesACCOUNT_SELECTOR_NOT_SUPPORTED
- 401Missing or invalid API key.
Error codesUNAUTHENTICATED
- 403The API key is missing a required scope.
Error codesACCOUNT_SUSPENDEDINSUFFICIENT_SCOPE
- 404The resource does not exist on this account.
Error codesNOT_FOUND
- 429Rate limited. Honour the Retry-After header before retrying.
Error codesRATE_LIMITED
- 500Unexpected server error. Retry with the same Idempotency-Key.
Error codesSERVER_ERROR
Request
curl -X GET 'https://api.agentency.com/v1/sitemap_crawlers/<SITEMAP_CRAWLER_ID>/statistics' \
-H "Authorization: Bearer <YOUR_KEY>" \
-H "Content-Type: application/json"Response
Example 200 response
{
"object": "crawler_statistics",
"id": 1,
"status": "completed",
"error_code": null
}Check a URL before crawling it
POST /crawlers probes base_url, and reports whether it answered (accessible, the HTTP status_code, or an error_code). Use it to tell your user "that site is unreachable" before creating a crawler. It creates nothing, so it needs only crawlers:read, and it has a tight rate limit of its own because each call is a live fetch. A blocked address is 422 on url and never fetched.- Required scope
- crawlers:read
- Webhook events
- None
- Rate limits
Request body
urlstringRequiredThe publichttp(s)URL to probe, at most 2048 characters. A private, loopback, link-local or otherwise blocked address is 422VALIDATION_FAILEDon this field and is never fetched.Format:
uriMax length:2048
Responses
- 200Success.
objectstringRequiredAlways
url_validationurlanyRequiredThe URL as you sent it.accessiblebooleanRequiredWhether the URL answered with a page a crawler could start from.status_codeintegernullableRequiredThe HTTP status the URL answered with;nullwhen it could not be reached.error_codestringnullableRequiredWhy the URL could not be reached, or null when the probe succeeded.Possible values
nullhttp_errorunreachable
- 400A tenant selector header named a tenant other than the API key's own (
ACCOUNT_SELECTOR_NOT_SUPPORTED): an all-digitX-Account-Idother than the key owner's id or, whileworkspaces.context_enabledis on, anX-Workspace-Idother than the key's workspace (ws_prefix optional, case-insensitive). A header naming the key's own tenant, or a non-numericX-Account-Id, is ignored; a key cannot switch tenants, so send neither.Error codesACCOUNT_SELECTOR_NOT_SUPPORTED
- 401Missing or invalid API key.
Error codesUNAUTHENTICATED
- 403The API key is missing a required scope.
Error codesACCOUNT_SUSPENDEDINSUFFICIENT_SCOPE
- 422Validation failed. See
error.details.Error codesVALIDATION_FAILED
- 429Rate limited. Honour the Retry-After header before retrying.
Error codesRATE_LIMITED
- 500Unexpected server error. Retry with the same Idempotency-Key.
Error codesSERVER_ERROR
Request
curl -X POST 'https://api.agentency.com/v1/crawlers/validate_url' \
-H "Authorization: Bearer <YOUR_KEY>" \
-H "Content-Type: application/json"
-d '{
"url": "url"
}'Response
Example 200 response
{
"object": "url_validation",
"url": "https://example.com/help",
"accessible": true,
"status_code": 200,
"error_code": null
}Validate a sitemap URL
POST /sitemap_crawlers runs the same check. It creates nothing, so it needs only crawlers:read, and it has a tight rate limit of its own because each call is a live fetch. A blocked address is 422 on sitemap_url and never fetched.- Required scope
- crawlers:read
- Webhook events
- None
- Rate limits
Request body
sitemap_urlstringRequiredThe publichttp(s)URL of asitemap.xmlor sitemap index, at most 2048 characters. A private, loopback, link-local or otherwise blocked address is 422VALIDATION_FAILEDon this field and is never fetched.Format:
uriMax length:2048
Responses
- 200Success.
objectstringRequiredAlways
sitemap_validationurlstringRequiredThe sitemap URL as you sent it.validbooleanRequiredWhether the URL is a sitemap a crawler can use.typeanyRequiredWhat the document is:sitemap(a list of pages),sitemap_index(a list of sitemaps) orinvalid;nullwhen it could not be fetched.url_countintegerRequiredHow many entries the document lists.has_lastmodbooleanRequiredWhether entries carry<lastmod>dates, which let later scans skip unchanged pages.errorsarray of anyRequiredWhy the sitemap cannot be used, as readable sentences; empty whenvalid.warningsarray of anyRequiredProblems that do not stop a crawl, as readable sentences.
- 400A tenant selector header named a tenant other than the API key's own (
ACCOUNT_SELECTOR_NOT_SUPPORTED): an all-digitX-Account-Idother than the key owner's id or, whileworkspaces.context_enabledis on, anX-Workspace-Idother than the key's workspace (ws_prefix optional, case-insensitive). A header naming the key's own tenant, or a non-numericX-Account-Id, is ignored; a key cannot switch tenants, so send neither.Error codesACCOUNT_SELECTOR_NOT_SUPPORTED
- 401Missing or invalid API key.
Error codesUNAUTHENTICATED
- 403The API key is missing a required scope.
Error codesACCOUNT_SUSPENDEDINSUFFICIENT_SCOPE
- 422Validation failed. See
error.details.Error codesVALIDATION_FAILED
- 429Rate limited. Honour the Retry-After header before retrying.
Error codesRATE_LIMITED
- 500Unexpected server error. Retry with the same Idempotency-Key.
Error codesSERVER_ERROR
Request
curl -X POST 'https://api.agentency.com/v1/sitemap_crawlers/validate_url' \
-H "Authorization: Bearer <YOUR_KEY>" \
-H "Content-Type: application/json"
-d '{
"sitemap_url": "sitemap_url"
}'Response
Example 200 response
{
"object": "sitemap_validation",
"url": "https://example.com/sitemap.xml",
"valid": true,
"type": "sitemap",
"url_count": 1,
"has_lastmod": true,
"errors": [],
"warnings": []
}Cancel a crawler of either kind
crawler_id and crawler_type, exactly as POST /crawlers/{id}/cancel does, and reports its new status. It answers a short status object rather than the crawler. One that already finished is 409 CRAWLER_TERMINAL. Emits no event.- Required scope
- crawlers:write
- Idempotency
- Accepts Idempotency-Key
- Webhook events
- None
- Rate limits
Integer: a website crawler id withcrawler_id(body)Crawler idcrawler_type: url, a sitemap crawler id withcrawler_type: sitemap.Placeholder in the samples:
<CRAWLER_ID>Get it from
- GET /v1/crawlers/queue returns it as
data[].id - POST /v1/crawlers returns it as
id - POST /v1/sitemap_crawlers returns it as
id - GET /v1/sitemap_crawlers returns it as
data[].id
- GET /v1/crawlers/queue returns it as
Header parameters
Idempotency-KeystringOptionalMakes a retry safe. The first 2xx answer is stored for 24 h and replayed for the same key withIdempotency-Replayed: true; a retry while the first request runs is 409IDEMPOTENCY_IN_FLIGHT; the same key with a different payload is 422IDEMPOTENCY_KEY_REUSED; a malformed key is 400INVALID_IDEMPOTENCY_KEY.Min length:
16Max length:128Pattern:^[A-Za-z0-9_-]+$
Request body
crawler_idintegerRequiredThe crawler to cancel: a website crawler id withcrawler_type: url, a sitemap crawler id withcrawler_type: sitemap.Minimum:
1crawler_typestringRequiredWhich kindcrawler_idnames:url(a website crawler) orsitemap. Website and sitemap crawlers are numbered separately, so the same id can name one of each.Possible values
urlsitemap
Responses
- 200Success.
objectstringRequiredThe crawler kind:website_crawlerorsitemap_crawler.Possible values
sitemap_crawlerwebsite_crawleridintegerRequiredThe crawler id.deletedbooleanRequiredAlwaysfalse: the crawler is cancelled, not deleted.statusstringRequiredThe crawler's status after the call:cancelled.
- 400A tenant selector header named a tenant other than the API key's own (
ACCOUNT_SELECTOR_NOT_SUPPORTED): an all-digitX-Account-Idother than the key owner's id or, whileworkspaces.context_enabledis on, anX-Workspace-Idother than the key's workspace (ws_prefix optional, case-insensitive). A header naming the key's own tenant, or a non-numericX-Account-Id, is ignored; a key cannot switch tenants, so send neither. A mutation that honoursIdempotency-Keyalso returnsINVALID_IDEMPOTENCY_KEYwhen that header is not 16–128[A-Za-z0-9_-]characters.Error codesACCOUNT_SELECTOR_NOT_SUPPORTEDINVALID_IDEMPOTENCY_KEY
- 401Missing or invalid API key.
Error codesUNAUTHENTICATED
- 403The API key is missing a required scope.
Error codesACCOUNT_SUSPENDEDINSUFFICIENT_SCOPE
- 404The resource does not exist on this account.
Error codesNOT_FOUND
- 409The request conflicts with the current resource state.
Error codesCRAWLER_TERMINALIDEMPOTENCY_IN_FLIGHT
- 422Validation failed. See
error.details.Error codesIDEMPOTENCY_KEY_REUSEDVALIDATION_FAILED
- 429Rate limited. Honour the Retry-After header before retrying.
Error codesRATE_LIMITED
- 500Unexpected server error. Retry with the same Idempotency-Key.
Error codesSERVER_ERROR
Request
curl -X POST 'https://api.agentency.com/v1/crawlers/queue/cancel' \
-H "Authorization: Bearer <YOUR_KEY>" \
-H "Content-Type: application/json"
-d '{
"crawler_id": 1,
"crawler_type": "crawler_type"
}'Response
Example 200 response
{
"object": "website_crawler",
"id": 1,
"deleted": false,
"status": "cancelled"
}Pause a website crawler
paused; the pages saved so far stay. A paused crawler holds no concurrent-crawl slot. Continue with POST /crawlers/{id}/resume. Any other state is 409 CRAWLER_NOT_RUNNING. Emits no event.- Required scope
- crawlers:write
- Idempotency
- Accepts Idempotency-Key
- Webhook events
- None
- Rate limits
Integer. Website and sitemap crawlers are numbered separately, so the same number can name one of each.id(path)Website crawler idPlaceholder in the samples:
<CRAWLER_ID>Get it from
- POST /v1/crawlers returns it as
id - GET /v1/crawlers returns it as
data[].id - GET /v1/crawlers/queue returns it as
data[].id - Webhook crawler.created carries it as
data.object.id crawler.*andcrawl.*events carry only{object, id}, not the crawler kind: keep the kind with the id when you create the crawler.
- POST /v1/crawlers returns it as
Path parameters
idintegerRequiredThe website crawler id.
Header parameters
Idempotency-KeystringOptionalMakes a retry safe. The first 2xx answer is stored for 24 h and replayed for the same key withIdempotency-Replayed: true; a retry while the first request runs is 409IDEMPOTENCY_IN_FLIGHT; the same key with a different payload is 422IDEMPOTENCY_KEY_REUSED; a malformed key is 400INVALID_IDEMPOTENCY_KEY.Min length:
16Max length:128Pattern:^[A-Za-z0-9_-]+$
Responses
- 200
CrawlerResourceobjectstringRequiredThe crawler kind:website_crawler(/crawlers) orsitemap_crawler(/sitemap_crawlers). The two kinds are numbered separately.Possible values
sitemap_crawlerwebsite_crawleridintegerRequiredThe crawler id, unique within its kind.namestringnullableRequiredDisplay name.urlstringnullableRequiredThe start URL of a website crawler, or the sitemap URL of a sitemap crawler.statusstringRequiredpending(queued, or a recurring crawler waiting for its next run),running,paused,completed,failedorcancelled. Reachingcompletedorfailedemitscrawl.completedorcrawl.failed.Possible values
pendingrunningpausedcompletedfailedcancelledchatbot_idstringnullableRequiredThe chatbot the collected pages train;nullwhen the crawler only fills a collection.error_codestringnullableRequiredWhy the crawler last failed, as a stable code;nullwhen it has not.Possible values
unreachablehttp_errortoo_many_redirectsinvalid_sitemaptoo_largerobots_blockednever_startedknowledge_limit_reachedunsupported_content_encodingcorrupt_content_encodingunsupported_content_typecontent_too_shortnot_knowledge_indexnot_knowledge_mediaexcluded_by_patternduplicatecanonical_duplicatenear_duplicatesoft_404redirect_externalredirect_other_pagestalledextraction_failedremoved_from_knowledge_basechallenge_blockedunknownnullcreated_atstringnullableRequiredWhen the crawler was created (ISO 8601, UTC).updated_atstringnullableRequiredWhen the crawler last changed (ISO 8601, UTC).
- 400A tenant selector header named a tenant other than the API key's own (
ACCOUNT_SELECTOR_NOT_SUPPORTED): an all-digitX-Account-Idother than the key owner's id or, whileworkspaces.context_enabledis on, anX-Workspace-Idother than the key's workspace (ws_prefix optional, case-insensitive). A header naming the key's own tenant, or a non-numericX-Account-Id, is ignored; a key cannot switch tenants, so send neither. A mutation that honoursIdempotency-Keyalso returnsINVALID_IDEMPOTENCY_KEYwhen that header is not 16–128[A-Za-z0-9_-]characters.Error codesACCOUNT_SELECTOR_NOT_SUPPORTEDINVALID_IDEMPOTENCY_KEY
- 401Missing or invalid API key.
Error codesUNAUTHENTICATED
- 403The API key is missing a required scope.
Error codesACCOUNT_SUSPENDEDINSUFFICIENT_SCOPE
- 404The resource does not exist on this account.
Error codesNOT_FOUND
- 409The request conflicts with the current resource state.
Error codesCRAWLER_NOT_RUNNINGIDEMPOTENCY_IN_FLIGHT
- 422Validation failed. See
error.details.Error codesIDEMPOTENCY_KEY_REUSED
- 429Rate limited. Honour the Retry-After header before retrying.
Error codesRATE_LIMITED
- 500Unexpected server error. Retry with the same Idempotency-Key.
Error codesSERVER_ERROR
Request
curl -X POST 'https://api.agentency.com/v1/crawlers/<CRAWLER_ID>/pause' \
-H "Authorization: Bearer <YOUR_KEY>" \
-H "Content-Type: application/json"Response
Example 200 response
{
"object": "website_crawler",
"id": 1,
"name": "Help centre (EN)",
"url": "https://example.com/help",
"status": "paused",
"chatbot_id": 1,
"error_code": null,
"created_at": "2026-01-01T00:00:00+00:00",
"updated_at": "2026-01-01T00:00:00+00:00"
}Resume a website crawler
CRAWLER_LIMIT_REACHED and the crawler stays paused. A crawler that is not paused (cancelled ones included) is 409 CRAWLER_NOT_PAUSED; a paused crawler that was deactivated is 409 CRAWLER_INACTIVE. Emits no event.- Required scope
- crawlers:write
- Idempotency
- Accepts Idempotency-Key
- Webhook events
- None
- Rate limits
Integer. Website and sitemap crawlers are numbered separately, so the same number can name one of each.id(path)Website crawler idPlaceholder in the samples:
<CRAWLER_ID>Get it from
- POST /v1/crawlers returns it as
id - GET /v1/crawlers returns it as
data[].id - GET /v1/crawlers/queue returns it as
data[].id - Webhook crawler.created carries it as
data.object.id crawler.*andcrawl.*events carry only{object, id}, not the crawler kind: keep the kind with the id when you create the crawler.
- POST /v1/crawlers returns it as
Path parameters
idintegerRequiredThe website crawler id.
Header parameters
Idempotency-KeystringOptionalMakes a retry safe. The first 2xx answer is stored for 24 h and replayed for the same key withIdempotency-Replayed: true; a retry while the first request runs is 409IDEMPOTENCY_IN_FLIGHT; the same key with a different payload is 422IDEMPOTENCY_KEY_REUSED; a malformed key is 400INVALID_IDEMPOTENCY_KEY.Min length:
16Max length:128Pattern:^[A-Za-z0-9_-]+$
Responses
- 200
CrawlerResourceobjectstringRequiredThe crawler kind:website_crawler(/crawlers) orsitemap_crawler(/sitemap_crawlers). The two kinds are numbered separately.Possible values
sitemap_crawlerwebsite_crawleridintegerRequiredThe crawler id, unique within its kind.namestringnullableRequiredDisplay name.urlstringnullableRequiredThe start URL of a website crawler, or the sitemap URL of a sitemap crawler.statusstringRequiredpending(queued, or a recurring crawler waiting for its next run),running,paused,completed,failedorcancelled. Reachingcompletedorfailedemitscrawl.completedorcrawl.failed.Possible values
pendingrunningpausedcompletedfailedcancelledchatbot_idstringnullableRequiredThe chatbot the collected pages train;nullwhen the crawler only fills a collection.error_codestringnullableRequiredWhy the crawler last failed, as a stable code;nullwhen it has not.Possible values
unreachablehttp_errortoo_many_redirectsinvalid_sitemaptoo_largerobots_blockednever_startedknowledge_limit_reachedunsupported_content_encodingcorrupt_content_encodingunsupported_content_typecontent_too_shortnot_knowledge_indexnot_knowledge_mediaexcluded_by_patternduplicatecanonical_duplicatenear_duplicatesoft_404redirect_externalredirect_other_pagestalledextraction_failedremoved_from_knowledge_basechallenge_blockedunknownnullcreated_atstringnullableRequiredWhen the crawler was created (ISO 8601, UTC).updated_atstringnullableRequiredWhen the crawler last changed (ISO 8601, UTC).
- 400A tenant selector header named a tenant other than the API key's own (
ACCOUNT_SELECTOR_NOT_SUPPORTED): an all-digitX-Account-Idother than the key owner's id or, whileworkspaces.context_enabledis on, anX-Workspace-Idother than the key's workspace (ws_prefix optional, case-insensitive). A header naming the key's own tenant, or a non-numericX-Account-Id, is ignored; a key cannot switch tenants, so send neither. A mutation that honoursIdempotency-Keyalso returnsINVALID_IDEMPOTENCY_KEYwhen that header is not 16–128[A-Za-z0-9_-]characters.Error codesACCOUNT_SELECTOR_NOT_SUPPORTEDINVALID_IDEMPOTENCY_KEY
- 401Missing or invalid API key.
Error codesUNAUTHENTICATED
- 403The API key is missing a required scope.
Error codesACCOUNT_SUSPENDEDINSUFFICIENT_SCOPE
- 404The resource does not exist on this account.
Error codesNOT_FOUND
- 409The request conflicts with the current resource state.
Error codesCRAWLER_INACTIVECRAWLER_NOT_PAUSEDIDEMPOTENCY_IN_FLIGHT
- 422Validation failed. See
error.details.Error codesIDEMPOTENCY_KEY_REUSED
- 429Rate limited. Honour Retry-After.
Error codesCRAWLER_LIMIT_REACHEDRATE_LIMITED
- 500Unexpected server error. Retry with the same Idempotency-Key.
Error codesSERVER_ERROR
Request
curl -X POST 'https://api.agentency.com/v1/crawlers/<CRAWLER_ID>/resume' \
-H "Authorization: Bearer <YOUR_KEY>" \
-H "Content-Type: application/json"Response
Example 200 response
{
"object": "website_crawler",
"id": 1,
"name": "Help centre (EN)",
"url": "https://example.com/help",
"status": "pending",
"chatbot_id": 1,
"error_code": null,
"created_at": "2026-01-01T00:00:00+00:00",
"updated_at": "2026-01-01T00:00:00+00:00"
}Re-run a website crawler
pending. Pages it saved before are updated in place, not duplicated; the run ends in crawl.completed or crawl.failed.
A crawler still running is 409 CRAWLER_RUNNING; a cancelled or deactivated one is 409 CRAWLER_INACTIVE (create a new crawler); a paused one is 409 CRAWL_NOT_RETRYABLE (resume it instead). The run takes a concurrent-crawl slot, so at the account's cap it is 429 CRAWLER_LIMIT_REACHED and the crawler keeps its state.- Required scope
- crawlers:write
- Idempotency
- Accepts Idempotency-Key
- Webhook events
- None
- Rate limits
Integer. Website and sitemap crawlers are numbered separately, so the same number can name one of each.id(path)Website crawler idPlaceholder in the samples:
<CRAWLER_ID>Get it from
- POST /v1/crawlers returns it as
id - GET /v1/crawlers returns it as
data[].id - GET /v1/crawlers/queue returns it as
data[].id - Webhook crawler.created carries it as
data.object.id crawler.*andcrawl.*events carry only{object, id}, not the crawler kind: keep the kind with the id when you create the crawler.
- POST /v1/crawlers returns it as
Path parameters
idintegerRequiredThe website crawler id.
Header parameters
Idempotency-KeystringOptionalMakes a retry safe. The first 2xx answer is stored for 24 h and replayed for the same key withIdempotency-Replayed: true; a retry while the first request runs is 409IDEMPOTENCY_IN_FLIGHT; the same key with a different payload is 422IDEMPOTENCY_KEY_REUSED; a malformed key is 400INVALID_IDEMPOTENCY_KEY.Min length:
16Max length:128Pattern:^[A-Za-z0-9_-]+$
Responses
- 200
CrawlerResourceobjectstringRequiredThe crawler kind:website_crawler(/crawlers) orsitemap_crawler(/sitemap_crawlers). The two kinds are numbered separately.Possible values
sitemap_crawlerwebsite_crawleridintegerRequiredThe crawler id, unique within its kind.namestringnullableRequiredDisplay name.urlstringnullableRequiredThe start URL of a website crawler, or the sitemap URL of a sitemap crawler.statusstringRequiredpending(queued, or a recurring crawler waiting for its next run),running,paused,completed,failedorcancelled. Reachingcompletedorfailedemitscrawl.completedorcrawl.failed.Possible values
pendingrunningpausedcompletedfailedcancelledchatbot_idstringnullableRequiredThe chatbot the collected pages train;nullwhen the crawler only fills a collection.error_codestringnullableRequiredWhy the crawler last failed, as a stable code;nullwhen it has not.Possible values
unreachablehttp_errortoo_many_redirectsinvalid_sitemaptoo_largerobots_blockednever_startedknowledge_limit_reachedunsupported_content_encodingcorrupt_content_encodingunsupported_content_typecontent_too_shortnot_knowledge_indexnot_knowledge_mediaexcluded_by_patternduplicatecanonical_duplicatenear_duplicatesoft_404redirect_externalredirect_other_pagestalledextraction_failedremoved_from_knowledge_basechallenge_blockedunknownnullcreated_atstringnullableRequiredWhen the crawler was created (ISO 8601, UTC).updated_atstringnullableRequiredWhen the crawler last changed (ISO 8601, UTC).
- 400A tenant selector header named a tenant other than the API key's own (
ACCOUNT_SELECTOR_NOT_SUPPORTED): an all-digitX-Account-Idother than the key owner's id or, whileworkspaces.context_enabledis on, anX-Workspace-Idother than the key's workspace (ws_prefix optional, case-insensitive). A header naming the key's own tenant, or a non-numericX-Account-Id, is ignored; a key cannot switch tenants, so send neither. A mutation that honoursIdempotency-Keyalso returnsINVALID_IDEMPOTENCY_KEYwhen that header is not 16–128[A-Za-z0-9_-]characters.Error codesACCOUNT_SELECTOR_NOT_SUPPORTEDINVALID_IDEMPOTENCY_KEY
- 401Missing or invalid API key.
Error codesUNAUTHENTICATED
- 403The API key is missing a required scope.
Error codesACCOUNT_SUSPENDEDINSUFFICIENT_SCOPE
- 404The resource does not exist on this account.
Error codesNOT_FOUND
- 409The request conflicts with the current resource state.
Error codesCRAWLER_INACTIVECRAWLER_RUNNINGCRAWL_NOT_RETRYABLEIDEMPOTENCY_IN_FLIGHT
- 422Validation failed. See
error.details.Error codesIDEMPOTENCY_KEY_REUSED
- 429Rate limited. Honour Retry-After.
Error codesCRAWLER_LIMIT_REACHEDRATE_LIMITED
- 500Unexpected server error. Retry with the same Idempotency-Key.
Error codesSERVER_ERROR
Request
curl -X POST 'https://api.agentency.com/v1/crawlers/<CRAWLER_ID>/retry' \
-H "Authorization: Bearer <YOUR_KEY>" \
-H "Content-Type: application/json"Response
Example 200 response
{
"object": "website_crawler",
"id": 1,
"name": "Blog",
"url": "https://example.com/blog",
"status": "pending",
"chatbot_id": 1,
"error_code": null,
"created_at": "2026-01-01T00:00:00+00:00",
"updated_at": "2026-01-01T00:00:00+00:00"
}Cancel a website crawler
cancelled; the pages saved so far stay as knowledge. A cancelled crawler cannot be resumed or re-run. One that already finished (completed, failed or cancelled) is 409 CRAWLER_TERMINAL. Emits no event.- Required scope
- crawlers:write
- Idempotency
- Accepts Idempotency-Key
- Webhook events
- None
- Rate limits
Integer. Website and sitemap crawlers are numbered separately, so the same number can name one of each.id(path)Website crawler idPlaceholder in the samples:
<CRAWLER_ID>Get it from
- POST /v1/crawlers returns it as
id - GET /v1/crawlers returns it as
data[].id - GET /v1/crawlers/queue returns it as
data[].id - Webhook crawler.created carries it as
data.object.id crawler.*andcrawl.*events carry only{object, id}, not the crawler kind: keep the kind with the id when you create the crawler.
- POST /v1/crawlers returns it as
Path parameters
idintegerRequiredThe website crawler id.
Header parameters
Idempotency-KeystringOptionalMakes a retry safe. The first 2xx answer is stored for 24 h and replayed for the same key withIdempotency-Replayed: true; a retry while the first request runs is 409IDEMPOTENCY_IN_FLIGHT; the same key with a different payload is 422IDEMPOTENCY_KEY_REUSED; a malformed key is 400INVALID_IDEMPOTENCY_KEY.Min length:
16Max length:128Pattern:^[A-Za-z0-9_-]+$
Responses
- 200
CrawlerResourceobjectstringRequiredThe crawler kind:website_crawler(/crawlers) orsitemap_crawler(/sitemap_crawlers). The two kinds are numbered separately.Possible values
sitemap_crawlerwebsite_crawleridintegerRequiredThe crawler id, unique within its kind.namestringnullableRequiredDisplay name.urlstringnullableRequiredThe start URL of a website crawler, or the sitemap URL of a sitemap crawler.statusstringRequiredpending(queued, or a recurring crawler waiting for its next run),running,paused,completed,failedorcancelled. Reachingcompletedorfailedemitscrawl.completedorcrawl.failed.Possible values
pendingrunningpausedcompletedfailedcancelledchatbot_idstringnullableRequiredThe chatbot the collected pages train;nullwhen the crawler only fills a collection.error_codestringnullableRequiredWhy the crawler last failed, as a stable code;nullwhen it has not.Possible values
unreachablehttp_errortoo_many_redirectsinvalid_sitemaptoo_largerobots_blockednever_startedknowledge_limit_reachedunsupported_content_encodingcorrupt_content_encodingunsupported_content_typecontent_too_shortnot_knowledge_indexnot_knowledge_mediaexcluded_by_patternduplicatecanonical_duplicatenear_duplicatesoft_404redirect_externalredirect_other_pagestalledextraction_failedremoved_from_knowledge_basechallenge_blockedunknownnullcreated_atstringnullableRequiredWhen the crawler was created (ISO 8601, UTC).updated_atstringnullableRequiredWhen the crawler last changed (ISO 8601, UTC).
- 400A tenant selector header named a tenant other than the API key's own (
ACCOUNT_SELECTOR_NOT_SUPPORTED): an all-digitX-Account-Idother than the key owner's id or, whileworkspaces.context_enabledis on, anX-Workspace-Idother than the key's workspace (ws_prefix optional, case-insensitive). A header naming the key's own tenant, or a non-numericX-Account-Id, is ignored; a key cannot switch tenants, so send neither. A mutation that honoursIdempotency-Keyalso returnsINVALID_IDEMPOTENCY_KEYwhen that header is not 16–128[A-Za-z0-9_-]characters.Error codesACCOUNT_SELECTOR_NOT_SUPPORTEDINVALID_IDEMPOTENCY_KEY
- 401Missing or invalid API key.
Error codesUNAUTHENTICATED
- 403The API key is missing a required scope.
Error codesACCOUNT_SUSPENDEDINSUFFICIENT_SCOPE
- 404The resource does not exist on this account.
Error codesNOT_FOUND
- 409The request conflicts with the current resource state.
Error codesCRAWLER_TERMINALIDEMPOTENCY_IN_FLIGHT
- 422Validation failed. See
error.details.Error codesIDEMPOTENCY_KEY_REUSED
- 429Rate limited. Honour the Retry-After header before retrying.
Error codesRATE_LIMITED
- 500Unexpected server error. Retry with the same Idempotency-Key.
Error codesSERVER_ERROR
Request
curl -X POST 'https://api.agentency.com/v1/crawlers/<CRAWLER_ID>/cancel' \
-H "Authorization: Bearer <YOUR_KEY>" \
-H "Content-Type: application/json"Response
Example 200 response
{
"object": "website_crawler",
"id": 1,
"name": "Help centre (EN)",
"url": "https://example.com/help",
"status": "cancelled",
"chatbot_id": 1,
"error_code": null,
"created_at": "2026-01-01T00:00:00+00:00",
"updated_at": "2026-01-01T00:00:00+00:00"
}Pause a sitemap crawler
paused; the pages saved so far stay, and no scheduled scan starts while it is paused. A paused crawler holds no concurrent-crawl slot. Continue with POST /sitemap_crawlers/{id}/resume. Any other state — a recurring crawler waiting for its next scan included — is 409 CRAWLER_NOT_RUNNING. Emits no event.- Required scope
- crawlers:write
- Idempotency
- Accepts Idempotency-Key
- Webhook events
- None
- Rate limits
Integer. Website and sitemap crawlers are numbered separately, so the same number can name one of each.id(path)Sitemap crawler idPlaceholder in the samples:
<SITEMAP_CRAWLER_ID>Get it from
- POST /v1/sitemap_crawlers returns it as
id - GET /v1/sitemap_crawlers returns it as
data[].id - Webhook crawler.created carries it as
data.object.id crawler.*andcrawl.*events carry only{object, id}, not the crawler kind: keep the kind with the id when you create the crawler.
- POST /v1/sitemap_crawlers returns it as
Path parameters
idintegerRequiredThe sitemap crawler id.
Header parameters
Idempotency-KeystringOptionalMakes a retry safe. The first 2xx answer is stored for 24 h and replayed for the same key withIdempotency-Replayed: true; a retry while the first request runs is 409IDEMPOTENCY_IN_FLIGHT; the same key with a different payload is 422IDEMPOTENCY_KEY_REUSED; a malformed key is 400INVALID_IDEMPOTENCY_KEY.Min length:
16Max length:128Pattern:^[A-Za-z0-9_-]+$
Responses
- 200
CrawlerResourceobjectstringRequiredThe crawler kind:website_crawler(/crawlers) orsitemap_crawler(/sitemap_crawlers). The two kinds are numbered separately.Possible values
sitemap_crawlerwebsite_crawleridintegerRequiredThe crawler id, unique within its kind.namestringnullableRequiredDisplay name.urlstringnullableRequiredThe start URL of a website crawler, or the sitemap URL of a sitemap crawler.statusstringRequiredpending(queued, or a recurring crawler waiting for its next run),running,paused,completed,failedorcancelled. Reachingcompletedorfailedemitscrawl.completedorcrawl.failed.Possible values
pendingrunningpausedcompletedfailedcancelledchatbot_idstringnullableRequiredThe chatbot the collected pages train;nullwhen the crawler only fills a collection.error_codestringnullableRequiredWhy the crawler last failed, as a stable code;nullwhen it has not.Possible values
unreachablehttp_errortoo_many_redirectsinvalid_sitemaptoo_largerobots_blockednever_startedknowledge_limit_reachedunsupported_content_encodingcorrupt_content_encodingunsupported_content_typecontent_too_shortnot_knowledge_indexnot_knowledge_mediaexcluded_by_patternduplicatecanonical_duplicatenear_duplicatesoft_404redirect_externalredirect_other_pagestalledextraction_failedremoved_from_knowledge_basechallenge_blockedunknownnullcreated_atstringnullableRequiredWhen the crawler was created (ISO 8601, UTC).updated_atstringnullableRequiredWhen the crawler last changed (ISO 8601, UTC).
- 400A tenant selector header named a tenant other than the API key's own (
ACCOUNT_SELECTOR_NOT_SUPPORTED): an all-digitX-Account-Idother than the key owner's id or, whileworkspaces.context_enabledis on, anX-Workspace-Idother than the key's workspace (ws_prefix optional, case-insensitive). A header naming the key's own tenant, or a non-numericX-Account-Id, is ignored; a key cannot switch tenants, so send neither. A mutation that honoursIdempotency-Keyalso returnsINVALID_IDEMPOTENCY_KEYwhen that header is not 16–128[A-Za-z0-9_-]characters.Error codesACCOUNT_SELECTOR_NOT_SUPPORTEDINVALID_IDEMPOTENCY_KEY
- 401Missing or invalid API key.
Error codesUNAUTHENTICATED
- 403The API key is missing a required scope.
Error codesACCOUNT_SUSPENDEDINSUFFICIENT_SCOPE
- 404The resource does not exist on this account.
Error codesNOT_FOUND
- 409The request conflicts with the current resource state.
Error codesCRAWLER_NOT_RUNNINGIDEMPOTENCY_IN_FLIGHT
- 422Validation failed. See
error.details.Error codesIDEMPOTENCY_KEY_REUSED
- 429Rate limited. Honour the Retry-After header before retrying.
Error codesRATE_LIMITED
- 500Unexpected server error. Retry with the same Idempotency-Key.
Error codesSERVER_ERROR
Request
curl -X POST 'https://api.agentency.com/v1/sitemap_crawlers/<SITEMAP_CRAWLER_ID>/pause' \
-H "Authorization: Bearer <YOUR_KEY>" \
-H "Content-Type: application/json"Response
Example 200 response
{
"object": "sitemap_crawler",
"id": 1,
"name": "Product pages",
"url": "https://example.com/sitemap.xml",
"status": "paused",
"chatbot_id": 1,
"error_code": null,
"created_at": "2026-01-01T00:00:00+00:00",
"updated_at": "2026-01-01T00:00:00+00:00"
}Resume a sitemap crawler
CRAWLER_LIMIT_REACHED and the crawler stays paused. A crawler that is not paused (cancelled ones included) is 409 CRAWLER_NOT_PAUSED; a paused crawler that was deactivated is 409 CRAWLER_INACTIVE. Emits no event.- Required scope
- crawlers:write
- Idempotency
- Accepts Idempotency-Key
- Webhook events
- None
- Rate limits
Integer. Website and sitemap crawlers are numbered separately, so the same number can name one of each.id(path)Sitemap crawler idPlaceholder in the samples:
<SITEMAP_CRAWLER_ID>Get it from
- POST /v1/sitemap_crawlers returns it as
id - GET /v1/sitemap_crawlers returns it as
data[].id - Webhook crawler.created carries it as
data.object.id crawler.*andcrawl.*events carry only{object, id}, not the crawler kind: keep the kind with the id when you create the crawler.
- POST /v1/sitemap_crawlers returns it as
Path parameters
idintegerRequiredThe sitemap crawler id.
Header parameters
Idempotency-KeystringOptionalMakes a retry safe. The first 2xx answer is stored for 24 h and replayed for the same key withIdempotency-Replayed: true; a retry while the first request runs is 409IDEMPOTENCY_IN_FLIGHT; the same key with a different payload is 422IDEMPOTENCY_KEY_REUSED; a malformed key is 400INVALID_IDEMPOTENCY_KEY.Min length:
16Max length:128Pattern:^[A-Za-z0-9_-]+$
Responses
- 200
CrawlerResourceobjectstringRequiredThe crawler kind:website_crawler(/crawlers) orsitemap_crawler(/sitemap_crawlers). The two kinds are numbered separately.Possible values
sitemap_crawlerwebsite_crawleridintegerRequiredThe crawler id, unique within its kind.namestringnullableRequiredDisplay name.urlstringnullableRequiredThe start URL of a website crawler, or the sitemap URL of a sitemap crawler.statusstringRequiredpending(queued, or a recurring crawler waiting for its next run),running,paused,completed,failedorcancelled. Reachingcompletedorfailedemitscrawl.completedorcrawl.failed.Possible values
pendingrunningpausedcompletedfailedcancelledchatbot_idstringnullableRequiredThe chatbot the collected pages train;nullwhen the crawler only fills a collection.error_codestringnullableRequiredWhy the crawler last failed, as a stable code;nullwhen it has not.Possible values
unreachablehttp_errortoo_many_redirectsinvalid_sitemaptoo_largerobots_blockednever_startedknowledge_limit_reachedunsupported_content_encodingcorrupt_content_encodingunsupported_content_typecontent_too_shortnot_knowledge_indexnot_knowledge_mediaexcluded_by_patternduplicatecanonical_duplicatenear_duplicatesoft_404redirect_externalredirect_other_pagestalledextraction_failedremoved_from_knowledge_basechallenge_blockedunknownnullcreated_atstringnullableRequiredWhen the crawler was created (ISO 8601, UTC).updated_atstringnullableRequiredWhen the crawler last changed (ISO 8601, UTC).
- 400A tenant selector header named a tenant other than the API key's own (
ACCOUNT_SELECTOR_NOT_SUPPORTED): an all-digitX-Account-Idother than the key owner's id or, whileworkspaces.context_enabledis on, anX-Workspace-Idother than the key's workspace (ws_prefix optional, case-insensitive). A header naming the key's own tenant, or a non-numericX-Account-Id, is ignored; a key cannot switch tenants, so send neither. A mutation that honoursIdempotency-Keyalso returnsINVALID_IDEMPOTENCY_KEYwhen that header is not 16–128[A-Za-z0-9_-]characters.Error codesACCOUNT_SELECTOR_NOT_SUPPORTEDINVALID_IDEMPOTENCY_KEY
- 401Missing or invalid API key.
Error codesUNAUTHENTICATED
- 403The API key is missing a required scope.
Error codesACCOUNT_SUSPENDEDINSUFFICIENT_SCOPE
- 404The resource does not exist on this account.
Error codesNOT_FOUND
- 409The request conflicts with the current resource state.
Error codesCRAWLER_INACTIVECRAWLER_NOT_PAUSEDIDEMPOTENCY_IN_FLIGHT
- 422Validation failed. See
error.details.Error codesIDEMPOTENCY_KEY_REUSED
- 429Rate limited. Honour Retry-After.
Error codesCRAWLER_LIMIT_REACHEDRATE_LIMITED
- 500Unexpected server error. Retry with the same Idempotency-Key.
Error codesSERVER_ERROR
Request
curl -X POST 'https://api.agentency.com/v1/sitemap_crawlers/<SITEMAP_CRAWLER_ID>/resume' \
-H "Authorization: Bearer <YOUR_KEY>" \
-H "Content-Type: application/json"Response
Example 200 response
{
"object": "sitemap_crawler",
"id": 1,
"name": "Product pages",
"url": "https://example.com/sitemap.xml",
"status": "pending",
"chatbot_id": 1,
"error_code": null,
"created_at": "2026-01-01T00:00:00+00:00",
"updated_at": "2026-01-01T00:00:00+00:00"
}Scan a sitemap now
scan_frequency — the way to refresh a manual crawler — and returns the crawler as pending. The scan picks up new URLs and re-fetches listed pages; unchanged ones are not retrained. It ends in crawl.completed or crawl.failed.
A crawler with a scan running is 409 CRAWLER_RUNNING; a cancelled or deactivated one is 409 CRAWLER_INACTIVE; a paused one is 409 CRAWL_NOT_RETRYABLE (resume it instead). The scan takes a concurrent-crawl slot, so at the account's cap it is 429 CRAWLER_LIMIT_REACHED and the crawler keeps its state.- Required scope
- crawlers:write
- Idempotency
- Accepts Idempotency-Key
- Webhook events
- None
- Rate limits
Integer. Website and sitemap crawlers are numbered separately, so the same number can name one of each.id(path)Sitemap crawler idPlaceholder in the samples:
<SITEMAP_CRAWLER_ID>Get it from
- POST /v1/sitemap_crawlers returns it as
id - GET /v1/sitemap_crawlers returns it as
data[].id - Webhook crawler.created carries it as
data.object.id crawler.*andcrawl.*events carry only{object, id}, not the crawler kind: keep the kind with the id when you create the crawler.
- POST /v1/sitemap_crawlers returns it as
Path parameters
idintegerRequiredThe sitemap crawler id.
Header parameters
Idempotency-KeystringOptionalMakes a retry safe. The first 2xx answer is stored for 24 h and replayed for the same key withIdempotency-Replayed: true; a retry while the first request runs is 409IDEMPOTENCY_IN_FLIGHT; the same key with a different payload is 422IDEMPOTENCY_KEY_REUSED; a malformed key is 400INVALID_IDEMPOTENCY_KEY.Min length:
16Max length:128Pattern:^[A-Za-z0-9_-]+$
Responses
- 200
CrawlerResourceobjectstringRequiredThe crawler kind:website_crawler(/crawlers) orsitemap_crawler(/sitemap_crawlers). The two kinds are numbered separately.Possible values
sitemap_crawlerwebsite_crawleridintegerRequiredThe crawler id, unique within its kind.namestringnullableRequiredDisplay name.urlstringnullableRequiredThe start URL of a website crawler, or the sitemap URL of a sitemap crawler.statusstringRequiredpending(queued, or a recurring crawler waiting for its next run),running,paused,completed,failedorcancelled. Reachingcompletedorfailedemitscrawl.completedorcrawl.failed.Possible values
pendingrunningpausedcompletedfailedcancelledchatbot_idstringnullableRequiredThe chatbot the collected pages train;nullwhen the crawler only fills a collection.error_codestringnullableRequiredWhy the crawler last failed, as a stable code;nullwhen it has not.Possible values
unreachablehttp_errortoo_many_redirectsinvalid_sitemaptoo_largerobots_blockednever_startedknowledge_limit_reachedunsupported_content_encodingcorrupt_content_encodingunsupported_content_typecontent_too_shortnot_knowledge_indexnot_knowledge_mediaexcluded_by_patternduplicatecanonical_duplicatenear_duplicatesoft_404redirect_externalredirect_other_pagestalledextraction_failedremoved_from_knowledge_basechallenge_blockedunknownnullcreated_atstringnullableRequiredWhen the crawler was created (ISO 8601, UTC).updated_atstringnullableRequiredWhen the crawler last changed (ISO 8601, UTC).
- 400A tenant selector header named a tenant other than the API key's own (
ACCOUNT_SELECTOR_NOT_SUPPORTED): an all-digitX-Account-Idother than the key owner's id or, whileworkspaces.context_enabledis on, anX-Workspace-Idother than the key's workspace (ws_prefix optional, case-insensitive). A header naming the key's own tenant, or a non-numericX-Account-Id, is ignored; a key cannot switch tenants, so send neither. A mutation that honoursIdempotency-Keyalso returnsINVALID_IDEMPOTENCY_KEYwhen that header is not 16–128[A-Za-z0-9_-]characters.Error codesACCOUNT_SELECTOR_NOT_SUPPORTEDINVALID_IDEMPOTENCY_KEY
- 401Missing or invalid API key.
Error codesUNAUTHENTICATED
- 403The API key is missing a required scope.
Error codesACCOUNT_SUSPENDEDINSUFFICIENT_SCOPE
- 404The resource does not exist on this account.
Error codesNOT_FOUND
- 409The request conflicts with the current resource state.
Error codesCRAWLER_INACTIVECRAWLER_RUNNINGCRAWL_NOT_RETRYABLEIDEMPOTENCY_IN_FLIGHT
- 422Validation failed. See
error.details.Error codesIDEMPOTENCY_KEY_REUSED
- 429Rate limited. Honour Retry-After.
Error codesCRAWLER_LIMIT_REACHEDRATE_LIMITED
- 500Unexpected server error. Retry with the same Idempotency-Key.
Error codesSERVER_ERROR
Request
curl -X POST 'https://api.agentency.com/v1/sitemap_crawlers/<SITEMAP_CRAWLER_ID>/scan' \
-H "Authorization: Bearer <YOUR_KEY>" \
-H "Content-Type: application/json"Response
Example 200 response
{
"object": "sitemap_crawler",
"id": 1,
"name": "Product pages",
"url": "https://example.com/sitemap.xml",
"status": "pending",
"chatbot_id": 1,
"error_code": null,
"created_at": "2026-01-01T00:00:00+00:00",
"updated_at": "2026-01-01T00:00:00+00:00"
}Re-run a sitemap crawler
failed — and returns it as pending. It is POST /sitemap_crawlers/{id}/scan without the few seconds' delay, with the same refusals: a crawler with a scan running is 409 CRAWLER_RUNNING, a cancelled or deactivated one 409 CRAWLER_INACTIVE, a paused one 409 CRAWL_NOT_RETRYABLE (resume it instead), and at the account's cap 429 CRAWLER_LIMIT_REACHED with the crawler left as it was.- Required scope
- crawlers:write
- Idempotency
- Accepts Idempotency-Key
- Webhook events
- None
- Rate limits
Integer. Website and sitemap crawlers are numbered separately, so the same number can name one of each.id(path)Sitemap crawler idPlaceholder in the samples:
<SITEMAP_CRAWLER_ID>Get it from
- POST /v1/sitemap_crawlers returns it as
id - GET /v1/sitemap_crawlers returns it as
data[].id - Webhook crawler.created carries it as
data.object.id crawler.*andcrawl.*events carry only{object, id}, not the crawler kind: keep the kind with the id when you create the crawler.
- POST /v1/sitemap_crawlers returns it as
Path parameters
idintegerRequiredThe sitemap crawler id.
Header parameters
Idempotency-KeystringOptionalMakes a retry safe. The first 2xx answer is stored for 24 h and replayed for the same key withIdempotency-Replayed: true; a retry while the first request runs is 409IDEMPOTENCY_IN_FLIGHT; the same key with a different payload is 422IDEMPOTENCY_KEY_REUSED; a malformed key is 400INVALID_IDEMPOTENCY_KEY.Min length:
16Max length:128Pattern:^[A-Za-z0-9_-]+$
Responses
- 200
CrawlerResourceobjectstringRequiredThe crawler kind:website_crawler(/crawlers) orsitemap_crawler(/sitemap_crawlers). The two kinds are numbered separately.Possible values
sitemap_crawlerwebsite_crawleridintegerRequiredThe crawler id, unique within its kind.namestringnullableRequiredDisplay name.urlstringnullableRequiredThe start URL of a website crawler, or the sitemap URL of a sitemap crawler.statusstringRequiredpending(queued, or a recurring crawler waiting for its next run),running,paused,completed,failedorcancelled. Reachingcompletedorfailedemitscrawl.completedorcrawl.failed.Possible values
pendingrunningpausedcompletedfailedcancelledchatbot_idstringnullableRequiredThe chatbot the collected pages train;nullwhen the crawler only fills a collection.error_codestringnullableRequiredWhy the crawler last failed, as a stable code;nullwhen it has not.Possible values
unreachablehttp_errortoo_many_redirectsinvalid_sitemaptoo_largerobots_blockednever_startedknowledge_limit_reachedunsupported_content_encodingcorrupt_content_encodingunsupported_content_typecontent_too_shortnot_knowledge_indexnot_knowledge_mediaexcluded_by_patternduplicatecanonical_duplicatenear_duplicatesoft_404redirect_externalredirect_other_pagestalledextraction_failedremoved_from_knowledge_basechallenge_blockedunknownnullcreated_atstringnullableRequiredWhen the crawler was created (ISO 8601, UTC).updated_atstringnullableRequiredWhen the crawler last changed (ISO 8601, UTC).
- 400A tenant selector header named a tenant other than the API key's own (
ACCOUNT_SELECTOR_NOT_SUPPORTED): an all-digitX-Account-Idother than the key owner's id or, whileworkspaces.context_enabledis on, anX-Workspace-Idother than the key's workspace (ws_prefix optional, case-insensitive). A header naming the key's own tenant, or a non-numericX-Account-Id, is ignored; a key cannot switch tenants, so send neither. A mutation that honoursIdempotency-Keyalso returnsINVALID_IDEMPOTENCY_KEYwhen that header is not 16–128[A-Za-z0-9_-]characters.Error codesACCOUNT_SELECTOR_NOT_SUPPORTEDINVALID_IDEMPOTENCY_KEY
- 401Missing or invalid API key.
Error codesUNAUTHENTICATED
- 403The API key is missing a required scope.
Error codesACCOUNT_SUSPENDEDINSUFFICIENT_SCOPE
- 404The resource does not exist on this account.
Error codesNOT_FOUND
- 409The request conflicts with the current resource state.
Error codesCRAWLER_INACTIVECRAWLER_RUNNINGCRAWL_NOT_RETRYABLEIDEMPOTENCY_IN_FLIGHT
- 422Validation failed. See
error.details.Error codesIDEMPOTENCY_KEY_REUSED
- 429Rate limited. Honour Retry-After.
Error codesCRAWLER_LIMIT_REACHEDRATE_LIMITED
- 500Unexpected server error. Retry with the same Idempotency-Key.
Error codesSERVER_ERROR
Request
curl -X POST 'https://api.agentency.com/v1/sitemap_crawlers/<SITEMAP_CRAWLER_ID>/retry' \
-H "Authorization: Bearer <YOUR_KEY>" \
-H "Content-Type: application/json"Response
Example 200 response
{
"object": "sitemap_crawler",
"id": 1,
"name": "Product pages",
"url": "https://example.com/sitemap.xml",
"status": "pending",
"chatbot_id": 1,
"error_code": null,
"created_at": "2026-01-01T00:00:00+00:00",
"updated_at": "2026-01-01T00:00:00+00:00"
}