{"openapi":"3.1.0","info":{"title":"querying.ai","description":"One API for every AI answer engine. Every task is asynchronous: submit, then collect the result via webhook or polling.","version":"1.0.0"},"servers":[{"url":"https://api.querying.ai","description":"Production"}],"security":[{"bearerAuth":[]}],"paths":{"/v1/async/task":{"post":{"summary":"Create a task","description":"Queue a single task against one engine. Returns immediately with a task id and status `QUEUED`; the result arrives by webhook or by polling `GET /v1/async/task/{id}`.","operationId":"createTask","tags":["Tasks"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AsyncRequest"},"examples":{"commerce":{"summary":"Storefront product search (3 credits)","value":{"taskType":"COMMERCE_SERP","payload":{"site":"amazon","query":"wireless earbuds","limit":20}}},"commerceProduct":{"summary":"Storefront product page (3 credits)","value":{"taskType":"COMMERCE_PRODUCT","payload":{"url":"https://www.amazon.com/dp/B00TTD9BRC"}}},"llm":{"summary":"LLM engine (reads payload.prompt)","value":{"taskType":"GEMINI","idempotencyKey":"job-42:prompt-7:gemini","priority":1,"webhook":{"url":"https://your-server.example.com/hook"},"payload":{"prompt":"best wireless earbuds 2026","country":"US","include":{"markdown":true}}}},"google":{"summary":"Google AI Overview (reads payload.query)","value":{"taskType":"GOOGLE","payload":{"query":"best wireless earbuds 2026","country":"US"}}}}}}},"responses":{"200":{"description":"Task accepted and queued.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AsyncResponse"}}}},"400":{"description":"`VALIDATION_ERROR`: malformed body, unrecognised `taskType`, a missing or invalid field (`details` names it), or an invalid `webhook.url`. `USE_DEDICATED_ENDPOINT`: CITATION_ANALYSIS and PROMPT_RESEARCH are created through `POST /v1/citation-analysis` and `POST /v1/prompt-research`. `CONVERSATION_EXPIRED`: the ChatGPT conversation named by `payload.continueFrom` can no longer be continued.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed","details":[{"field":"payload.prompt","message":"payload.prompt or payload.query is required"}],"timestamp":"2026-07-09T04:12:00.000Z"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`INSUFFICIENT_CREDITS`: the balance is below the price of the task.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"INSUFFICIENT_CREDITS","message":"insufficient credits (need 2)","timestamp":"2026-07-09T04:12:00.000Z"}}}}},"403":{"description":"`KEY_SCOPE_DENIED`: the engine is outside the key's Allowed engines. `ENGINE_PRIVATE`: the `taskType` is not available on self-serve plans; `details.availableTaskTypes` lists the ones that are.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"keyScope":{"summary":"Engine outside the key's scope","value":{"success":false,"error":{"code":"KEY_SCOPE_DENIED","message":"This API key is not allowed to submit taskType 'GEMINI'","timestamp":"2026-07-09T04:12:00.000Z"}}},"enginePrivate":{"summary":"Engine not sold on self-serve plans","value":{"success":false,"error":{"code":"ENGINE_PRIVATE","message":"taskType 'CLAUDE' is not available on self-serve plans","details":{"taskType":"CLAUDE","retryable":false,"availableTaskTypes":["CHATGPT","GEMINI","..."]},"timestamp":"2026-07-09T04:12:00.000Z"}}}}}}},"409":{"description":"A task with this `idempotencyKey` already exists. The batch endpoint absorbs this as success instead.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"RESOURCE_ALREADY_EXISTS","message":"Task already exists.","timestamp":"2026-07-09T04:12:00.000Z"}}}}},"413":{"description":"`PAYLOAD_TOO_LARGE`: the body exceeds 1 MiB. Rejected before parsing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"PAYLOAD_TOO_LARGE","message":"request body exceeds 1 MiB","timestamp":"2026-07-09T04:12:00.000Z"}}}}},"422":{"$ref":"#/components/responses/RegionUnavailable"},"429":{"description":"Retry after the `Retry-After` header (seconds). `PLAN_CONCURRENCY_LIMIT`: queued and running tasks reached the plan or contract limit. `KEY_DAILY_CREDIT_LIMIT`: the key used up its daily credit limit. `SUB_ACCOUNT_CREDIT_LIMIT`: the sub-account would exceed its `monthlyCreditLimit`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"PLAN_CONCURRENCY_LIMIT","message":"free plan allows 2 concurrent tasks; 2 already active","details":{"plan":"free","limit":2,"source":"plan","active":2,"retryAfterSec":5},"timestamp":"2026-07-09T04:12:00.000Z"}}}}},"503":{"description":"Retry after the `Retry-After` header (seconds). `QUEUE_BACKPRESSURE`: this engine's queue is full. `SERVER_OVERLOADED`: admission is saturated, or the task queue as a whole is full. `DB_UNAVAILABLE`: task storage did not answer. `ENGINE_UNAVAILABLE`: this engine is temporarily not accepting tasks. `EVIDENCE_UNAVAILABLE`: HTML pages of answers are not available right now.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"DB_UNAVAILABLE","message":"Task storage unavailable — retry shortly","details":{"retryAfterSec":2,"retryable":true},"timestamp":"2026-07-09T04:12:00.000Z"}}}}}}}},"/v1/async/task/batch":{"post":{"summary":"Create tasks in bulk","description":"Queue up to 500 tasks in one request. Engines may be mixed freely.\n\nA well-formed request returns `200` and each task's outcome in `results[]`: per-task failures surface as `results[].success = false` so one bad task never sinks the rest. A duplicate `idempotencyKey` is absorbed as **success**, returning the existing task. The whole request is refused before any task is created with `400` (malformed body), `413` (over 8 MiB) or `503 SERVER_OVERLOADED` (admission is saturated, or the global queue is full), which carries `Retry-After`.","operationId":"createTaskBatch","tags":["Tasks"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"array","minItems":1,"maxItems":500,"items":{"$ref":"#/components/schemas/AsyncRequest"}},"example":[{"taskType":"GEMINI","idempotencyKey":"job-42:p1:gemini","payload":{"prompt":"best wireless earbuds 2026"}},{"taskType":"PERPLEXITY","idempotencyKey":"job-42:p1:perplexity","payload":{"prompt":"best wireless earbuds 2026"}},{"taskType":"GOOGLE","idempotencyKey":"job-42:p1:google","payload":{"query":"best wireless earbuds 2026"}}]}}},"responses":{"200":{"description":"Batch processed. Inspect `results[]` for per-task outcomes.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AsyncBatchResult"},"example":{"success":true,"summary":{"total":3,"succeeded":2,"failed":1},"results":[{"success":true,"index":0,"task":{"id":"8f2c1e40-0000-0000-0000-000000000000","taskType":"GEMINI","status":"QUEUED","priority":1,"createdAt":"2026-07-09T04:12:00.000Z","idempotencyKey":"job-42:p1:gemini"},"credits":{"creditsToCharge":0,"creditsCharged":0}},{"success":false,"index":1,"error":{"code":"QUEUE_BACKPRESSURE","message":"PERPLEXITY queue is full","details":{"taskType":"PERPLEXITY","retryAfterSec":5,"retryable":true},"timestamp":"2026-07-09T04:12:00.000Z"}},{"success":true,"index":2,"task":{"id":"1b7d9c22-0000-0000-0000-000000000000","taskType":"GOOGLE","status":"QUEUED","priority":1,"createdAt":"2026-07-09T04:12:00.000Z","idempotencyKey":"job-42:p1:google"},"credits":{"creditsToCharge":0,"creditsCharged":0}}]}}}},"400":{"description":"The request as a whole is malformed — not valid JSON, not an array, empty, or over 500 items.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed","details":[{"field":"","message":"Too small: expected array to have >=1 items"}],"timestamp":"2026-07-09T04:12:00.000Z"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"description":"Batch body exceeds 8 MiB (8,388,608 bytes). Rejected before parsing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"PAYLOAD_TOO_LARGE","message":"batch body exceeds 8388608 bytes","timestamp":"2026-07-09T04:12:00.000Z"}}}}},"503":{"description":"`SERVER_OVERLOADED`: admission is saturated, or the global task queue is full; no task was created. When the queue is full, `details` carries `queueDepth`, `queueLimit` and `retryAfterSec`. Retry after the `Retry-After` header (seconds).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/async/task/{id}":{"get":{"summary":"Get a task","description":"Fetch a task by id. `response` is absent until the task reaches a terminal state. `credits` is `0` until the task is terminal, then shows the settled charge (`0` for a failed task). A terminal task can be polled for 24 hours after it completes; after that this returns `404`.","operationId":"getTask","tags":["Tasks"],"parameters":[{"name":"id","in":"path","required":true,"description":"The task id returned at submit time.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The task, plus `response` or `error` once terminal.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskResponse"},"examples":{"queued":{"summary":"Still queued — no response yet","value":{"success":true,"task":{"id":"8f2c1e40-0000-0000-0000-000000000000","taskType":"GEMINI","status":"QUEUED","priority":1,"createdAt":"2026-07-09T04:12:00.000Z"},"credits":{"creditsToCharge":0,"creditsCharged":0}}},"completed":{"summary":"Completed","value":{"success":true,"task":{"id":"8f2c1e40-0000-0000-0000-000000000000","taskType":"GEMINI","status":"COMPLETED","priority":1,"createdAt":"2026-07-09T04:12:00.000Z"},"credits":{"creditsToCharge":1.25,"creditsCharged":1.25},"response":{"text":"The best wireless earbuds in 2026 are ...","sources":[{"position":1,"url":"https://example.com/review","label":"Best earbuds, reviewed"}]}}},"failed":{"summary":"Failed — note `error` is a string here, not an object","value":{"success":true,"task":{"id":"8f2c1e40-0000-0000-0000-000000000000","taskType":"GEMINI","status":"FAILED","priority":1,"createdAt":"2026-07-09T04:12:00.000Z"},"credits":{"creditsToCharge":0,"creditsCharged":0},"error":"ENGINE_TIMEOUT: The engine did not answer before the task deadline."}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"Unknown task id, another account's task, or a terminal task past the 24-hour polling window. The cases are indistinguishable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"RESOURCE_NOT_FOUND","message":"Task not found","details":{"id":"8f2c1e40-0000-0000-0000-000000000000"},"timestamp":"2026-07-09T04:12:00.000Z"}}}}}}}},"/v1/batches":{"post":{"summary":"Create a batch","operationId":"createBatch","tags":["Tasks"],"description":"Submit up to 10,000 tasks as one batch and receive a batch id. Every item is checked first: one invalid item returns `400` with the failing items' indexes and nothing is stored.\n\nThe batch keeps its items and turns them into tasks as your plan's active-task limit and each engine's queue have room, so a batch larger than your limit runs through without retries on your side. Accounts share engine room turn by turn, so a large batch and a small one from another account move together.\n\nFollow progress with `GET /v1/batches/{id}` and read results with `GET /v1/batches/{id}/items`. With `webhook.url`, each task posts its result there as a single task does, and the batch posts `{\"event\":\"batch.completed\",\"batch\":{...}}` once when it completes, signed with the same `querying-webhook-*` headers (`querying-webhook-id` is `batch_<id>`).\n\n`POST /v1/async/task/batch` (500 tasks, created in the request) remains available.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchRequest"},"example":{"idempotencyKey":"daily-2026-10-09","webhook":{"url":"https://example.com/hooks/querying"},"metadata":{"run":"daily"},"items":[{"customId":"shoes-chatgpt-us","taskType":"CHATGPT","payload":{"prompt":"best running shoes 2026","country":"US"}},{"customId":"shoes-gemini-us","taskType":"GEMINI","payload":{"prompt":"best running shoes 2026","country":"US"}}]}}}},"responses":{"200":{"description":"A batch with this `idempotencyKey` already exists; it is returned unchanged.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchResponse"}}}},"202":{"description":"Batch stored. The first items are already queued.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchResponse"},"example":{"success":true,"batch":{"id":"3f6b2a10-0000-0000-0000-000000000000","status":"OPEN","total":10000,"counts":{"pending":9520,"queued":480,"processing":0,"completed":0,"failed":0,"rejected":0},"createdAt":"2026-10-09T09:00:00.000Z","completedAt":null,"idempotencyKey":"daily-2026-10-09","webhook":{"url":"https://example.com/hooks/querying"},"metadata":{"run":"daily"}}}}}},"400":{"description":"Invalid body or items. `details.items` lists up to 50 failing items with their index, code and message; `details.invalidItems` counts all of them.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"1 of 10000 items are invalid; the batch was not stored","details":{"invalidItems":1,"items":[{"index":17,"code":"VALIDATION_ERROR","message":"Request validation failed","details":[{"field":"payload.prompt","message":"Invalid input: expected string, received undefined"}]}]},"timestamp":"2026-10-09T09:00:00.000Z"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"description":"Body exceeds 32 MiB.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"PAYLOAD_TOO_LARGE","message":"batch body exceeds 33554432 bytes","timestamp":"2026-10-09T09:00:00.000Z"}}}}}}}},"/v1/batches/{id}":{"get":{"summary":"Get a batch","operationId":"getBatch","tags":["Tasks"],"description":"Progress of a batch: item counts by status. Polling also moves pending items into the queue when there is room, so a client that polls every few seconds keeps its batch flowing.","parameters":[{"name":"id","in":"path","required":true,"description":"The batch id returned by POST /v1/batches.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The batch.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchResponse"},"example":{"success":true,"batch":{"id":"3f6b2a10-0000-0000-0000-000000000000","status":"COMPLETED","total":10000,"counts":{"pending":0,"queued":0,"processing":0,"completed":9987,"failed":11,"rejected":2},"createdAt":"2026-10-09T09:00:00.000Z","completedAt":"2026-10-09T09:41:12.000Z","idempotencyKey":"daily-2026-10-09","webhook":{"url":"https://example.com/hooks/querying"},"metadata":{"run":"daily"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"No batch with this id belongs to your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"RESOURCE_NOT_FOUND","message":"Batch not found","timestamp":"2026-10-09T09:00:00.000Z"}}}}}}}},"/v1/batches/{id}/items":{"get":{"summary":"List batch items","operationId":"listBatchItems","tags":["Tasks"],"description":"Items in submission order, a page at a time. Pass `nextCursor` back as `cursor` until it is null. With `include=response` each finished item carries its task's result.","parameters":[{"name":"id","in":"path","required":true,"description":"The batch id returned by POST /v1/batches.","schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"`nextCursor` from the previous page."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":1000},"description":"Items per page: default 100, up to 1,000; with `include=response` default 20, up to 100."},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["pending","queued","processing","completed","failed","rejected"]}},{"name":"include","in":"query","required":false,"schema":{"type":"string","enum":["response"]}}],"responses":{"200":{"description":"One page of items.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchItemsResponse"},"example":{"success":true,"nextCursor":"99","items":[{"index":0,"customId":"shoes-chatgpt-us","taskType":"CHATGPT","status":"COMPLETED","taskId":"8f2c1e40-0000-0000-0000-000000000000","completedAt":"2026-10-09T09:01:02.000Z"},{"index":1,"customId":"shoes-gemini-us","taskType":"GEMINI","status":"QUEUED","taskId":"1b7d9c22-0000-0000-0000-000000000000"}]}}}},"400":{"description":"Invalid cursor, limit or status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"No batch with this id belongs to your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"RESOURCE_NOT_FOUND","message":"Batch not found","timestamp":"2026-10-09T09:00:00.000Z"}}}}}}}},"/v1/sub-accounts":{"get":{"summary":"List sub-accounts","operationId":"listSubAccounts","tags":["Sub-accounts"],"description":"Your sub-accounts, oldest first, each with this UTC month's usage. Pass nextCursor back as cursor for the next page.","parameters":[{"name":"externalId","in":"query","description":"Only the sub-account with this externalId.","schema":{"type":"string"}},{"name":"limit","in":"query","description":"Page size, 1 to 1,000. Default 100.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":100}},{"name":"cursor","in":"query","description":"nextCursor from the previous page.","schema":{"type":"string"}}],"responses":{"200":{"description":"A page of sub-accounts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubAccountListResponse"}}}},"400":{"description":"A field is missing, out of range or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"unknown field creditLimit; allowed: name, externalId, monthlyCreditLimit, concurrencyLimit","timestamp":"2026-10-09T09:00:00.000Z"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"The key cannot manage sub-accounts: it has an engine scope or a daily credit limit, it is a sub-account's key, or it is an operator key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"SUB_ACCOUNT_FORBIDDEN","message":"Managing sub-accounts needs an API key without an engine scope or a daily credit limit","timestamp":"2026-10-09T09:00:00.000Z"}}}}}}},"post":{"summary":"Create a sub-account","operationId":"createSubAccount","tags":["Sub-accounts"],"description":"Create an account for one of your end customers. It gets its own API keys (POST /v1/sub-accounts/{id}/keys), tasks, batches and monitors, and its charges are drawn from your balance. Your plan's or contract's concurrency limit covers you and every sub-account together. Call with one of your own keys that has no engine scope and no daily credit limit.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubAccountCreateRequest"},"example":{"name":"Acme","externalId":"cust_acme","monthlyCreditLimit":200000,"concurrencyLimit":50}}}},"responses":{"201":{"description":"The new sub-account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubAccountResponse"},"example":{"success":true,"data":{"id":"0199d2a4-5b10-7000-8000-000000000001","name":"Acme","externalId":"cust_acme","status":"active","monthlyCreditLimit":200000,"concurrencyLimit":50,"createdAt":"2026-10-09T09:00:00.000Z","suspendedAt":null,"usage":{"month":"2026-10","credits":0,"tasks":0,"reservedCredits":0}}}}}},"400":{"description":"A field is missing, out of range or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"unknown field creditLimit; allowed: name, externalId, monthlyCreditLimit, concurrencyLimit","timestamp":"2026-10-09T09:00:00.000Z"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"The key cannot manage sub-accounts: it has an engine scope or a daily credit limit, it is a sub-account's key, or it is an operator key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"SUB_ACCOUNT_FORBIDDEN","message":"Managing sub-accounts needs an API key without an engine scope or a daily credit limit","timestamp":"2026-10-09T09:00:00.000Z"}}}}},"409":{"description":"Another of your sub-accounts already has this externalId. Find it with GET /v1/sub-accounts?externalId=.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"SUB_ACCOUNT_EXISTS","message":"Another sub-account already has that externalId","timestamp":"2026-10-09T09:00:00.000Z"}}}}}}}},"/v1/sub-accounts/usage":{"get":{"summary":"Usage of every sub-account","operationId":"listSubAccountUsage","tags":["Sub-accounts"],"description":"Credits and tasks charged to each sub-account over an inclusive range of UTC dates, largest first. Sub-accounts with no charge in the range are left out. Failed tasks are never charged.","parameters":[{"name":"from","in":"query","description":"First UTC date, inclusive. Default: the first day of the current UTC month.","schema":{"type":"string","format":"date"}},{"name":"to","in":"query","description":"Last UTC date, inclusive. Default: today (UTC). The range spans at most 366 days, from and to included.","schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Totals per sub-account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubAccountUsageResponse"}}}},"400":{"description":"from or to is not a YYYY-MM-DD date, to is before from, or the range spans more than 366 days.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"to must not be before from","timestamp":"2026-10-09T09:00:00.000Z"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"The key cannot manage sub-accounts: it has an engine scope or a daily credit limit, it is a sub-account's key, or it is an operator key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"SUB_ACCOUNT_FORBIDDEN","message":"Managing sub-accounts needs an API key without an engine scope or a daily credit limit","timestamp":"2026-10-09T09:00:00.000Z"}}}}}}}},"/v1/sub-accounts/{id}":{"get":{"summary":"Get a sub-account","operationId":"getSubAccount","tags":["Sub-accounts"],"description":"One sub-account with this month's usage and the tasks it has queued or running now.","parameters":[{"name":"id","in":"path","required":true,"description":"The sub-account id.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The sub-account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubAccountDetailResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"The key cannot manage sub-accounts: it has an engine scope or a daily credit limit, it is a sub-account's key, or it is an operator key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"SUB_ACCOUNT_FORBIDDEN","message":"Managing sub-accounts needs an API key without an engine scope or a daily credit limit","timestamp":"2026-10-09T09:00:00.000Z"}}}}},"404":{"description":"No sub-account with this id belongs to your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"NOT_FOUND","message":"No sub-account with that id","timestamp":"2026-10-09T09:00:00.000Z"}}}}}}},"patch":{"summary":"Update or suspend a sub-account","operationId":"updateSubAccount","tags":["Sub-accounts"],"description":"Change its name, externalId or limits (null removes a limit), or set status. Suspending stops its keys within five seconds (401), stops its monitors and ends its batch items that have not started; tasks already queued or running finish and are charged. Setting status back to active restores the keys and monitors.","parameters":[{"name":"id","in":"path","required":true,"description":"The sub-account id.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubAccountUpdateRequest"},"example":{"status":"suspended"}}}},"responses":{"200":{"description":"The updated sub-account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubAccountResponse"}}}},"400":{"description":"A field is missing, out of range or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"unknown field creditLimit; allowed: name, externalId, monthlyCreditLimit, concurrencyLimit","timestamp":"2026-10-09T09:00:00.000Z"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"The key cannot manage sub-accounts: it has an engine scope or a daily credit limit, it is a sub-account's key, or it is an operator key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"SUB_ACCOUNT_FORBIDDEN","message":"Managing sub-accounts needs an API key without an engine scope or a daily credit limit","timestamp":"2026-10-09T09:00:00.000Z"}}}}},"404":{"description":"No sub-account with this id belongs to your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"NOT_FOUND","message":"No sub-account with that id","timestamp":"2026-10-09T09:00:00.000Z"}}}}},"409":{"description":"Another of your sub-accounts already has this externalId.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"SUB_ACCOUNT_EXISTS","message":"Another sub-account already has that externalId","timestamp":"2026-10-09T09:00:00.000Z"}}}}}}}},"/v1/sub-accounts/{id}/usage":{"get":{"summary":"Daily usage of a sub-account","operationId":"getSubAccountUsage","tags":["Sub-accounts"],"description":"Credits and tasks charged to one sub-account per UTC day and engine. taskType OTHER is a charge that is not a task, such as a monitor's competitor analysis.","parameters":[{"name":"id","in":"path","required":true,"description":"The sub-account id.","schema":{"type":"string","format":"uuid"}},{"name":"from","in":"query","description":"First UTC date, inclusive. Default: the first day of the current UTC month.","schema":{"type":"string","format":"date"}},{"name":"to","in":"query","description":"Last UTC date, inclusive. Default: today (UTC). The range spans at most 366 days, from and to included.","schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Credit and task totals for the range, and one row per UTC date and engine that had a charge.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubAccountDailyUsageResponse"}}}},"400":{"description":"from or to is not a YYYY-MM-DD date, to is before from, or the range spans more than 366 days.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"to must not be before from","timestamp":"2026-10-09T09:00:00.000Z"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"The key cannot manage sub-accounts: it has an engine scope or a daily credit limit, it is a sub-account's key, or it is an operator key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"SUB_ACCOUNT_FORBIDDEN","message":"Managing sub-accounts needs an API key without an engine scope or a daily credit limit","timestamp":"2026-10-09T09:00:00.000Z"}}}}},"404":{"description":"No sub-account with this id belongs to your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"NOT_FOUND","message":"No sub-account with that id","timestamp":"2026-10-09T09:00:00.000Z"}}}}}}}},"/v1/sub-accounts/{id}/keys":{"get":{"summary":"List a sub-account's keys","operationId":"listSubAccountKeys","tags":["Sub-accounts"],"description":"Every key of the sub-account, newest first, including revoked and expired ones. Never the key itself.","parameters":[{"name":"id","in":"path","required":true,"description":"The sub-account id.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The keys.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubAccountKeyListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"The key cannot manage sub-accounts: it has an engine scope or a daily credit limit, it is a sub-account's key, or it is an operator key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"SUB_ACCOUNT_FORBIDDEN","message":"Managing sub-accounts needs an API key without an engine scope or a daily credit limit","timestamp":"2026-10-09T09:00:00.000Z"}}}}},"404":{"description":"No sub-account with this id belongs to your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"NOT_FOUND","message":"No sub-account with that id","timestamp":"2026-10-09T09:00:00.000Z"}}}}}}},"post":{"summary":"Issue a sub-account key","operationId":"createSubAccountKey","tags":["Sub-accounts"],"description":"Issue an API key for the sub-account. The response carries key once; store it. Up to 5 active keys per sub-account.","parameters":[{"name":"id","in":"path","required":true,"description":"The sub-account id.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubAccountKeyRequest"},"example":{"name":"production","allowedTaskTypes":["CHATGPT","GEMINI"]}}}},"responses":{"201":{"description":"The new key, with the raw key in key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubAccountKeyCreatedResponse"}}}},"400":{"description":"A field is missing, out of range or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"unknown field creditLimit; allowed: name, externalId, monthlyCreditLimit, concurrencyLimit","timestamp":"2026-10-09T09:00:00.000Z"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"The key cannot manage sub-accounts: it has an engine scope or a daily credit limit, it is a sub-account's key, or it is an operator key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"SUB_ACCOUNT_FORBIDDEN","message":"Managing sub-accounts needs an API key without an engine scope or a daily credit limit","timestamp":"2026-10-09T09:00:00.000Z"}}}}},"404":{"description":"No sub-account with this id belongs to your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"NOT_FOUND","message":"No sub-account with that id","timestamp":"2026-10-09T09:00:00.000Z"}}}}},"409":{"description":"The sub-account already has 5 active keys.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"KEY_LIMIT","message":"Max 5 active keys per sub-account — revoke one first","timestamp":"2026-10-09T09:00:00.000Z"}}}}}}}},"/v1/sub-accounts/{id}/keys/{keyId}":{"delete":{"summary":"Revoke a sub-account key","operationId":"revokeSubAccountKey","tags":["Sub-accounts"],"description":"Revoke one key. It stops working within five seconds.","parameters":[{"name":"id","in":"path","required":true,"description":"The sub-account id.","schema":{"type":"string","format":"uuid"}},{"name":"keyId","in":"path","required":true,"description":"The key id.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Revoked.","content":{"application/json":{"example":{"success":true,"data":{"revoked":"6b1f0c52-0000-0000-0000-000000000000"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"The key cannot manage sub-accounts: it has an engine scope or a daily credit limit, it is a sub-account's key, or it is an operator key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"SUB_ACCOUNT_FORBIDDEN","message":"Managing sub-accounts needs an API key without an engine scope or a daily credit limit","timestamp":"2026-10-09T09:00:00.000Z"}}}}},"404":{"description":"No active key with this id belongs to the sub-account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"NOT_FOUND","message":"No active key with that id","timestamp":"2026-10-09T09:00:00.000Z"}}}}}}}},"/health":{"get":{"summary":"Liveness probe","description":"Shallow liveness check. Does not touch the database. Requires no authentication.","operationId":"getHealth","tags":["Operations"],"security":[],"responses":{"200":{"description":"The process is alive.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"ts":{"type":"string","format":"date-time"}}},"example":{"ok":true,"ts":"2026-07-09T04:12:00.000Z"}}}}}}},"/ready":{"get":{"summary":"Readiness probe","description":"Checks database connectivity, unlike `/health`. Returns `503` when the database is unreachable, so load balancers and deploy gates reflect real serving capability. Requires no authentication.","operationId":"getReady","tags":["Operations"],"security":[],"responses":{"200":{"description":"Ready to serve.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"db":{"type":"boolean"},"ts":{"type":"string","format":"date-time"}}},"example":{"ok":true,"db":true,"ts":"2026-07-09T04:12:00.000Z"}}}},"503":{"description":"The database is unreachable.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"db":{"type":"boolean"},"error":{"type":"string"}}},"example":{"ok":false,"db":false,"error":"connection refused"}}}}}}},"/stats":{"get":{"summary":"Your task counts","description":"Counts of your own account's tasks by state. A customer key sees only its account's tasks; fleet-wide queue figures are not public.","operationId":"getStats","tags":["Operations"],"responses":{"200":{"description":"Current statistics.","content":{"application/json":{"schema":{"type":"object","properties":{"tasks":{"type":"object","description":"Your account's tasks. `pending` counts QUEUED tasks and `running` PROCESSING tasks right now; `completed` and `failed` count tasks that finished in the last 24 hours.","properties":{"pending":{"type":"integer"},"running":{"type":"integer"},"completed":{"type":"integer"},"failed":{"type":"integer"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/async/status":{"get":{"summary":"Get queue status","description":"Your queued and processing tasks, and the concurrency limit they count against. A sub-account's tasks count toward its parent account's. `concurrency.used` is queued plus processing tasks, because your plan limit counts both: a submit that would pass `max` returns `429 PLAN_CONCURRENCY_LIMIT`. Reading it costs nothing.","operationId":"getAsyncStatus","tags":["Operations"],"responses":{"200":{"description":"Your queue right now.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueueStatus"},"example":{"success":true,"queuedTasks":19,"processingTasks":6,"priorityBreakdown":[{"priority":8,"count":3},{"priority":1,"count":16}],"concurrency":{"used":25,"max":200}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"The key belongs to a sub-account. A sub-account queues inside its parent account's concurrency limit; the parent account reads the queue here, and a sub-account key reads its own task counts at GET /stats.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"SUB_ACCOUNT_FORBIDDEN","message":"A sub-account queues inside its parent account's concurrency limit. The parent account reads the queue at GET /v1/async/status; a sub-account key reads its own task counts at GET /stats","timestamp":"2026-10-20T00:00:00.000Z"}}}}}}}},"/capacity":{"get":{"summary":"ChatGPT serving mode","description":"The serving mode of the ChatGPT lane. A customer key receives only `{\"chatgpt\": {\"mode\": \"anon\"}}`; it reports no per-region capacity. Use `GET /v1/capabilities` for engines, prices and country policy.","operationId":"getCapacity","tags":["Operations"],"responses":{"200":{"description":"Capacity per engine.","content":{"application/json":{"schema":{"type":"object","properties":{"chatgpt":{"type":"object","properties":{"mode":{"type":"string","example":"anon"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/credits":{"get":{"summary":"Get credit balance","description":"Your account's credits: what you can spend now, what your queued and running tasks hold, what your plan grants each cycle and when the cycle ends, and your top-up credits. Reading it costs nothing, so a program can check it before each batch.","operationId":"getCredits","tags":["Operations"],"responses":{"200":{"description":"Your account's credits.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditBalance"},"example":{"success":true,"remaining":1879939,"perCycle":1000000,"cycleResetsAt":"2026-11-14T07:37:57.000Z","reserved":61,"plan":"max","topUpBalance":{"credits":1000000,"nextExpiresAt":"2027-01-19T10:01:57.000Z","nextCredits":1000000}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"The key belongs to a sub-account. A sub-account spends its parent account's credits and has no balance; the parent account reads its usage at GET /v1/sub-accounts/{id}/usage.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"SUB_ACCOUNT_FORBIDDEN","message":"A sub-account spends its parent account's credits. The parent account reads its usage at /v1/sub-accounts/{id}/usage","timestamp":"2026-10-20T00:00:00.000Z"}}}}}}}},"/v1/usage":{"get":{"summary":"Get usage","description":"What your account was charged over a range of UTC dates, split by day, engine and key as you choose. It counts what tasks were charged. A monitor's monthly competitor read is charged without a task, so it lowers your balance but is not in usage. Reading it costs nothing.","operationId":"getUsage","tags":["Operations"],"parameters":[{"name":"from","in":"query","description":"First UTC date, inclusive. Default: the first day of the current UTC month.","schema":{"type":"string","format":"date"}},{"name":"to","in":"query","description":"Last UTC date, inclusive. Default: today (UTC). The range spans at most 366 days, from and to included.","schema":{"type":"string","format":"date"}},{"name":"groupBy","in":"query","description":"How to split the rows: a comma-separated choice of `day`, `engine` and `key`. Default: `day,engine`.","schema":{"type":"string","default":"day,engine","examples":["engine","day,key"]}}],"responses":{"200":{"description":"Credit and task totals for the range, and one row per combination of the chosen splits that had a charge.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Usage"},"example":{"success":true,"data":{"from":"2026-10-01","to":"2026-10-20","groupBy":["day","engine"],"credits":66.25,"tasks":65,"rows":[{"date":"2026-10-17","taskType":"CHATGPT","credits":42,"tasks":42},{"date":"2026-10-17","taskType":"PERPLEXITY","credits":9,"tasks":9},{"date":"2026-10-20","taskType":"CHATGPT","credits":7,"tasks":7},{"date":"2026-10-20","taskType":"GEMINI","credits":6.25,"tasks":5},{"date":"2026-10-20","taskType":"PERPLEXITY","credits":2,"tasks":2}]}}}}},"400":{"description":"A date is not a `YYYY-MM-DD` date, `to` is before `from`, the range spans more than 366 days, or `groupBy` names something other than `day`, `engine` and `key`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"groupBy must name some of day, engine, key, separated by commas","timestamp":"2026-10-20T00:00:00.000Z"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"The key belongs to a sub-account. A sub-account spends its parent account's credits and has no balance; the parent account reads its usage at GET /v1/sub-accounts/{id}/usage.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"SUB_ACCOUNT_FORBIDDEN","message":"A sub-account spends its parent account's credits. The parent account reads its usage at /v1/sub-accounts/{id}/usage","timestamp":"2026-10-20T00:00:00.000Z"}}}}}}}},"/v1/citation-analysis":{"post":{"summary":"Analyze answer claims and cited sources","operationId":"createCitationAnalysis","tags":["Research"],"description":"Analyzes an answer against its cited pages and returns a version 4 result: the searches the engine ran, the pages it retrieved and cited and who controls each, the brands the answer names and the pages naming them, the brand's visibility stage and prioritized actions with steps (with brand), the paragraphs of each cited page mapped to UTF-16 answer ranges with explanations, and short summaries of what the pages add up to. Post-hoc correspondence, not causal attribution. The retired analysis.version=1 opt-in is rejected with 400 because insights are automatic. Tasks stored with the older v2 result stay readable as-is. Size is not a failure mode: anything the request contract accepts (an answer up to 200,000 characters with up to 100 citations) is analyzed, with long answers, large source sets and very long pages handled by splitting the work. Depth follows the answer rather than the page, so a large or repetitive page yields its strongest corresponding passages instead of every occurrence, and markup-only pages such as sitemaps or link indexes contribute no links.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CitationAnalysisRequest"},"examples":{"answerAndCitations":{"summary":"Answer and citations","value":{"answer":"Teams plan starts at $19.95 per month for up to 10 users. The Business plan adds audit logs.","prompt":"Which plan fits a small team?","citations":[{"url":"https://example.com/pricing"},{"url":"https://review.example.com/note"}]}},"taskId":{"summary":"A completed answer task","value":{"taskId":"7c1f0b2e-5d0a-4a8e-9f3b-2c1d6e7a8b90","brand":"Acme","competitors":["Beta"]}}}}}},"responses":{"200":{"description":"Queued; poll /v1/async/task/{id}. Its response follows CitationAnalysisResult.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AsyncResponse"}}}},"400":{"description":"Request rejected. Supplying the retired analysis opt-in is a 400 because insights are automatic.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Request rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"taskId does not name a task you can read (unknown, another account's, or past retention)."},"409":{"description":"Request rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"Request rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Request rejected, including brandDomains or brandAliases sent without brand, and an input that exceeds a processing limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Request rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Request rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/geo-audit":{"post":{"summary":"Deprecated alias of /v1/citation-analysis","operationId":"createGeoAuditAlias","tags":["Research"],"deprecated":true,"description":"Deprecated alias of /v1/citation-analysis, identical in every respect.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CitationAnalysisRequest"},"examples":{"answerAndCitations":{"summary":"Answer and citations","value":{"answer":"Teams plan starts at $19.95 per month for up to 10 users. The Business plan adds audit logs.","prompt":"Which plan fits a small team?","citations":[{"url":"https://example.com/pricing"},{"url":"https://review.example.com/note"}]}},"taskId":{"summary":"A completed answer task","value":{"taskId":"7c1f0b2e-5d0a-4a8e-9f3b-2c1d6e7a8b90","brand":"Acme","competitors":["Beta"]}}}}}},"responses":{"200":{"description":"Queued; poll /v1/async/task/{id}. Its response follows CitationAnalysisResult.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AsyncResponse"}}}},"400":{"description":"Request rejected. Supplying the retired analysis opt-in is a 400 because insights are automatic.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Request rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"taskId does not name a task you can read (unknown, another account's, or past retention)."},"409":{"description":"Request rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"Request rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Request rejected, including brandDomains or brandAliases sent without brand, and an input that exceeds a processing limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Request rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Request rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/source-influence":{"post":{"summary":"Deprecated alias of /v1/citation-analysis","operationId":"createSourceInfluenceAlias","tags":["Research"],"deprecated":true,"description":"Deprecated alias of /v1/citation-analysis, identical in every respect.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CitationAnalysisRequest"},"examples":{"answerAndCitations":{"summary":"Answer and citations","value":{"answer":"Teams plan starts at $19.95 per month for up to 10 users. The Business plan adds audit logs.","prompt":"Which plan fits a small team?","citations":[{"url":"https://example.com/pricing"},{"url":"https://review.example.com/note"}]}},"taskId":{"summary":"A completed answer task","value":{"taskId":"7c1f0b2e-5d0a-4a8e-9f3b-2c1d6e7a8b90","brand":"Acme","competitors":["Beta"]}}}}}},"responses":{"200":{"description":"Queued; poll /v1/async/task/{id}. Its response follows CitationAnalysisResult.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AsyncResponse"}}}},"400":{"description":"Request rejected. Supplying the retired analysis opt-in is a 400 because insights are automatic.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Request rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"taskId does not name a task you can read (unknown, another account's, or past retention)."},"409":{"description":"Request rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"Request rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Request rejected, including brandDomains or brandAliases sent without brand, and an input that exceeds a processing limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Request rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Request rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/research":{"post":{"summary":"Deprecated alias of /v1/citation-analysis","operationId":"createResearchAlias","tags":["Research"],"deprecated":true,"description":"Deprecated alias of /v1/citation-analysis, identical in every respect.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CitationAnalysisRequest"},"example":{"answer":"Teams plan starts at $19.95 per month for up to 10 users. The Business plan adds audit logs.","prompt":"Which plan fits a small team?","citations":[{"url":"https://example.com/pricing"},{"url":"https://review.example.com/note"}]}}}},"responses":{"200":{"description":"Queued; poll /v1/async/task/{id}. Its response follows CitationAnalysisResult.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AsyncResponse"}}}},"400":{"description":"Request rejected. Supplying the retired analysis opt-in is a 400 because insights are automatic.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Request rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Request rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"Request rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Request rejected, including brandDomains or brandAliases sent without brand, and an input that exceeds a processing limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Request rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Request rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/monitors":{"get":{"summary":"List monitors","operationId":"listMonitors","tags":["Monitors"],"description":"Every monitor this key owns, newest first. Each carries its 30-day mention and citation rollup in stats, the rollup window (windowDays) and the schedule state (enabled, nextRunAt, lastRunAt). A monitor with no scored answers yet is listed with an all-zero stats rather than hidden. A category monitor (mode CATEGORY) also carries leader: the brand its answers named most in the window, or null when none was named yet. Its stats.mentioned and stats.cited are always 0.","responses":{"200":{"description":"The monitors and their 30-day rollup.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"summary":"Create a monitor","operationId":"createMonitor","tags":["Monitors"],"description":"Save a named prompt set in one market and start its schedule. The first run starts inside this call: the answer tasks your plan admits are queued before it returns and the schedule queues the rest within a minute. A run submits prompts x points x samples ordinary async tasks for each engine it includes that spend credits from the plan's existing balance, then repeats every intervalHours until paused or deleted. A run's tasks must not exceed the tasksPerRun limit GET /v1/monitors/capabilities reports for the account, and a run too large for its engine to drain before that engine runs again is a 400 naming the interval that fits; engineSettings sets samples and a slower cadence per engine, and webhookUrl turns on change events; a key restricted to some engines may only schedule those engines (403 KEY_SCOPE_DENIED otherwise). Set mode to CATEGORY to follow a market with no brand of its own: it takes category, promptTopics and up to 25 competitors, and a value for aliases, domains or alertBelowPct is a 400. mode is fixed at creation.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMonitorRequest"},"examples":{"earbuds":{"summary":"Two engines, one prompt, one competitor","value":{"name":"Earbud brand tracking","engines":["CHATGPT","GEMINI"],"prompts":["best wireless earbuds for commuting"],"aliases":["Acme Audio","Acme"],"domains":["example.com"],"competitors":[{"name":"Sony","aliases":["Sony"]}],"country":"US","intervalHours":24}},"category":{"summary":"A category monitor: a market with sub-fields","value":{"name":"Sunscreen market","mode":"CATEGORY","category":"Sunscreen","engines":["CHATGPT","GEMINI"],"prompts":["best sunscreen for sensitive skin","best sunscreen for kids"],"promptTopics":{"best sunscreen for sensitive skin":"Sensitive skin","best sunscreen for kids":"Kids"},"competitors":[{"name":"Supergoop"},{"name":"La Roche-Posay","aliases":["LRP"]}],"country":"US","intervalHours":24}}}}}},"responses":{"201":{"description":"Monitor created and scheduled.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorResponse"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/KeyScopeDenied"},"409":{"$ref":"#/components/responses/MonitorLimit"}}}},"/v1/monitors/capabilities":{"get":{"summary":"Get monitor capabilities","operationId":"getMonitorCapabilities","tags":["Monitors"],"description":"The monitoring contract as data: which engines a monitor may schedule and what each task costs in credits, the published limits, the definition of every metric a report returns, the workflow the endpoints implement, and how a schedule consumes credits. A cheap read with no side effects — call it before configuring anything or writing a dashboard.","responses":{"200":{"description":"Engines, limits, metric definitions, workflow and schedule economics.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorCapabilitiesResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/monitors/suggest":{"post":{"summary":"Suggest prompts","operationId":"suggestMonitorPrompts","tags":["Monitors"],"description":"Turn the brand facts already in a setup form into candidate prompts, in the language a buyer in that country would use. Stateless: nothing is saved, no task is created and no credits are spent. Suggestions naming the brand or its aliases are dropped, because a prompt that contains the brand always scores 100% and measures nothing. Write the list into the monitor yourself after editing it.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorSuggestRequest"},"example":{"name":"Acme Audio","aliases":["Acme"],"domains":["example.com"],"competitors":[{"name":"Sony"}],"country":"US"}}}},"responses":{"200":{"description":"Candidate prompts, up to 12.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorSuggestResponse"}}}},"400":{"description":"No brand name or alias was supplied, or the suggestion service declined to write prompts for this brand.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"description":"One suggestion per owner per 20 seconds, 30 per hour.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"RATE_LIMITED","message":"One suggestion at a time — wait a few seconds","timestamp":"2026-09-22T04:12:00.000Z"}}}}},"502":{"description":"The suggestion service failed or returned nothing usable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Prompt suggestions are not configured on this deployment.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/monitors/research":{"post":{"summary":"Research prompts for a monitor","operationId":"researchMonitorPrompts","tags":["Monitors"],"description":"Queues the same task as POST /v1/prompt-research for your account: a topic in, the questions people ask AI assistants about it out, ranked by the search demand behind each one, with the set a monitor should track in monitorSet and the brands people search for in brands. The body, validation, price (11 credits per completed task) and result are identical; KR and US are the supported markets. When you create a category monitor, use each monitorSet prompt's topic as its sub-field in promptTopics and brands[].brand as competitors. Nothing is written to any monitor. Read the queued task with GET /v1/async/task/{id}, where the id is data.task.id.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromptResearchRequest"},"example":{"seed":"sunscreen","country":"US","monitorSize":10,"monitorEngines":["CHATGPT","GEMINI"]}}}},"responses":{"200":{"description":"Queued. Poll /v1/async/task/{id}; its response follows PromptResearchResult.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorResearchResponse"},"example":{"success":true,"data":{"task":{"id":"4299622a-1321-43a9-b780-809a0116f1b5","taskType":"PROMPT_RESEARCH","status":"QUEUED","priority":1,"createdAt":"2026-09-30T04:03:26.092Z"},"credits":{"creditsToCharge":11,"creditsCharged":0},"replayed":false}}}}},"400":{"description":"The body is not valid JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Not enough credits.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The API key is not allowed to use PROMPT_RESEARCH.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"VALIDATION_ERROR for a field out of range, or REGION_UNSUPPORTED when country is not KR or US.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Request rejected; retry after Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/monitors/{id}":{"get":{"summary":"Get monitor (legacy detail)","operationId":"getMonitor","tags":["Monitors"],"description":"The original period detail: the same payload the dashboard overview renders. It mixes a chosen window (stats, previous, engineRates, series, shareOfVoice, voiceSeries) with all-time cells (the latest scored answer per prompt and engine, with no window or engine filter), reports health only for tasks still visible (roughly the last 24 hours) and caps citations at 12 domains and 20 pages with no cursor. Prefer GET /v1/monitors/{id}/analytics for a report: it applies one cohort and one filter set to every section and paginates sources through GET /v1/monitors/{id}/sources.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Monitor id from GET /v1/monitors."},{"name":"days","in":"query","required":false,"schema":{"type":"integer","enum":[7,30,90],"default":30},"description":"Window length ending now. Only these three values are accepted."}],"responses":{"200":{"description":"Monitor, window aggregates, all-time latest cells and recent task health.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorDetailResponse"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"summary":"Update a monitor","operationId":"updateMonitor","tags":["Monitors"],"description":"Update any subset of the definition, or set enabled to pause and resume. Changing intervalHours or re-enabling restarts the clock from now, so a monitor paused for a month does not fire the instant it comes back; the edited run size is re-checked against the account's limit and the engines' drain on every update, and engineSettings is re-checked against the engines and interval the monitor ends with. Changing alertBelowPct re-arms the alert latch. mode is fixed at creation: the same value is accepted and a different one is a 400. On a category monitor, promptTopics follows prompts: removing a prompt removes its sub-field entry.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMonitorRequest"}}}},"responses":{"200":{"description":"Updated monitor.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorResponse"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/KeyScopeDenied"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"summary":"Delete a monitor","operationId":"deleteMonitor","tags":["Monitors"],"description":"Remove the monitor and its scored history (MonitorResult cascades). Deleting does not refund credits, and its queued tasks are not cancelled.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorDeleteResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/monitors/{id}/run":{"post":{"summary":"Run a monitor now","operationId":"runMonitor","tags":["Monitors"],"description":"Bring the next run forward to now; the ordinary sweep picks it up within a minute. It spends credits exactly like a scheduled run (prompts x points x samples tasks for each engine the run includes), so it is not a free preview. A second call while that window is still due is absorbed rather than charged twice, which makes retrying the call safe. Only an enabled monitor can run.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The run is due; tasks appear as the sweep admits them.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorRunResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/KeyScopeDenied"},"404":{"description":"No enabled monitor with that id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/monitors/{id}/analytics":{"get":{"summary":"Get monitor analytics","operationId":"getMonitorAnalytics","tags":["Monitors"],"description":"The report contract. One cohort and one filter set drive every section, and the previous interval has exactly the same duration and filters, so the comparison is like for like. The window is half-open in UTC: since is inclusive, until exclusive. Rates are null when there is no sample rather than 0, changes are withheld (null) when the scoring definition was legacy or changed between the periods, and a completed observation with no answer counts as not mentioned while a failed task is excluded from the denominator and reported only in health. Share of voice divides by all tracked brand mentions, not by answers, so the shares of one window add up to 100 and are not market share. A category monitor answers with the category report: stats and previous hold runs, named and namedRate, changes holds namedRatePp, and category holds the brand ranking, the sub-fields, the engines, the daily series and the prompts (see MonitorCategoryAnalytics).","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","enum":[7,30,90],"default":30},"description":"Window length ending now. Cannot be combined with since/until."},{"name":"since","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Inclusive ISO instant with a timezone offset, for example 2026-09-15T00:00:00Z. Requires until. A date without a timezone is rejected: it cannot define a portable window."},{"name":"until","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Exclusive ISO instant with a timezone offset. Requires since. The span must be positive, at most 90 days, and not in the future."},{"name":"engine","in":"query","required":false,"schema":{"type":"string"},"description":"Restrict every section to one engine. Accepts a canonical id or a public alias (GOOGLE_AIO and GOOGLE_AIMODE). Must be an engine a monitor can schedule."},{"name":"prompt","in":"query","required":false,"schema":{"type":"string","maxLength":2000},"description":"Restrict every section to one exact prompt. Rows are keyed by the prompt text, so a prompt removed by a later edit stays queryable."}],"responses":{"200":{"description":"Report for the window and the equal interval immediately before it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorAnalyticsResponse"}}}},"400":{"description":"Invalid window or filter, or a report too large to aggregate (narrow the window, engine or prompt).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"The window must be positive and at most 90 days","timestamp":"2026-09-22T04:12:00.000Z"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/monitors/{id}/sources":{"get":{"summary":"List cited sources","operationId":"listMonitorSources","tags":["Monitors"],"description":"Which domains or pages the engines cited inside the same window and filters as the report, counted in distinct answers rather than raw citations, so a page cited three times in one answer counts once. Ranks by answer count with an opaque keyset cursor: pass nextCursor back unchanged until it is null. This endpoint has no silent top-N cut - every combination is reachable, unlike the 12 domains and 20 pages the legacy detail returns.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"groupBy","in":"query","required":false,"schema":{"type":"string","enum":["domain","page"],"default":"domain"},"description":"domain groups by host (www stripped); page keeps the full URL and its label."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"Opaque keyset cursor. Pass the previous response's nextCursor unchanged; do not construct or decode it."},{"name":"days","in":"query","required":false,"schema":{"type":"integer","enum":[7,30,90],"default":30},"description":"Window length ending now. Cannot be combined with since/until."},{"name":"since","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Inclusive ISO instant with a timezone offset. Requires until."},{"name":"until","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Exclusive ISO instant with a timezone offset. Requires since."},{"name":"engine","in":"query","required":false,"schema":{"type":"string"},"description":"Same filter as the report."},{"name":"prompt","in":"query","required":false,"schema":{"type":"string","maxLength":2000},"description":"Same exact-prompt filter as the report."}],"responses":{"200":{"description":"One page of ranked sources.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorSourcesResponse"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/monitors/{id}/citations":{"get":{"summary":"Citations over time","operationId":"getMonitorCitations","tags":["Monitors"],"description":"The data behind the dashboard's citation charts: daily citation totals for the window and a daily series for each of the top 20 domains and pages. A citation is one page appearing in one answer (URLs normalized, duplicates within an answer removed), unlike /sources, which counts distinct answers. kind, q and offset only narrow the domains and pages lists; totals, days and types always cover every source in the window, so a source's share is its citations divided by totals.citations. Reads stored results only and spends no credits.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","enum":[7,30,90],"default":30},"description":"Window length ending now. When since and until are set, the fixed window wins and days is only echoed as windowDays."},{"name":"since","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Inclusive ISO instant with a timezone offset. Requires until."},{"name":"until","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Exclusive ISO instant with a timezone offset. Requires since."},{"name":"engine","in":"query","required":false,"schema":{"type":"string"},"description":"Same filter as the report."},{"name":"prompt","in":"query","required":false,"schema":{"type":"string","maxLength":2000},"description":"Same exact-prompt filter as the report."},{"name":"kind","in":"query","required":false,"schema":{"type":"string","enum":["all","owned","editorial","review_media","pr_wire","institution","reviews","commerce","social","blog","community","video","brand","content","other"],"default":"all"},"description":"Narrows the domains and pages lists to one source type."},{"name":"q","in":"query","required":false,"schema":{"type":"string","maxLength":200},"description":"Substring filter: domain name in the domains list, URL in the pages list."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":10000,"default":0},"description":"Skips this many rows in each list. Each list returns 20 rows."}],"responses":{"200":{"description":"Citation totals, daily series and ranked sources.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorCitationsResponse"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/monitors/{id}/results":{"get":{"summary":"Export scored answers","operationId":"listMonitorResults","tags":["Monitors"],"description":"The scored rows themselves, newest first, for a warehouse load or a spreadsheet. since and until are half-open and both accept a bare YYYY-MM-DD (read as 00:00:00Z) for compatibility with the original export; every filter is applied server-side. Pagination is a keyset cursor over (ranAt, id) with microsecond precision, so equal timestamps cannot drop or repeat a row: keep the cursor's first response's since and until fixed and follow nextCursor until it is null. includeEvidence adds the retained answer text, the citations and the scoring context, and lowers the page size bound because a page of evidence is far heavier than a page of scores.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"since","in":"query","required":false,"schema":{"type":"string"},"description":"ISO instant or legacy YYYY-MM-DD (00:00:00Z). Default: 30 days ago. Inclusive."},{"name":"until","in":"query","required":false,"schema":{"type":"string"},"description":"ISO instant or legacy YYYY-MM-DD (00:00:00Z). Default: now. Exclusive; must be after since."},{"name":"engine","in":"query","required":false,"schema":{"type":"string"}},{"name":"prompt","in":"query","required":false,"schema":{"type":"string","maxLength":2000},"description":"Exact prompt."},{"name":"mentioned","in":"query","required":false,"schema":{"type":"boolean"},"description":"true keeps answers naming the brand; false keeps only the misses (the competitive-gap rows)."},{"name":"cited","in":"query","required":false,"schema":{"type":"boolean"},"description":"true keeps answers citing a registered domain."},{"name":"competitor","in":"query","required":false,"schema":{"type":"string","maxLength":80},"description":"Keeps only answers whose stored competitorHits contain exactly this name (case-sensitive). It is matched against the stored hits, not checked against the monitor's current competitors, so a competitor removed since still filters its old answers and a misspelled name returns no rows rather than a 400."},{"name":"includeEvidence","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Add answerText, sources and scoringContext to every row, and lower the page-size bound to 100."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":10000,"default":10000},"description":"Default 10000 (max 10000) without evidence; default and maximum 100 when includeEvidence is true."},{"name":"format","in":"query","required":false,"schema":{"type":"string","enum":["json","csv"],"default":"json"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"The previous response's nextCursor (JSON) or x-next-cursor header (CSV), unchanged."}],"responses":{"200":{"description":"A page of scored rows, as JSON or CSV.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorResultsResponse"}},"text/csv":{"schema":{"type":"string"},"example":"ran_at,monitor,engine,prompt,mentioned,cited,position,competitors,task_id\n2026-09-22T03:00:00.123456Z,Earbud brand tracking,CHATGPT,best wireless earbuds for commuting,true,false,412,Sony,0f4b6f1c-4c1e-4a4c-9d5a-2f0a5b0b1a2c"}},"headers":{"X-Next-Cursor":{"schema":{"type":"string"},"description":"CSV only: the cursor for the next page, empty when the page is the last and nothing was truncated."},"X-Result-Truncated":{"schema":{"type":"string","enum":["true","false"]},"description":"CSV only: whether more rows match than this page returned."},"X-Result-Since":{"schema":{"type":"string","format":"date-time"},"description":"CSV only: the resolved inclusive window start."},"X-Result-Until":{"schema":{"type":"string","format":"date-time"},"description":"CSV only: the resolved exclusive window end."}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/monitors/{id}/answers/{taskId}":{"get":{"summary":"Get one answer","operationId":"getMonitorAnswer","tags":["Monitors"],"description":"The retained evidence behind one scored cell: the answer as the engine gave it (markdown when available, capped at 8,000 characters with a trailing ellipsis when it was cut), the citations in the engine's order, the competitor names scored against it, and the aliases that were matched so the mention can be checked rather than trusted. display adds the original task's display fields (the full answer, sources, layout, places and products) while the task is still stored. Rows scored before scoring context was stored return scoringKnown false with the monitor's current aliases and a null evidenceTruncated, and answerText is null when the engine returned no answer text.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"taskId","in":"path","required":true,"schema":{"type":"string"},"description":"A taskId from cells[], results[].taskId, sources[].evidenceTaskId or the CSV."}],"responses":{"200":{"description":"The scored answer and the definition it was scored against.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorAnswerResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"No monitor with that id, or no scored answer with that task id on this monitor.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/monitors/{id}/prompt":{"get":{"summary":"Get one prompt","operationId":"getMonitorPrompt","tags":["Monitors"],"description":"Drill into a single prompt: its per-day per-engine series, its top domains and pages (12 and 20, uncursored), and up to 100 recent scored rows. The same queries as the monitor level with one more predicate, so the prompt view and the monitor view cannot disagree. A prompt removed by a later edit stays queryable.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"prompt","in":"query","required":true,"schema":{"type":"string","maxLength":2000}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","enum":[7,30,90],"default":30}}],"responses":{"200":{"description":"Series, sources and recent rows for one prompt.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorPromptResponse"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/monitors/{id}/alerts":{"get":{"summary":"Get alert history","operationId":"getMonitorAlerts","tags":["Monitors"],"description":"Whether a mention-rate alert is configured (alertBelowPct, null when off), whether its latch is armed, and the last 20 deliveries with their status, attempts and last error. An alert fires on the crossing, not on the state: it re-arms only after the rate recovers, so one dip sends one email.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Alert configuration and delivery history.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorAlertsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/monitors/{id}/alerts/test":{"post":{"summary":"Send a test alert","operationId":"testMonitorAlert","tags":["Monitors"],"description":"Queue a test email through the same delivery path the real alert uses, so what is tested is the path rather than the template. Rate limited to three per monitor per five minutes. A category monitor has no alert, so this returns 400 for it.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Test email queued.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorRunResponse"}}}},"400":{"description":"The monitor is a category monitor, which has no alert.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"description":"Three test emails in five minutes is the limit for this monitor.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/prompt-research":{"post":{"summary":"Research prompts by search demand","operationId":"createPromptResearch","tags":["Research"],"description":"Queues a task that turns a topic into the questions people ask AI assistants about it, ranked by the monthly search demand behind each one, and picks the set a GEO monitor should track (monitorSet), with the demand for competitor brands kept separately. South Korea (KR) and the United States (US). 11 credits per completed task; a failed task releases its hold. The task usually completes in 30-60 seconds; poll /v1/async/task/{id} or use a webhook. A task fails with NO_SEARCH_DEMAND when no search demand is found for the seed or anything related to it, and with NO_RELATED_SEARCHES when only the seed itself is searched.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromptResearchRequest"},"examples":{"seed":{"summary":"A seed topic","value":{"seed":"sunscreen","country":"US","limit":20,"brand":"MyBrand"}},"described":{"summary":"With your brand described","value":{"seed":"sunscreen","country":"US","monitorSize":12,"monitorEngines":["CHATGPT","PERPLEXITY"],"brand":"MyBrand","brandAliases":["My Brand"],"brandDescription":"Gentle mineral sunscreens for sensitive and dry skin"}}}}}},"responses":{"200":{"description":"Queued; poll /v1/async/task/{id}. Its response follows PromptResearchResult.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AsyncResponse"},"examples":{"queued":{"summary":"Queued prompt research","value":{"success":true,"task":{"id":"4299622a-1321-43a9-b780-809a0116f1b5","taskType":"PROMPT_RESEARCH","status":"QUEUED","priority":1,"createdAt":"2026-09-28T13:03:26.092Z"},"credits":{"creditsToCharge":0,"creditsCharged":0}}}}}}},"400":{"description":"Request rejected: the body is not valid JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Request rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Not enough credits.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The API key is not allowed to use PROMPT_RESEARCH.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"A task with this idempotencyKey already exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"Request rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"VALIDATION_ERROR for a field out of range or for brandAliases or brandDescription without brand, or REGION_UNSUPPORTED when country is not KR or US.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Request rejected; retry after Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Request rejected; retry after Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/geo-score":{"post":{"summary":"Score how much of a page ChatGPT search keeps","operationId":"createGeoScore","tags":["Research"],"description":"Queues a task that scores one page on how much of what a person reads on it ChatGPT search keeps, beside how much ChatGPT receives when it opens the page itself, and names what keeps the rest out: robots.txt, refused requests, content loaded after the page opens, text inside images. The reference is the page rendered in a browser in country, with the text in its images. 10 credits a page, 5 for each image whose text is read (images.read) and 2 for each image the account read in the last 90 days (images.reused), at most 12 images: submitting holds 70 credits and completion charges what the task used; a failed task releases its hold. Most tasks complete in 2-5 minutes; poll /v1/async/task/{id} or use a webhook. A page no browser can show, as a person or as ChatGPT search's crawler, fails with PAGE_UNAVAILABLE, and a task whose questions ChatGPT answered none of fails with CHATGPT_UNAVAILABLE.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeoScoreRequest"},"examples":{"product":{"summary":"A product page read from the US","value":{"url":"https://www.allbirds.com/products/mens-tree-runners","country":"US"}},"korea":{"summary":"A Korean page read from KR, with a webhook","value":{"url":"https://www.musinsa.com/products/6247370","country":"KR","idempotencyKey":"musinsa-6247370","webhook":{"url":"https://example.com/hooks/geo-score"}}}}}}},"responses":{"200":{"description":"Queued; poll /v1/async/task/{id}. Its response follows GeoScoreResult.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AsyncResponse"},"examples":{"queued":{"summary":"Queued GEO Score","value":{"success":true,"task":{"id":"0b6c1f7e-2d4a-4c55-9a0e-3f1d2b7c8e91","taskType":"GEO_SCORE","status":"QUEUED","priority":1,"createdAt":"2026-10-21T09:00:00.000Z"},"credits":{"creditsToCharge":0,"creditsCharged":0}}}}}}},"400":{"description":"VALIDATION_ERROR: the body is not a JSON object, has a field other than url, country, idempotencyKey, priority and webhook, or one of the last three has the wrong type.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Request rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Not enough credits.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The API key is not allowed to use GEO_SCORE.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"A task with this idempotencyKey already exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"Request rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"VALIDATION_ERROR for a url that is missing, not http or https, or on a private host or port, or REGION_UNSUPPORTED when country is not US or KR.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Request rejected; retry after Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Request rejected; retry after Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/product-lookup":{"post":{"summary":"Look up a product on AI shopping engines","operationId":"createProductLookup","tags":["Research"],"description":"Asks the AI shopping engines of one market (US or KR) about a product by name, and about up to 5 competitors and 3 shopper prompts you name. Each ask is an ordinary task, so polling, webhooks, credits and plan concurrency are those of single tasks. A product's asks have the key `<id>:<engine>:<ask>`, a competitor's add `:c<n>`, and a prompt's are `<id>:<engine>:p<n>`. Read the lookup with GET /v1/product-lookup/{id}.\n\nAsks are admitted one at a time: every engine's first ask about each product, and each prompt, before any second ask. A refused ask stays in asks[] with success false. When none of the product's first asks is admitted, nothing else is asked and the first refusal is the response. Sending the lookup again under the same idempotencyKey returns the asks that exist and admits only the missing ones.\n\nA lookup costs 10 credits per product (the product and each competitor) and 5 credits per shopper prompt, whichever engines are asked. Each ask carries its share of its product's or prompt's credits, and an ask that fails is not charged.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductLookupRequest"},"examples":{"lookup":{"summary":"A product with competitors and shopper prompts","value":{"product":"belif Moisturizing Eye Bomb","country":"US","competitors":["Clinique All About Eyes","CeraVe Eye Repair Cream"],"prompts":["best eye cream for puffiness","best moisturizing eye cream"],"idempotencyKey":"eye-bomb-us"}}}}}},"responses":{"200":{"description":"Asks processed. Each entry of asks[] holds its task, or the error that refused it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductLookupCreateResponse"},"example":{"success":true,"lookup":{"id":"eye-bomb-us","product":"belif Moisturizing Eye Bomb","competitors":["Clinique All About Eyes","CeraVe Eye Repair Cream"],"prompts":["best eye cream for puffiness","best moisturizing eye cream"],"country":"US","engines":["CHATGPT","GOOGLE","AIMODE","BING_COPILOT"]},"summary":{"total":23,"succeeded":23,"failed":0},"credits":{"creditsToCharge":40,"creditsCharged":0},"asks":[{"engine":"CHATGPT","taskType":"CHATGPT","role":"product","prompt":"Buy belif Moisturizing Eye Bomb","success":true,"task":{"id":"56be57f3-d316-4727-8bd3-ab065fed2ec1","taskType":"CHATGPT","status":"QUEUED","priority":1,"createdAt":"2026-10-20T09:22:43.422Z","idempotencyKey":"eye-bomb-us:CHATGPT:buy"}},{"engine":"CHATGPT","taskType":"CHATGPT","role":"competitor","prompt":"Buy Clinique All About Eyes","success":true,"task":{"id":"35f300a4-7603-4ad0-97ba-82eb6a07eed9","taskType":"CHATGPT","status":"QUEUED","priority":1,"createdAt":"2026-10-20T09:22:43.637Z","idempotencyKey":"eye-bomb-us:CHATGPT:buy:c1"}},{"engine":"AIMODE","taskType":"AIMODE","role":"prompt","query":"best eye cream for puffiness","success":true,"task":{"id":"bff41168-d081-4bce-a873-9609baafbaa5","taskType":"AIMODE","status":"QUEUED","priority":1,"createdAt":"2026-10-20T09:22:44.149Z","idempotencyKey":"eye-bomb-us:AIMODE:p1"}}]}}}},"400":{"description":"VALIDATION_ERROR: the body is not valid JSON; product or a competitor is missing, a product page URL or a GTIN; there are more than 5 competitors or 3 prompts, or a duplicate; an engine is unknown or does not answer in the market; or idempotencyKey is not 1-200 characters without leading or trailing spaces. details names the field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed","details":[{"field":"product","message":"product takes a product's name; a GTIN or barcode is not supported"}],"timestamp":"2026-10-20T09:22:43.000Z"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"INSUFFICIENT_CREDITS: none of the product's first asks could be held, so nothing was asked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"The API key may not use the engines of the product's first asks, so nothing was asked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"RESOURCE_ALREADY_EXISTS: the idempotencyKey names a lookup of another product or country, or one that holds a different competitor or prompt in the same position. Nothing was written.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"RESOURCE_ALREADY_EXISTS","message":"lookup 'eye-bomb-us' was created for another product, competitor, prompt or country; send this lookup under a new idempotencyKey","timestamp":"2026-10-20T09:22:43.000Z"}}}}},"413":{"description":"PAYLOAD_TOO_LARGE: the body is over 1 MiB.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"REGION_UNSUPPORTED: country is not US or KR.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"REGION_UNSUPPORTED","message":"Product lookups ask the engines of US and KR only; country='JP' is not one.","details":{"country":"JP","supportedCountries":["US","KR"],"retryable":false},"timestamp":"2026-10-20T09:22:43.000Z"}}}}},"429":{"description":"None of the product's first asks was admitted, for example PLAN_CONCURRENCY_LIMIT or KEY_DAILY_CREDIT_LIMIT. Retry after Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"None of the product's first asks was admitted because the service is busy. Retry after Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/product-lookup/{id}":{"get":{"summary":"Get a product lookup","operationId":"getProductLookup","tags":["Research"],"description":"Reads a lookup back from its asks' tasks: for the product and each competitor, whether each engine's answers showed it, the merchant listings they showed and the pages they cite; the products side by side engine by engine; and what each engine answered each shopper prompt. Entries fill in as asks finish. Readable while the asks' tasks are, until 24 hours after they complete.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":200},"description":"The lookup's id: the idempotencyKey you sent, or lookup.id from the POST response."}],"responses":{"200":{"description":"The lookup, read from its asks so far.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductLookupResponse"},"example":{"success":true,"lookup":{"id":"eye-bomb-us","product":"belif Moisturizing Eye Bomb","competitors":["Clinique All About Eyes","CeraVe Eye Repair Cream"],"prompts":["best eye cream for puffiness","best moisturizing eye cream"],"country":"US","status":"COMPLETED","createdAt":"2026-10-20T09:22:43.422Z","completedAt":"2026-10-20T09:24:36.695Z","credits":40},"summary":{"foundIn":["CHATGPT","GOOGLE","AIMODE","BING_COPILOT"],"notFoundIn":[],"pending":[],"failed":[],"merchants":[{"merchant":"Ulta Beauty","engines":["CHATGPT","BING_COPILOT"],"price":{"currency":"USD","min":48,"max":48}},{"merchant":"Amazon","engines":["CHATGPT"],"price":{"currency":"USD","min":43,"max":43}},{"merchant":"Comparor","engines":["BING_COPILOT"],"price":{"currency":"USD","min":35.82,"max":45.9}}],"priceRange":{"currency":"USD","min":35.82,"max":48},"citedDomains":[{"domain":"ulta.com","engines":["CHATGPT","GOOGLE","AIMODE","BING_COPILOT"]},{"domain":"lgbeauty.com","engines":["CHATGPT","GOOGLE","AIMODE"]}],"credits":10},"engines":[{"engine":"CHATGPT","status":"COMPLETED","found":true,"via":[{"taskType":"CHATGPT","prompt":"Buy belif Moisturizing Eye Bomb","taskId":"56be57f3-d316-4727-8bd3-ab065fed2ec1","status":"COMPLETED","completedAt":"2026-10-20T09:23:04.711Z","credits":2},{"taskType":"CHATGPT","prompt":"Find the best price for belif Moisturizing Eye Bomb","taskId":"c60ffa61-d399-4b15-8343-452dcc150fd3","status":"COMPLETED","completedAt":"2026-10-20T09:23:20.863Z","credits":2}],"listings":[{"position":1,"title":"belif Moisturizing Eye Bomb Eye Cream","source":"merchant_feed","merchant":"Ulta Beauty","url":"https://www.ulta.com/p/moisturizing-eye-bomb-eye-cream-pimprod2043262?cmpid…","price":{"value":48,"currency":"USD","raw":"$48.00"},"available":true,"brand":"belif","modelSees":{"title":"belif Moisturizing Eye Bomb Eye Cream","description":"belif's Moisturizing Eye Bomb Eye Cream is a lightweight cream that floods the eye area wi…","rating":4.5,"reviewCount":105,"brand":"belif"},"ids":{"chatgptProductId":"2619879","feedId":"oai-shopping-id:v1:feed:…"},"ask":1,"match":{"score":1}},{"position":1,"title":"Amazon","source":"chatgpt_widget","merchant":"Amazon","url":"https://www.amazon.com/s?k=belif+Moisturizing+Eye+Bomb","price":{"value":43,"currency":"USD","raw":"$43.00"},"description":"Reported sale price · $5 below retail · A recent October 2026 deal report lists this price.","pictured":"belif Moisturizing Eye Bomb 25ml blue jar white lid","ask":2,"match":{"score":1}}],"otherListings":[],"citedPages":[{"url":"https://lgbeauty.com/products/moisturizing-eye-bomb?selectedVariant=47584416432448","domain":"lgbeauty.com","title":"Moisturizing Eye Bomb","ask":1}]}],"competitors":[{"product":"Clinique All About Eyes","summary":{"foundIn":["CHATGPT","GOOGLE","AIMODE","BING_COPILOT"],"notFoundIn":[],"pending":[],"failed":[],"merchants":[{"merchant":"Ulta Beauty","engines":["CHATGPT","AIMODE","BING_COPILOT"],"price":{"currency":"USD","min":39,"max":66}}],"priceRange":{"currency":"USD","min":38.05,"max":72},"citedDomains":[{"domain":"clinique.com","engines":["GOOGLE","AIMODE"]}],"credits":10},"engines":[{"engine":"BING_COPILOT","status":"COMPLETED","found":true,"via":[{"taskType":"BING_COPILOT","prompt":"Clinique All About Eyes","taskId":"5a2119a5-69f4-49db-89e2-a7822b6d99d9","status":"COMPLETED","completedAt":"2026-10-20T09:23:39.682Z","credits":2}],"listings":[{"position":1,"title":"Clinique All About Eyes Cream","source":"microsoft_shopping","merchant":"Walmart","url":"https://www.walmart.com/ip/Clinique-All-About-Eyes-1-oz-Eye…","price":{"value":54,"currency":"USD","raw":"$54"},"rating":4.58,"reviewCount":76542,"brand":"Olabens","ask":1,"match":{"score":1}}],"otherListings":[],"citedPages":[]}]},{"product":"CeraVe Eye Repair Cream","summary":{"foundIn":["CHATGPT","GOOGLE","AIMODE","BING_COPILOT"],"notFoundIn":[],"pending":[],"failed":[],"merchants":[{"merchant":"Ulta Beauty","engines":["CHATGPT"],"price":{"currency":"USD","min":14.99,"max":19.99}}],"priceRange":{"currency":"USD","min":14.44,"max":38.95},"citedDomains":[{"domain":"cerave.com","engines":["GOOGLE"]}],"credits":10},"engines":[{"engine":"BING_COPILOT","status":"COMPLETED","found":true,"via":[{"taskType":"BING_COPILOT","prompt":"CeraVe Eye Repair Cream","taskId":"c6568949-6bf5-44a4-a7dd-38db0a86be71","status":"COMPLETED","completedAt":"2026-10-20T09:23:41.368Z","credits":2}],"listings":[{"position":1,"title":"CeraVe Eye Repair Cream for Dark Circles and Puffiness","source":"microsoft_shopping","merchant":"Pasteur Pharmacy","url":"https://pasteurpharmacy.com/products/cerave-anti-aging-eye-r…","price":{"value":15.95,"currency":"USD","raw":"$15.95"},"rating":4.35,"reviewCount":117193,"brand":"CeraVe","ask":1,"match":{"score":1}}],"otherListings":[],"citedPages":[{"url":"https://ctchealth.ca/product/cerave-eye-repair-cream-with-hyaluronic-acid-3-ceramides/?utm_source=copilot.com","domain":"ctchealth.ca","title":"CeraVe Eye Repair Cream for Dark Circles and Puffiness","ask":1}]}]}],"comparison":[{"product":"belif Moisturizing Eye Bomb","role":"product","engines":[{"engine":"CHATGPT","status":"COMPLETED","found":true,"listings":4,"merchants":4,"mostReviewed":{"reviewCount":105,"rating":4.5,"merchant":"Ulta Beauty"},"priceRange":{"currency":"USD","min":43,"max":48},"prompts":{"answered":2,"appeared":0}},{"engine":"BING_COPILOT","status":"COMPLETED","found":true,"listings":6,"merchants":5,"mostReviewed":{"reviewCount":2942,"rating":4.58,"merchant":"Comparor"},"priceRange":{"currency":"USD","min":35.82,"max":48},"prompts":{"answered":2,"appeared":1}}]},{"product":"Clinique All About Eyes","role":"competitor","engines":[{"engine":"BING_COPILOT","status":"COMPLETED","found":true,"listings":4,"merchants":3,"mostReviewed":{"reviewCount":85773,"rating":4.6,"merchant":"Walmart"},"priceRange":{"currency":"USD","min":38.05,"max":72},"prompts":{"answered":2,"appeared":0}}]},{"product":"CeraVe Eye Repair Cream","role":"competitor","engines":[{"engine":"BING_COPILOT","status":"COMPLETED","found":true,"listings":6,"merchants":6,"mostReviewed":{"reviewCount":117193,"rating":4.35,"merchant":"Pasteur Pharmacy"},"priceRange":{"currency":"USD","min":15.95,"max":38.95},"prompts":{"answered":2,"appeared":0}}]}],"prompts":[{"prompt":"best moisturizing eye cream","engines":[{"engine":"GOOGLE","status":"COMPLETED","via":[{"taskType":"GOOGLE","query":"best moisturizing eye cream","taskId":"ae6a153a-6382-40d6-84df-c99de0b60d17","status":"COMPLETED","completedAt":"2026-10-20T09:24:29.231Z","credits":1.25}],"shown":["CeraVe Eye Repair Cream","Clinique All About Eyes"],"named":["belif Moisturizing Eye Bomb","CeraVe Eye Repair Cream","Clinique All About Eyes"],"listings":[{"position":1,"title":"CeraVe Eye Repair Cream","source":"google_shopping","product":"CeraVe Eye Repair Cream","match":{"score":1}},{"position":3,"title":"Clinique All About Eyes Rich","source":"google_shopping","product":"Clinique All About Eyes","match":{"score":1}}],"citedPages":[{"url":"https://www.nytimes.com/wirecutter/reviews/best-eye-cream/","domain":"nytimes.com","title":"The New York Times"}]},{"engine":"BING_COPILOT","status":"COMPLETED","via":[{"taskType":"BING_COPILOT","prompt":"best moisturizing eye cream","taskId":"0f582e93-7756-439d-8e5c-bacc510fdff0","status":"COMPLETED","completedAt":"2026-10-20T09:23:45.384Z","credits":1.25}],"shown":["belif Moisturizing Eye Bomb"],"named":["belif Moisturizing Eye Bomb"],"listings":[{"position":1,"title":"belif Moisturizing Eye Bomb with Peptide and Ceramide","source":"microsoft_shopping","merchant":"Comparor","url":"https://www.comparor.com/us/belif-moisturizing-eye-bomb-hydr…","price":{"value":45.9,"currency":"USD","raw":"$45.9"},"rating":4.58,"reviewCount":2942,"product":"belif Moisturizing Eye Bomb","match":{"score":1}}],"citedPages":[{"url":"https://www.comparor.com/us/belif-moisturizing-eye-bomb-hydrating-eye-cream-25ml.html?utm_source=copilot.com","domain":"comparor.com","title":"belif Moisturizing Eye Bomb with Peptide and Ceramide"}]}]}]}}}},"400":{"description":"VALIDATION_ERROR: the id is not 1-200 characters without leading or trailing spaces.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"RESOURCE_NOT_FOUND: no lookup with this id on your account, including one whose tasks are past the read window.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"RESOURCE_NOT_FOUND","message":"Product lookup not found","details":{"id":"eye-bomb-us"},"timestamp":"2026-10-20T09:22:43.000Z"}}}}}}}},"/v1/place-lookup":{"post":{"summary":"Create a place lookup","operationId":"createPlaceLookup","tags":["Research"],"description":"Ask AI engines about one store. Each engine gets two questions, and each question is an ordinary task of that engine under the key {lookup id}:{engine}:{ask}, so holds, plan concurrency and the 24-hour window are those of single tasks. Engines: CHATGPT, GEMINI, GOOGLE, BING_COPILOT, and NAVER_AI_TAB in KR. Read the lookup with GET /v1/place-lookup/{id}; a lookup sends no webhook.\n\nA lookup of the country's default engines costs 10 credits: 1 credit for each of the 10 questions in KR and 1.25 for each of the 8 elsewhere. A lookup that names fewer engines pays for the questions it sends, and a failed question costs 0.\n\nA question the account's plan or the engine's queue has no room for yet waits: it answers status PENDING without a task and starts on its own as room frees up, within a minute or on the next GET, so one request runs the whole lookup. A waiting question's price is held when it starts; if the key that sent the lookup is revoked or expires first, the question ends as FAILED with API_KEY_INACTIVE and costs 0. A question refused for good (balance, key scope) is reported in tasks[] with success false. When every question is refused, the first refusal is the response and nothing is created. The same request under the same idempotencyKey returns the existing tasks and sends the questions that have no task yet; the same id with another store, country or engine list returns 409.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaceLookupRequest"},"example":{"place":{"name":"Canlis","address":"2576 Aurora Ave N, Seattle, WA 98109","location":{"latitude":47.6430534,"longitude":-122.3467361},"phone":"(206) 283-3313","website":"https://canlis.com/"},"country":"US","idempotencyKey":"canlis-2026-10"}}}},"responses":{"200":{"description":"Lookup created, or resent under its id. Each question's outcome is in tasks[]: its task, status PENDING while it waits for room, or its error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaceLookupSubmitResult"},"example":{"success":true,"lookup":{"id":"canlis-2026-10"},"tasks":[{"engine":"CHATGPT","ask":1,"success":true,"task":{"id":"9d02deef-4c1c-47db-8d86-e1a71f8b00e8","taskType":"CHATGPT","status":"QUEUED","priority":1,"createdAt":"2026-10-20T09:00:00.000Z","idempotencyKey":"canlis-2026-10:CHATGPT:1"}},{"engine":"CHATGPT","ask":2,"success":true,"task":{"id":"91505c8f-d2d6-4bd3-8623-a8706249f1e1","taskType":"CHATGPT","status":"QUEUED","priority":1,"createdAt":"2026-10-20T09:00:00.000Z","idempotencyKey":"canlis-2026-10:CHATGPT:2"}}]}}}},"400":{"description":"Request rejected: the body is not valid JSON, a field is missing or invalid, an unknown field or webhook was sent, or NAVER_AI_TAB was asked outside KR. details names the field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Every question was refused: not enough credits. Nothing was created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Every question was refused: the API key is not allowed to use the engines (KEY_SCOPE_DENIED). Nothing was created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The idempotencyKey names a lookup of another store, country or engine list. Nothing was created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"Request rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Every question was refused: the engines do not serve the country (REGION_UNSUPPORTED). Nothing was created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Every question was refused by a sub-account's credit limit (SUB_ACCOUNT_CREDIT_LIMIT); retry after Retry-After. Nothing was created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Task storage is temporarily unavailable; retry after Retry-After. Nothing was created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/place-lookup/{id}":{"get":{"summary":"Get a place lookup","operationId":"getPlaceLookup","tags":["Research"],"description":"Each engine's record of the store, judged from the stored answers on every read: whether the answers showed the store (found), the record's map database (source), what the record says, what is wrong with it (issues), and where the engines' records disagree (summary.differences). Readable for 24 hours after the lookup's tasks complete.","parameters":[{"name":"id","in":"path","required":true,"description":"The lookup id: your idempotencyKey, or the UUID the server minted.","schema":{"type":"string"}}],"responses":{"200":{"description":"The lookup, judged per engine.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaceLookupResult"},"example":{"success":true,"lookup":{"id":"canlis-2026-10","status":"COMPLETED","place":{"name":"Canlis","address":"2576 Aurora Ave N, Seattle, WA 98109","location":{"latitude":47.6430534,"longitude":-122.3467361},"phone":"(206) 283-3313","website":"https://canlis.com/"},"country":"US","engines":[{"engine":"CHATGPT","status":"COMPLETED","found":true,"via":[{"taskType":"CHATGPT","prompt":"Show Canlis on a map","taskId":"9d02deef-4c1c-47db-8d86-e1a71f8b00e8","status":"COMPLETED","collectedAt":"2026-10-19T16:38:48.957Z","places":1},{"taskType":"CHATGPT","prompt":"Show Canlis, 2576 Aurora Ave N, Seattle, WA 98109 on a map","taskId":"91505c8f-d2d6-4bd3-8623-a8706249f1e1","status":"COMPLETED","collectedAt":"2026-10-19T16:39:04.194Z","places":1}],"record":{"position":1,"name":"Canlis","source":"yelp","provider":"yelp-feed","url":"https://www.yelp.com/biz/canlis-seattle?adjust_creative=openai","address":"2576 Aurora Ave N, Seattle, WA 98109, United States","latitude":47.6430933,"longitude":-122.3467535,"phone":"+1 206-283-3313","category":"Pacific Northwest restaurant (US)","rating":4,"reviewCount":1935,"website":"https://canlis.com/","match":{"same":true,"by":["phone","website","location","address","name"],"nameScore":1,"distanceMeters":5}}},{"engine":"GEMINI","status":"COMPLETED","found":true,"via":[{"taskType":"GEMINI","prompt":"Show Canlis on a map","taskId":"f659899b-6dc8-487d-b33e-bdabd98ec562","status":"COMPLETED","collectedAt":"2026-10-19T16:38:48.831Z","places":1},{"taskType":"GEMINI","prompt":"Show Canlis, 2576 Aurora Ave N, Seattle, WA 98109 on a map","taskId":"f93bc0cc-070b-4ccc-a113-07581795105e","status":"COMPLETED","collectedAt":"2026-10-19T16:38:48.861Z","places":1}],"record":{"position":1,"name":"Canlis","source":"google_maps","placeId":"ChIJRXCfNwUVkFQRxraD8U-dANE","url":"https://maps.google.com/?cid=15060210120606856902","address":"2576 Aurora Ave N, Seattle, WA 98109","latitude":47.6430933,"longitude":-122.3467535,"phone":"+1 206-283-3313","category":"American restaurant","rating":4.6,"reviewCount":2892,"website":"https://canlis.com/","match":{"same":true,"by":["phone","website","location","address","name"],"nameScore":1,"distanceMeters":5}}},{"engine":"GOOGLE","status":"COMPLETED","found":false,"via":[{"taskType":"GOOGLE","query":"Canlis location","taskId":"6d3c3a73-8193-4b82-a17b-3d3441afef7d","status":"COMPLETED","collectedAt":"2026-10-19T16:38:43.932Z","places":0},{"taskType":"GOOGLE","query":"Canlis","location":{"latitude":47.6430534,"longitude":-122.3467361},"taskId":"980a858a-00d7-442c-b9be-b2ad75202b13","status":"COMPLETED","collectedAt":"2026-10-19T16:38:48.902Z","places":0}]},{"engine":"BING_COPILOT","status":"COMPLETED","found":true,"via":[{"taskType":"BING_COPILOT","prompt":"Show Canlis on a map","taskId":"a9166a27-205b-4eb0-b8ec-248c0b5d149c","status":"COMPLETED","collectedAt":"2026-10-19T16:38:53.967Z","places":1},{"taskType":"BING_COPILOT","prompt":"Show Canlis, 2576 Aurora Ave N, Seattle, WA 98109 on a map","taskId":"4f8afd8a-866d-4e17-8a29-acca4e53e056","status":"COMPLETED","collectedAt":"2026-10-19T16:38:53.983Z","places":1}],"record":{"position":1,"name":"Canlis","source":"google_maps","placeId":"ChIJRXCfNwUVkFQRxraD8U-dANE","url":"https://maps.google.com/?cid=15060210120606856902","address":"2576 Aurora Ave N, Seattle, WA 98109","latitude":47.6430933,"longitude":-122.3467535,"phone":"(206) 283-3313","category":"Pacific Northwest restaurant (US),American restaurant,Bar,Fine dining restaurant,New American restaurant,Restaurant","rating":4.6,"reviewCount":2892,"website":"https://canlis.com/","openState":"Closed · Opens 5 PM Tue","match":{"same":true,"by":["phone","website","location","address","name"],"nameScore":1,"distanceMeters":5}}}],"summary":{"foundIn":["CHATGPT","GEMINI","BING_COPILOT"],"notFoundIn":["GOOGLE"],"failed":[],"pending":[],"differences":[]},"credits":10}}}}},"400":{"description":"Request rejected: the lookup id is missing or longer than 200 characters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"No lookup with this id for your account, or its tasks are past the 24-hour window.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"RESOURCE_NOT_FOUND","message":"Place lookup not found","details":{"id":"canlis-2026-10"},"timestamp":"2026-10-20T09:00:00.000Z"}}}}}}}},"/v1/async/task/grid":{"post":{"summary":"Create a location grid","operationId":"createTaskGrid","tags":["Tasks"],"description":"Ask one prompt from every point of a square grid around a center. Each point is an ordinary task with that point as payload.location, so polling, webhooks, credits and plan concurrency are those of single tasks.\n\nThe center point is admitted first. A refusal that applies to every point (validation, an engine without location, key scope, region, balance, a full plan) is the whole grid's answer and creates nothing. The other points are admitted like a batch: a point refused for capacity is reported in place, and sending the same grid again under grid.id admits only the missing points.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GridRequest"},"example":{"taskType":"CHATGPT","payload":{"prompt":"dermatologist near me","country":"KR"},"grid":{"center":{"latitude":37.4979,"longitude":127.0276},"size":5,"radiusMeters":2000},"idempotencyKey":"gangnam-derm-2026-10-09"}}}},"responses":{"200":{"description":"Grid processed. Inspect points[] for per-point outcomes.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GridResult"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/async/task/grid/{id}":{"get":{"summary":"Get a location grid","operationId":"getTaskGrid","tags":["Tasks"],"description":"The grid's points in row and column order, each with its location, task and credits. include=response adds each finished task's response. Points the grid never admitted are absent.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"include","in":"query","required":false,"schema":{"type":"string","enum":["response"]}}],"responses":{"200":{"description":"The grid's points.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GridReadResult"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/monitors/{id}/grid":{"get":{"summary":"Get a monitor's answers by location","operationId":"getMonitorGrid","tags":["Monitors"],"description":"For a monitor with a location or grid: per point of its current place, the answers scored, how many mentioned and cited the brand, the competitor mentioned most, and the latest answer. A monitor without a place returns no points.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","enum":[7,30,90],"default":30}},{"name":"engine","in":"query","required":false,"schema":{"type":"string"}},{"name":"prompt","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Points with their counts."},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/capabilities":{"get":{"summary":"Engine capabilities","description":"Every self-serve taskType with its input fields, credit price, location support and country policy. Values come from the same code that validates submissions, so a request built from this response is accepted. No API key needed. Cached for 5 minutes.","operationId":"getCapabilities","tags":["Operations"],"security":[],"parameters":[{"name":"taskType","in":"query","required":false,"schema":{"type":"string"},"description":"Return one engine. Aliases such as GOOGLE_AIO are accepted."}],"responses":{"200":{"description":"Engines.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"engines":{"type":"array","items":{"type":"object","properties":{"taskType":{"type":"string","example":"PERPLEXITY"},"aliases":{"type":"array","items":{"type":"string"},"description":"Other ids the submit path folds into this taskType."},"endpoint":{"type":"string","example":"/v1/async/task","description":"Where to POST this taskType."},"credits":{"type":"number","example":1,"description":"Credits charged per completed task. CITATION_ANALYSIS reports its hold; the charge is metered up to it."},"input":{"type":"object","properties":{"required":{"type":"array","items":{"type":"string"}},"optional":{"type":"array","items":{"type":"string"}}}},"location":{"type":"boolean","description":"Accepts payload.location."},"countries":{"oneOf":[{"type":"object","properties":{"policy":{"type":"string","enum":["all_except"]},"unsupported":{"type":"array","items":{"type":"object","properties":{"country":{"type":"string","example":"CN"},"cause":{"type":"string","enum":["no_proxy_route","target_blocks_exit"]}}}}}},{"type":"object","properties":{"policy":{"type":"string","enum":["only"]},"supported":{"type":"array","items":{"type":"string"},"example":["KR","US"]}}}]},"example":{"type":"object","additionalProperties":true,"description":"A minimal payload that passes validation (the request body for dedicated endpoints)."}}}}}}}}}}},"400":{"description":"taskType is not a self-serve engine."}}}},"/v1/exports/{id}/runs/{runId}/retry":{"post":{"summary":"Send a window again","operationId":"retryExportRun","tags":["Exports"],"description":"Queues the window now with a fresh retry budget: a failed one after fixing the grant, or a delivered one to rewrite. Files keep their names and BigQuery replaces the partition.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"runId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Queued run.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExportRunResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"EXPORT_RUN_RUNNING: the window is being delivered now.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/exports/{id}/runs":{"get":{"summary":"List delivery history","operationId":"listExportRuns","tags":["Exports"],"description":"One run per window and data set, newest window first. Follow nextCursor until it is null.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["pending","running","delivered","failed"]}},{"name":"data","in":"query","required":false,"schema":{"type":"string","enum":["tasks","monitor_results"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Runs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExportRunListResponse"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/exports/{id}":{"get":{"summary":"Get an export","operationId":"getExport","tags":["Exports"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Export.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExportResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"summary":"Pause or resume an export","operationId":"updateExport","tags":["Exports"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"description":"Only enabled changes. Resuming delivers the windows missed while paused, up to 30 days back.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["enabled"],"properties":{"enabled":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Updated export.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExportResponse"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"summary":"Delete an export","operationId":"deleteExport","tags":["Exports"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"description":"Stops future deliveries. Files already delivered stay in your storage.","responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExportDeleteResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/exports":{"get":{"summary":"List exports","operationId":"listExports","tags":["Exports"],"description":"Every export of the account with its delivery health.","responses":{"200":{"description":"Exports.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExportListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"summary":"Create an export","operationId":"createExport","tags":["Exports"],"description":"Connects a destination and schedules every closed window from startAt. Writes <prefix><accountKey>/_querying/connection-check.json (or reads the BigQuery dataset) first; without the grant it returns 422 EXPORT_DESTINATION_UNREACHABLE with the storage provider's reason and saves nothing. API keys limited to some engines get 403 KEY_SCOPE. Up to 10 exports per account (409 EXPORT_LIMIT).","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateExportRequest"}}}},"responses":{"201":{"description":"Created export.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExportResponse"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/KeyScopeDenied"},"409":{"description":"EXPORT_LIMIT: the account already has 10 exports.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"EXPORT_DESTINATION_UNREACHABLE: the grant is missing; the message carries the storage provider's reason.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/exports/identity":{"get":{"summary":"Read the export identity","operationId":"getExportIdentity","tags":["Exports"],"description":"The Google service account to grant on a GCS bucket or BigQuery dataset, and the AWS web identity details and trust policy for an S3 role. accountKey names this account's folder and tables.","responses":{"200":{"description":"Export identity.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExportIdentityResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/monitors/{id}/events":{"get":{"summary":"List change events","operationId":"getMonitorEvents","tags":["Monitors"],"description":"The monitor's change events, newest first, each with its webhook delivery state. Events are kept for 30 days. A monitor sends them only while it has a webhookUrl.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"nextCursor from the previous page."},{"name":"type","in":"query","schema":{"type":"string","enum":["monitor.mention.started","monitor.mention.stopped","monitor.competitor.ahead","monitor.source.first_cited"]}}],"responses":{"200":{"description":"Events and their delivery state.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorEventsResponse"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/monitors/{id}/events/{eventId}/redeliver":{"post":{"summary":"Redeliver a change event","operationId":"redeliverMonitorEvent","tags":["Monitors"],"description":"Send one event again now to the monitor's current webhookUrl, with a fresh retry ladder, and return its delivery state after that attempt. Delivered events can be sent again.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"eventId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The event after the attempt.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorEventResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"WEBHOOK_NOT_SET: the monitor has no webhookUrl.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/monitors/{id}/share":{"get":{"summary":"Get report sharing","operationId":"getMonitorShare","tags":["Monitors"],"description":"Whether the monitor's report is published at querying.ai/<slug>, to whom and in which language, with a suggested slug to offer when none is set yet.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The current sharing state.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorShareResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"put":{"summary":"Share a report","operationId":"updateMonitorShare","tags":["Monitors"],"description":"Publish the monitor's read-only report at querying.ai/<slug> for anyone with the link (LINK) or for search engines too (PUBLIC), or take it offline (PRIVATE) while keeping the slug for the next time.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorShareRequest"},"example":{"access":"LINK","slug":"acme-earbuds","locale":"en"}}}},"responses":{"200":{"description":"The sharing state after the change.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorShareUpdateResponse"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"SLUG_TAKEN: another monitor already uses this slug.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"SLUG_TAKEN","message":"querying.ai/acme-earbuds is taken. Choose another address","timestamp":"2026-10-09T09:00:00.000Z"}}}}}}}},"/v1/ai-rendering/sites":{"get":{"summary":"List sites","operationId":"listAiRenderingSites","tags":["AI Rendering"],"description":"The account's connected sites, oldest first, each with its count of published pages.","responses":{"200":{"description":"The sites.","content":{"application/json":{"schema":{"type":"object","required":["success","sites"],"properties":{"success":{"type":"boolean"},"sites":{"type":"array","items":{"$ref":"#/components/schemas/AiRenderingSite"}}}}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"summary":"Connect a site","operationId":"createAiRenderingSite","tags":["AI Rendering"],"description":"Connects a host and returns its site key once. The site's CDN reads the site's copy list with the key. An account connects up to 20 sites, each host once. Connecting a site is free.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiRenderingSiteRequest"},"example":{"host":"www.example.com"}}}},"responses":{"201":{"description":"The site and its key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiRenderingSiteKeyResponse"},"example":{"success":true,"site":{"id":"5b0e9f52-6a3c-4f0e-8d0b-2c7e4a1f9d33","host":"www.example.com","refreshDays":28,"country":"US","keyPrefix":"rs_8f2c4a1b","pages":0,"createdAt":"2026-10-23T01:00:00.000Z","updatedAt":"2026-10-23T01:00:00.000Z"},"key":"rs_8f2c4a1b…"}}}},"400":{"description":"VALIDATION_ERROR: the body is not a JSON object or has an unknown field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"SITE_EXISTS: the account already connected the host. SITE_LIMIT: the account has 20 sites.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"VALIDATION_ERROR: host, agents, mode, refreshDays or country is not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/ai-rendering/sites/{id}":{"parameters":[{"name":"id","in":"path","required":true,"description":"The site's id.","schema":{"type":"string"}}],"get":{"summary":"Get a site","operationId":"getAiRenderingSite","tags":["AI Rendering"],"description":"The site and its published pages, newest first, each with its copy.","responses":{"200":{"description":"The site and its pages.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiRenderingSiteDetail"},"example":{"success":true,"site":{"id":"5b0e9f52-6a3c-4f0e-8d0b-2c7e4a1f9d33","host":"www.example.com","refreshDays":28,"country":"US","keyPrefix":"rs_8f2c4a1b","pages":1,"createdAt":"2026-10-23T01:00:00.000Z","updatedAt":"2026-10-23T01:00:00.000Z"},"pages":[{"id":"a3d1c9e0-7b52-4e1f-9c84-0f6b2d5e7a10","url":"https://www.example.com/products/sunscreen","path":"/products/sunscreen","status":"rendering","copy":null,"taskId":null,"renderedAt":null,"expiresAt":null,"publishedAt":"2026-10-23T01:00:00.000Z","refreshAt":"2026-10-23T01:00:00.000Z","refreshTaskId":"7c4e2a90-1d3b-4f6a-8e25-9b0c1f3d4e57"}]}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"NOT_FOUND: no site of the account with that id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"patch":{"summary":"Update a site","operationId":"updateAiRenderingSite","tags":["AI Rendering"],"description":"Changes how often the site's pages are rendered and from which country.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiRenderingSiteUpdate"},"example":{"agents":["chatgpt-user","oai-searchbot","claude-searchbot"]}}}},"responses":{"200":{"description":"The site.","content":{"application/json":{"schema":{"type":"object","required":["success","site"],"properties":{"success":{"type":"boolean"},"site":{"$ref":"#/components/schemas/AiRenderingSite"}}}}}},"400":{"description":"VALIDATION_ERROR: the body is not a JSON object or has an unknown field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"NOT_FOUND: no site of the account with that id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"VALIDATION_ERROR: agents, mode, refreshDays or country is not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"summary":"Remove a site","operationId":"deleteAiRenderingSite","tags":["AI Rendering"],"description":"Removes the site and its published pages. Its key stops working within 30 seconds, and the CDN sends every request to the origin.","responses":{"200":{"description":"Removed.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}}}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"NOT_FOUND: no site of the account with that id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/ai-rendering/sites/{id}/key":{"parameters":[{"name":"id","in":"path","required":true,"description":"The site's id.","schema":{"type":"string"}}],"post":{"summary":"Get a new site key","operationId":"rotateAiRenderingSiteKey","tags":["AI Rendering"],"description":"Returns a new site key once. The previous key stops at once; update the CDN's key with it.","responses":{"200":{"description":"The site and its new key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiRenderingSiteKeyResponse"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"NOT_FOUND: no site of the account with that id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/ai-rendering/sites/{id}/pages":{"parameters":[{"name":"id","in":"path","required":true,"description":"The site's id.","schema":{"type":"string"}}],"post":{"summary":"Publish a page","operationId":"publishAiRenderingPage","tags":["AI Rendering"],"description":"With url, queues an AI_RENDERING task that renders the page as a person sees it in the site's country and writes the text of its images into their alt text (202). The copy joins the site's copy list once it is made, and the page is rendered again every refreshDays. A page already rendering returns that task; a published page sent again is rendered now. A render costs 5 credits, plus 5 for each image whose text is read and 2 for each image the account read in the last 90 days, at most 12 images: submitting holds 65 credits and a failed render is not charged. A refresh is charged the same, to the site's account. With taskId, publishes the copy a completed GEO Score of the account made, without rendering again (201). A site publishes up to 1,000 pages.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiRenderingPublishRequest"},"examples":{"url":{"summary":"Render by URL","value":{"url":"https://www.example.com/products/sunscreen"}},"geoScore":{"summary":"Publish a GEO Score's copy","value":{"taskId":"0b6c1f7e-2d4a-4c55-9a0e-3f1d2b7c8e91"}}}}}},"responses":{"201":{"description":"Published from a GEO Score; the copy is in the site's copy list at once.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiRenderingPageResponse"}}}},"202":{"description":"Rendering; the copy joins the site's copy list once it is made.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiRenderingPageResponse"},"example":{"success":true,"page":{"id":"a3d1c9e0-7b52-4e1f-9c84-0f6b2d5e7a10","url":"https://www.example.com/products/sunscreen","path":"/products/sunscreen","status":"rendering","copy":null,"taskId":null,"renderedAt":null,"expiresAt":null,"publishedAt":"2026-10-23T01:00:00.000Z","refreshAt":"2026-10-23T01:00:00.000Z","refreshTaskId":"7c4e2a90-1d3b-4f6a-8e25-9b0c1f3d4e57"},"taskId":"7c4e2a90-1d3b-4f6a-8e25-9b0c1f3d4e57"}}}},"400":{"description":"VALIDATION_ERROR: the body is not a JSON object or has an unknown field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"INSUFFICIENT_CREDITS: the balance cannot cover the 65-credit hold.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"KEY_SCOPE_DENIED: the API key is limited to engines that leave out GEO_SCORE.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"NOT_FOUND: no site of the account with that id, or no GEO Score task of the account with taskId.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"PAGE_LIMIT: the site has 1,000 pages. TASK_NOT_COMPLETED: the GEO Score has not completed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"410":{"description":"COPY_EXPIRED: the GEO Score's copy has expired; publish the page by url.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"VALIDATION_ERROR: url is not a page on the site's host, or the GEO Score was scored from another country than the site's. NO_RENDERED_COPY: the GEO Score made no copy.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Plan concurrency is full; retry after Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"The engine's backlog is full; retry after Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/ai-rendering/sites/{id}/pages/{pageId}":{"parameters":[{"name":"id","in":"path","required":true,"description":"The site's id.","schema":{"type":"string"}},{"name":"pageId","in":"path","required":true,"schema":{"type":"string"}}],"delete":{"summary":"Take a page down","operationId":"deleteAiRenderingPage","tags":["AI Rendering"],"description":"The page leaves the site's copy list, and the site's CDN drops its copy at the next sync. The page is no longer rendered.","responses":{"200":{"description":"Taken down.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}}}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"NOT_FOUND: no site of the account with that id, or no published page with pageId.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/ai-rendering/copies":{"get":{"summary":"List a site's copies","operationId":"listAiRenderingCopies","tags":["AI Rendering"],"security":[{"siteKey":[]}],"description":"What a site's CDN reads on a schedule to keep its copies: every published page whose copy has not expired, with the copy's file. Download a copy when its renderedAt is new, drop the copies of pages no longer listed, and answer AI agents' GETs with the stored copies. Free.","responses":{"200":{"description":"The site's copies.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiRenderingCopyList"},"example":{"success":true,"host":"www.example.com","copies":[{"path":"/products/sunscreen","url":"https://www.example.com/products/sunscreen","copy":"https://api.querying.ai/v1/evidence/1792717200-9f3c2a7d1e4b.html","renderedAt":"2026-10-23T01:00:31.000Z","expiresAt":"2026-11-22T01:00:00.000Z"}]}}}},"401":{"description":"UNAUTHORIZED: no site key, a replaced key, or the key of a removed site.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Your API key, sent as `Authorization: Bearer <key>`."},"siteKey":{"type":"apiKey","in":"header","name":"X-Querying-Site-Key","description":"The site key AI Rendering showed when the site was connected or given a new key. It reads the site's copy list and nothing else."}},"responses":{"NotFound":{"description":"No monitor with that id for this key, or no scored row with that task id. A monitor owned by another account is reported the same way rather than as a 403.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"NOT_FOUND","message":"No monitor with that id","timestamp":"2026-09-22T04:12:00.000Z"}}}}},"KeyScopeDenied":{"description":"The key is restricted to some engines (allowedTaskTypes) and the monitor schedules an engine outside that list. The scope that applies to POST /v1/async/task also applies to monitors, or a schedule would be a way around it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"KEY_SCOPE_DENIED","message":"This key is not allowed to use engine GEMINI","timestamp":"2026-09-22T04:12:00.000Z"}}}}},"MonitorLimit":{"description":"The account already holds the maximum number of monitors. Delete one before creating another.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"MONITOR_LIMIT","message":"Max 20 monitors — delete one first","timestamp":"2026-09-22T04:12:00.000Z"}}}}},"Unauthorized":{"description":"Missing or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"MISSING_API_KEY","message":"Missing or invalid API key","timestamp":"2026-07-09T04:12:00.000Z"}}}}},"ValidationError":{"description":"The request is malformed — bad JSON, unrecognised `taskType`, or neither `payload.prompt` nor `payload.query` present. `details` names the offending field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"missingPrompt":{"summary":"Neither prompt nor query supplied","value":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed","details":[{"field":"payload.prompt","message":"payload.prompt or payload.query is required"}],"timestamp":"2026-07-09T04:12:00.000Z"}}},"badTaskType":{"summary":"Unrecognised taskType","value":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed","details":[{"field":"taskType","message":"'NOPE' is not recognized"}],"timestamp":"2026-07-09T04:12:00.000Z"}}}}}}},"RegionUnavailable":{"description":"The request is well-formed, but it cannot be served as asked. `REGION_UNSUPPORTED`: this engine never serves `payload.country`. `LOCATION_UNSUPPORTED`: the engine does not take `payload.location`. `EVIDENCE_UNSUPPORTED`: the engine cannot return `include.html`, or a CHATGPT task asks for it with `location`, country `CN` or `HK`, or `continueFrom`. `VALIDATION_ERROR` (422): an engine-specific field rule, such as a WEB_SCRAPE URL, a REDDIT field, a BING_SEARCH text over 4,000 characters, or `include.analysis` on an engine that does not support it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"REGION_UNSUPPORTED","message":"PERPLEXITY cannot be served for country='CN' ...","details":{"taskType":"PERPLEXITY","country":"CN","retryable":false},"timestamp":"2026-07-09T04:12:00.000Z"}}}}}},"schemas":{"TaskType":{"type":"string","description":"The engine to query. `NAVER` is a deprecated alias for `NAVER_AI_BRIEF`. GOOGLE_AIO and GOOGLE_AIMODE are the unified names for GOOGLE and AIMODE; both spellings are accepted and responses echo the canonical GOOGLE / AIMODE. `NAVER_AI_MODE` is accepted as an earlier spelling of `NAVER_AI_TAB`. `GOOGLE_SERP` returns the Google results page without the AI Overview; `payload.page` selects pages 1-10. `NAVER_SERP` returns Naver's web results, 15 per page (`payload.page` 1-10), and with `payload.action` `page` reads one naver.com page by `payload.url`. `REDDIT` searches Reddit posts by `query` (optionally within one `subreddit`), reads one post with its first page of comments by `url`, or lists posts with `action` `feed` or `user_posts`. `WEB_SCRAPE` reads one web page by `payload.url` and returns its main content as Markdown with its images. `WEB_MAP` lists a site's addresses from its start page links and sitemaps. `WEB_CRAWL` reads a site's pages under a start address, each as WEB_SCRAPE reads it, at 1 credit per page returned. `KEYWORD_VOLUME` returns the monthly search volume of `payload.keywords` (1-100) in `payload.country`: Naver for KR and Google for 216 other countries. `META_AI` returns the meta.ai chat answer with its cited sources, search queries and the products it shows (`shoppingCards`, `inlineProducts`); a prompt Meta refuses completes with an empty text and a `notice` quoting Meta. `QWEN` returns the answer of Qwen's China web chat (qianwen.com) with its web search, sources and search queries; `payload.country` sets the exit and the answer locale. `DOUBAO` returns the answer of Doubao's China web chat (doubao.com) with its web search, sources and search queries; it always asks from mainland China, whatever `payload.country` is. `BING` and `BING_COPILOT_SEARCH` are accepted as earlier spellings of `BING_SEARCH`, and `COPILOT` as the earlier spelling of `BING_COPILOT`; responses echo the new names. Private engines (for example CLAUDE) are rejected with 403 ENGINE_PRIVATE. CITATION_ANALYSIS, PROMPT_RESEARCH and GEO_SCORE tasks are created through their own endpoints (POST /v1/citation-analysis, POST /v1/prompt-research, POST /v1/geo-score) and are rejected here with 400 USE_DEDICATED_ENDPOINT; they appear in this list because their tasks report them. GEO_AUDIT, SOURCE_INFLUENCE and CITATION_ATTRIBUTION are accepted as earlier names of CITATION_ANALYSIS; responses echo CITATION_ANALYSIS.","enum":["CHATGPT","PERPLEXITY","GEMINI","AIMODE","GOOGLE_AIMODE","GOOGLE","GOOGLE_AIO","GOOGLE_SERP","NAVER_AI_BRIEF","NAVER_AI_TAB","NAVER_AI_MODE","NAVER","NAVER_SERP","COMMERCE_SERP","COMMERCE_PRODUCT","BING_SEARCH","BING","BING_COPILOT_SEARCH","BING_COPILOT","COPILOT","META_AI","QWEN","DOUBAO","REDDIT","WEB_SCRAPE","WEB_MAP","WEB_CRAWL","KEYWORD_VOLUME","CITATION_ANALYSIS","GEO_AUDIT","SOURCE_INFLUENCE","CITATION_ATTRIBUTION","PROMPT_RESEARCH","GEO_SCORE"]},"TaskStatus":{"type":"string","description":"`PROCESSING` means a worker holds the task. `COMPLETED` and `FAILED` are terminal.","enum":["QUEUED","PROCESSING","COMPLETED","FAILED"]},"Include":{"type":"object","description":"Optional output flags. `markdown`, `rawResponse`, `searchQueries`, `ads` and `shopping` are ignored by engines that do not support them. `analysis` on an unsupported engine is rejected with 422 VALIDATION_ERROR, `html` with 422 EVIDENCE_UNSUPPORTED, and `screenshot: true` with 400 VALIDATION_ERROR on every engine. See the engine guide for the support table.","properties":{"markdown":{"type":"boolean","description":"Adds `markdown` on CHATGPT (on by default), PERPLEXITY, GEMINI, GOOGLE (the AI Overview), BING_SEARCH (the summary) and BING_COPILOT. AIMODE, META_AI, QWEN, DOUBAO, NAVER_AI_BRIEF and NAVER_AI_TAB return `markdown` without the flag."},"html":{"type":"boolean","description":"Returns `html`: `{\"status\": \"ok\", \"url\", \"expiresAt\"}`, the screen the engine showed for the answer, which opens without an API key until `expiresAt` (30 days). On GOOGLE and AIMODE it is the results page Google served, scripts removed; on CHATGPT, GEMINI, PERPLEXITY and META_AI it is the engine's screen as it showed when the answer finished, scripts removed and images included. A screen that could not be collected, did not match the answer, or could not be stored comes back as `{\"status\": \"failed\", \"error\": \"EVIDENCE_FAILED\"}` and the task still completes. Other engines reject it with 422 EVIDENCE_UNSUPPORTED, and so does CHATGPT with `location`, country `CN` or `HK`, or `continueFrom`: ChatGPT draws its page only for a new conversation answered without a device location. On CHATGPT, PERPLEXITY and META_AI it costs 0.25 credits per task on top of the engine's price, charged only when `html.status` is `ok`; on GEMINI, GOOGLE and AIMODE it costs nothing more. Off by default."},"rawResponse":{"type":"boolean","description":"Returns the engine's raw payload. Arrives as `rawResponse` on CHATGPT, GEMINI, PERPLEXITY, BING_COPILOT, META_AI, QWEN and DOUBAO, and as `rawContent` on GOOGLE, AIMODE, GOOGLE_SERP, BING_SEARCH, NAVER_AI_BRIEF and NAVER_AI_TAB. NAVER_SERP, REDDIT, WEB_SCRAPE, WEB_MAP, WEB_CRAWL and KEYWORD_VOLUME return no raw payload. Off by default."},"searchQueries":{"type":"boolean","description":"Gates `searchQueries` on CHATGPT (on by default) and PERPLEXITY. Other engines that emit it do so unconditionally."},"ads":{"type":"boolean","description":"Only honored by CHATGPT."},"shopping":{"type":"boolean","description":"Only honored by CHATGPT."},"citationAnalysis":{"type":"boolean","description":"Answer engines (CHATGPT, GEMINI, PERPLEXITY, GOOGLE_AIO, GOOGLE_AIMODE, NAVER_AI_BRIEF, NAVER_AI_TAB, BING_SEARCH, BING_COPILOT): run a Citation Analysis analysis on the answer as soon as it is collected. The result then carries `response.citationAnalysis`, the analysis task as GET /v1/async/task/{id} returns it (`task`, `credits`, `response` or `error`), or `{error}` when no analysis could start (no cited URL, or credits or the key's daily limit cannot cover its hold). The webhook is sent once, after the analysis settles; a polled answer task is COMPLETED first, so poll until `response.citationAnalysis.task.status` is terminal. The analysis is charged separately by usage; a key limited to certain task types must also allow CITATION_ANALYSIS. Any other engine is rejected with 400."},"geoAudit":{"type":"boolean","deprecated":true,"description":"Accepted alias of `citationAnalysis`; results still carry `response.citationAnalysis`."},"sourceInfluence":{"type":"boolean","deprecated":true,"description":"Accepted alias of `citationAnalysis`; results still carry `response.citationAnalysis`."},"analysis":{"type":"boolean","description":"CHATGPT, GEMINI, PERPLEXITY, GOOGLE, AIMODE, NAVER_AI_BRIEF and NAVER_AI_TAB. Adds `analysis` (AnswerAnalysis) to the response: every brand the answer names in order, with recommendation and sentiment, the presence of `brand` and `competitors`, and the kind of each cited site. 1 credit per task on top of the engine price, charged only when `analysis.status` is `ok`. Rejected with 422 on other engines."},"entityDetails":{"type":"boolean","description":"CHATGPT only. Adds `entityDetails`: for each card in the answer (up to 20), the detail panel ChatGPT opens when a reader clicks it, with `name`, `category`, `query`, `status` (`ok` or `failed` with `error`), `markdown`, `sources` (`position`, `url`, `label`, `site`, `description`), `products` (the shopping card a product's panel opens on, shaped like `shoppingCards[].products`), `images` and `complete` (`false` when ChatGPT stopped writing the panel early). `error` is `ENTITY_DETAIL_FAILED`, `ENTITY_DETAIL_EMPTY`, or `ENTITY_DETAIL_UNAVAILABLE` when the conversation or turn credentials needed to open panels are missing. Supports tasks with `payload.location`, CN, HK, fallback answers and `html`. No extra credits; each follow-up answer gets its own panels. Rejected with 422 on other engines. Off by default."},"aioverview":{"type":"object","description":"Legacy GOOGLE flag. `aioverview.markdown: true` works like `include.markdown` on GOOGLE.","properties":{"markdown":{"type":"boolean"}}},"screenshot":{"type":"boolean","description":"No longer available. `true` is rejected with 400 VALIDATION_ERROR; use `html` for a page of the answer."}},"additionalProperties":false},"FollowUpSelect":{"type":"object","additionalProperties":false,"description":"Press a button of a ChatGPT follow-up form.","properties":{"button":{"type":"integer","minimum":0,"default":0,"description":"The button, counted from 0 across the answer's forms."},"choices":{"description":"Options to pick by choice name, or as an array in the form's order. A pick is an option's value or label, or its position from 0. Unpicked choices keep ChatGPT's selection.","oneOf":[{"type":"object","maxProperties":20,"additionalProperties":{"oneOf":[{"type":"string","minLength":1,"maxLength":500},{"type":"integer","minimum":0}]}},{"type":"array","maxItems":20,"items":{"oneOf":[{"type":"string","minLength":1,"maxLength":500},{"type":"integer","minimum":0}]}}]}}},"CommerceSerpPayload":{"type":"object","required":["site","query"],"properties":{"site":{"type":"string","enum":["amazon","walmart","target","ebay","aliexpress","google_shopping","sephora","ulta","coupang","oliveyoung","11st","lotteon","musinsa","kurly","rakuten","yahoo_shopping","qoo10","flipkart","myntra","nykaa","zalando"],"description":"The storefront to search. One site per task."},"query":{"type":"string","minLength":1,"maxLength":500},"country":{"type":"string","description":"The site's own country: US for amazon, walmart, target, ebay, aliexpress, google_shopping, sephora and ulta; KR for coupang, oliveyoung, 11st, lotteon, musinsa and kurly; JP for rakuten, yahoo_shopping and qoo10; IN for flipkart, myntra and nykaa; DE for zalando. Omit to use it; any other value is rejected with 422 REGION_UNSUPPORTED."},"limit":{"type":"integer","minimum":1,"maximum":40,"default":20}},"additionalProperties":false},"CommerceSerpProduct":{"type":"object","required":["rank","productId","title","url"],"properties":{"rank":{"type":"integer","minimum":1,"description":"Position among the results the storefront shows. Sponsored listings are left out on every site except Coupang."},"productId":{"type":"string","description":"The storefront's own product id, such as the ASIN on amazon, the TCIN on target, the item number on ebay or shop:item on rakuten. On google_shopping it is Google's product id, or the offer id for a listing Google has not grouped into a product."},"title":{"type":"string"},"url":{"type":"string","format":"uri","description":"The product page. On google_shopping, the Google Shopping results page the product was ranked on, with #product={productId}&title={title} at the end: Google's page links no product or merchant page. COMMERCE_PRODUCT reads that url."},"price":{"type":"number","description":"The displayed price, or the lowest price when the product's sizes are priced apart. Absent when the search page shows none."},"currency":{"type":"string","description":"ISO 4217 code of this product's price. Amazon can list prices in more than one currency in the same search."},"rating":{"type":"number","minimum":0,"maximum":5},"reviewCount":{"type":"integer","minimum":0,"description":"Absent when the storefront abbreviates the count, such as 999+ or Google Shopping's 17K."},"imageUrl":{"type":"string","format":"uri"},"brand":{"type":"string","description":"Present where the storefront lists the brand apart from the title."},"seller":{"type":"string","description":"google_shopping only: the store Google lists first for the product."}}},"CommerceSerpResult":{"type":"object","required":["site","query","country","returnedCount","products"],"properties":{"site":{"type":"string","enum":["amazon","walmart","target","ebay","aliexpress","google_shopping","sephora","ulta","coupang","oliveyoung","11st","lotteon","musinsa","kurly","rakuten","yahoo_shopping","qoo10","flipkart","myntra","nykaa","zalando"]},"query":{"type":"string"},"country":{"type":"string"},"returnedCount":{"type":"integer","minimum":1,"maximum":40},"products":{"type":"array","minItems":1,"maxItems":40,"items":{"$ref":"#/components/schemas/CommerceSerpProduct"}}}},"CommerceProductPayload":{"type":"object","required":["url"],"properties":{"url":{"type":"string","maxLength":2048,"description":"A product page on amazon.com, walmart.com, target.com, sephora.com or ulta.com (US); 11st.co.kr, lotteon.com, musinsa.com, kurly.com or oliveyoung.co.kr (KR); item.rakuten.co.jp, store.shopping.yahoo.co.jp or qoo10.jp (JP); flipkart.com, myntra.com or nykaa.com (IN); or zalando.de (DE). The URL picks the storefront. Product URLs that COMMERCE_SERP returns for these storefronts work as they are, except yahoo_shopping's LOHACO pages on lohaco.yahoo.co.jp. A google_shopping product is read from the url COMMERCE_SERP returns for it (google.com/search?q={query}&udm=28#product={productId}&title={title}): the read runs the query again, or the title when Google no longer lists the product for the query, opens that product's panel, and fails with PAGE_UNAVAILABLE when Google lists it for neither."},"country":{"type":"string","description":"The storefront's own country: US for amazon, walmart, target, sephora, ulta and google_shopping; KR for 11st, lotteon, musinsa, kurly and oliveyoung; JP for rakuten, yahoo_shopping and qoo10; IN for flipkart, myntra and nykaa; DE for zalando. Omit to use it; any other value is rejected with 422 REGION_UNSUPPORTED."}},"additionalProperties":false},"CommerceProductResult":{"type":"object","required":["site","country","url","productId","title"],"properties":{"site":{"type":"string","enum":["amazon","walmart","target","sephora","ulta","11st","lotteon","musinsa","kurly","oliveyoung","rakuten","yahoo_shopping","qoo10","flipkart","myntra","nykaa","zalando","google_shopping"]},"country":{"type":"string"},"url":{"type":"string","format":"uri","description":"The page that was read, without the parameters its fields do not depend on, such as tracking codes."},"productId":{"type":"string","description":"The storefront's own product id, such as the ASIN on amazon or shop:item on rakuten. It matches the one COMMERCE_SERP returns, except for a nykaa product with shades or sizes, where COMMERCE_SERP returns one option's id and this read returns the product page's id."},"title":{"type":"string"},"brand":{"type":"string"},"price":{"type":"number","description":"What a shopper pays for the product as the page first shows it, before coupons and delivery."},"listPrice":{"type":"number","description":"The regular price the page strikes through, present when it is above price."},"currency":{"type":"string","description":"ISO 4217 code of price and listPrice."},"inStock":{"type":"boolean"},"seller":{"type":"string"},"offers":{"type":"array","maxItems":20,"description":"google_shopping only: the stores Google shows for the product, starting with the one Google marks as the best price. The product's price, listPrice, seller and inStock are the first store's.","items":{"type":"object","required":["seller"],"properties":{"seller":{"type":"string"},"title":{"type":"string","description":"The store's own name for the product."},"url":{"type":"string","format":"uri","description":"The store's product page, absent when Google's link to it did not resolve."},"price":{"type":"number"},"listPrice":{"type":"number"},"currency":{"type":"string"},"inStock":{"type":"boolean"}}}},"rating":{"type":"number","minimum":0,"maximum":5},"reviewCount":{"type":"integer","minimum":0},"images":{"type":"array","maxItems":30,"items":{"type":"string","format":"uri"},"description":"Photos from the product's gallery, in page order. 11st and lotteon return the main photo only; on rakuten and yahoo_shopping, banners or notices a seller places in that gallery come along."},"description":{"type":"string","maxLength":10000,"description":"Plain text, one line per paragraph."},"descriptionImages":{"type":"array","maxItems":300,"items":{"type":"string","format":"uri"},"description":"Images from the product description, such as a seller's detail page or Amazon A+ content, in page order. Returned by amazon, 11st, lotteon, musinsa, kurly, rakuten, yahoo_shopping and qoo10."},"specs":{"type":"array","maxItems":100,"items":{"type":"object","required":["name","value"],"properties":{"name":{"type":"string"},"value":{"type":"string"}}}},"options":{"type":"array","maxItems":20,"description":"Choices such as size or color. The other fields describe the choice the page opens on.","items":{"type":"object","required":["name","values"],"properties":{"name":{"type":"string"},"values":{"type":"array","maxItems":100,"items":{"type":"string"}}}}},"categories":{"type":"array","maxItems":10,"description":"From the broadest category to the narrowest.","items":{"type":"string"}},"gtin":{"type":"string","description":"The UPC, EAN or JAN the page lists."}}},"Payload":{"type":"object","description":"Engine payloads share this envelope. COMMERCE_SERP requires site and query (see CommerceSerpPayload). COMMERCE_PRODUCT requires url, a product page on a supported storefront (see CommerceProductPayload). Other scraping engines require prompt or query; WEB_SCRAPE, WEB_MAP and WEB_CRAWL require url; KEYWORD_VOLUME requires keywords and country. CITATION_ANALYSIS has its own endpoint (POST /v1/citation-analysis, with answer and citations at the top level; GEO_AUDIT, SOURCE_INFLUENCE and CITATION_ATTRIBUTION are accepted aliases) and is rejected here with 400 USE_DEDICATED_ENDPOINT.","properties":{"prompt":{"type":"string","description":"The question, for LLM engines."},"query":{"type":"string","description":"The search term, for GOOGLE, AIMODE, GOOGLE_SERP, BING_SEARCH, REDDIT, COMMERCE_SERP and NAVER_* engines. BING_SEARCH reads `prompt` first and falls back to `query`, and rejects text over 4,000 characters with 422 VALIDATION_ERROR."},"country":{"type":"string","description":"ISO 3166-1 alpha-2 country code, case-insensitive. Omitted, empty or null means `US` (`KR` for NAVER_* engines). A value that is not an officially assigned code, such as `UK` (use `GB`), is rejected with 400 VALIDATION_ERROR, and a country this engine cannot serve is rejected at submit time with 422.","example":"US"},"location":{"type":"object","additionalProperties":false,"required":["latitude","longitude"],"properties":{"latitude":{"type":"number","minimum":-90,"maximum":90},"longitude":{"type":"number","minimum":-180,"maximum":180}},"description":"CHATGPT, GEMINI, GOOGLE, AIMODE and GOOGLE_SERP. The point to ask from, in decimal degrees (WGS84). The engine answers as a user standing there, so local recommendations come from that neighborhood. Send a point inside `country`: `country` sets the market and this point sets the device location. The response echoes it as `location`.","example":{"latitude":37.4979,"longitude":127.0276}},"followUps":{"type":"array","minItems":1,"maxItems":4,"description":"CHATGPT only. Questions asked after the first answer in the same conversation, in order. Each answer costs 1 credit. The result lists the answers in followUps and, when a select cannot be pressed, where and why the turns stopped in followUpsStopped.","items":{"oneOf":[{"type":"object","additionalProperties":false,"required":["prompt"],"properties":{"prompt":{"type":"string","minLength":1,"maxLength":100000,"description":"A question of your own."}}},{"type":"object","additionalProperties":false,"required":["select"],"properties":{"select":{"$ref":"#/components/schemas/FollowUpSelect","description":"Press a follow-up form's button in the previous answer."}}}]}},"continueFrom":{"type":"string","format":"uuid","description":"CHATGPT only. The id of a completed CHATGPT task of this account: asks one more question in its conversation, under its last answer, with either `prompt` or `select`. `country` and `location` carry over; leave them out or send the same values. The result carries `conversation` (`id`, `turn`, `expiresAt`) and, when it pressed a form, `selection`. Rejected before any charge with 400 VALIDATION_ERROR (another account's or engine's task, a task not completed, an invalid select) or 400 CONVERSATION_EXPIRED (after `conversation.expiresAt`, 3 hours after the conversation's first answer)."},"select":{"$ref":"#/components/schemas/FollowUpSelect","description":"With `continueFrom`, instead of `prompt`: press a follow-up form's button in the last answer of the continued task. Answers that show a form list them in `forms` (`buttons` in `button` order, `choices` with their `name`, the option selected at first and the `options`)."},"page":{"type":"integer","minimum":1,"maximum":10,"default":1,"description":"GOOGLE_SERP and NAVER_SERP. The results page to return, 1-10. Positions count across pages, so page 2 starts at 11 on Google and at 16 on Naver."},"subreddit":{"type":"string","pattern":"^[A-Za-z0-9_]{2,21}$","description":"REDDIT only. Limits a search to one subreddit (the name without `r/`), or picks the subreddit for `action` `feed`. A feed without it lists r/popular."},"url":{"type":"string","format":"uri","description":"REDDIT: a public post URL (`https://www.reddit.com/r/{subreddit}/comments/{postId}/...`); returns `post` with its first page of about 20-25 `comments` instead of searching. NAVER_SERP with `action` `page`: the naver.com page to read (blog, cafe, news, terms, kin or any other naver.com page). A redirect that leaves naver.com fails the task. WEB_SCRAPE: the HTML, plain-text page or text-based PDF to read, a public http or https address on the default port, up to 2,048 characters. PDFs return page-order text as `markdown`, available document metadata and `images: []`; no OCR, attachments or layout reconstruction. PDF limits: 8 MiB downloaded, 100 pages, 1,000,000 extracted characters and 20 seconds of extraction, independently of maxChars. Encrypted, damaged, incomplete, textless or over-limit PDFs fail with PAGE_UNAVAILABLE. A multi-page PDF costs 1 credit per URL. WEB_MAP and WEB_CRAWL: the site's start address, under the same rules; the host it redirects to is the site (`www.` aside)."},"action":{"type":"string","enum":["feed","user_posts","page","search"],"description":"REDDIT: `feed` lists the newest posts of `subreddit`, `user_posts` lists what `username` submitted. NAVER_SERP: `page` reads `url` instead of searching. Omit it to search."},"username":{"type":"string","pattern":"^[A-Za-z0-9_-]{3,20}$","description":"REDDIT with `action` `user_posts`. The Reddit username, without `u/`."},"limit":{"type":"integer","minimum":1,"maximum":10000,"description":"COMMERCE_SERP: product count, integer 1-40 (default 20). REDDIT with `action` `feed` or `user_posts`: the most posts to return, 1-25 (default 25). WEB_MAP: the most addresses to return, 1-10,000 (default 1,000); `truncated` says whether the list was cut."},"commentSort":{"type":"string","enum":["top","new","controversial","old","qa"],"default":"top","description":"REDDIT post `url` only. The order of the returned comment page."},"commentMaxDepth":{"type":"integer","minimum":0,"maximum":100,"description":"REDDIT post `url` only. Drops replies deeper than this; `0` keeps top-level comments only."},"maxChars":{"type":"integer","minimum":1000,"maximum":200000,"description":"NAVER_SERP with `action` `page`, WEB_SCRAPE and WEB_CRAWL. The most characters to return: page text on NAVER_SERP (1,000-50,000, default 20,000), Markdown on WEB_SCRAPE (1,000-200,000, default 100,000), Markdown per page on WEB_CRAWL (1,000-50,000, default 20,000). `truncated` says whether it was cut."},"maxPages":{"type":"integer","minimum":1,"maximum":100,"default":10,"description":"WEB_CRAWL. The most pages to read, the start page included. The task holds this many credits at submission and is charged 1 credit per page it returns; pages it could not read are not charged."},"maxDepth":{"type":"integer","minimum":0,"maximum":5,"default":2,"description":"WEB_CRAWL. Link hops from the start page; `0` reads the start page alone."},"includePaths":{"type":"array","maxItems":20,"items":{"type":"string","pattern":"^/","maxLength":200},"description":"WEB_MAP and WEB_CRAWL. Path patterns an address must match: `*` within one path segment, `**` across segments, `/blog/**` includes `/blog`. Matched against the decoded path."},"excludePaths":{"type":"array","maxItems":20,"items":{"type":"string","pattern":"^/","maxLength":200},"description":"WEB_MAP and WEB_CRAWL. Path patterns that remove an address, in the same form as `includePaths`, which they override."},"includeSubdomains":{"type":"boolean","default":false,"description":"WEB_MAP and WEB_CRAWL. Counts the site's subdomains as the site."},"keywords":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"string","minLength":1,"maxLength":80},"description":"KEYWORD_VOLUME only. The keywords to count, 1-100 of up to 80 characters each; KR keywords take letters, digits and spaces. Each comes back with `searchVolume` (the 12-month average), `monthlySearches` (`{month, searchVolume}`, oldest first), `last30Days` (Naver's 30-day count, KR only) and `competition`. `country` is required, and CN and RU are refused with 422 REGION_UNSUPPORTED.","example":["sunscreen","best sunscreen for face"]},"include":{"$ref":"#/components/schemas/Include"},"brand":{"type":"string","maxLength":200,"description":"With `include.analysis`: your brand's name, reported in `analysis.targets` with role `brand`."},"brandAliases":{"type":"array","maxItems":20,"items":{"type":"string","maxLength":200},"description":"With `include.analysis` and `brand`: other names the answer may use for your brand."},"brandDomains":{"type":"array","maxItems":20,"items":{"type":"string"},"description":"With `include.analysis` and `brand`: your sites, such as `example.com`. A citation on one of them or a subdomain has `kind` `owned`.","example":["example.com"]},"competitors":{"type":"array","maxItems":50,"items":{"oneOf":[{"type":"string","maxLength":200},{"type":"object","additionalProperties":false,"required":["name"],"properties":{"name":{"type":"string","maxLength":200},"aliases":{"type":"array","maxItems":20,"items":{"type":"string","maxLength":200}},"domains":{"type":"array","maxItems":20,"items":{"type":"string"}}}}]},"description":"With `include.analysis`: competitors reported in `analysis.targets` with role `competitor`. A citation on one of their domains has `kind` `competitor`."}},"additionalProperties":false},"AsyncRequest":{"type":"object","required":["taskType","payload"],"allOf":[{"if":{"properties":{"taskType":{"const":"COMMERCE_SERP"}},"required":["taskType"]},"then":{"properties":{"payload":{"$ref":"#/components/schemas/CommerceSerpPayload"}}}},{"if":{"properties":{"taskType":{"const":"COMMERCE_PRODUCT"}},"required":["taskType"]},"then":{"properties":{"payload":{"$ref":"#/components/schemas/CommerceProductPayload"}}}}],"properties":{"taskType":{"$ref":"#/components/schemas/TaskType"},"idempotencyKey":{"type":"string","description":"Optional. Deduplicates submissions. Omit for no deduplication. A duplicate is a `409` on this endpoint, but a success on the batch endpoint."},"priority":{"type":"integer","description":"Compatibility field; does not guarantee execution order. Values outside 1–10 are clamped, not rejected.","minimum":1,"maximum":10,"default":1},"webhook":{"type":"object","description":"Optional. Omit to collect the result by polling instead.","required":["url"],"properties":{"url":{"type":"string","format":"uri","description":"Receives a POST when the task reaches a terminal state."}}},"payload":{"$ref":"#/components/schemas/Payload"}},"additionalProperties":false},"TaskMeta":{"type":"object","required":["id","taskType","status","priority","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"taskType":{"$ref":"#/components/schemas/TaskType"},"status":{"$ref":"#/components/schemas/TaskStatus"},"priority":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"idempotencyKey":{"type":"string","description":"Echoed back verbatim. **Omitted** — not null — when the caller supplied none."}}},"Credits":{"type":"object","description":"Credits, with up to two decimals (for example `1.25`). The submit response always shows `0`: a hold is placed on your balance, but nothing is charged yet. Polling shows `0` until the task is terminal, then the settled charge: the task's price for COMPLETED, `0` for FAILED. A task webhook reports the same charge in `creditsCharged`; on a FAILED task it reports the task's price in `creditsToCharge` and `0` in `creditsCharged`. CITATION_ANALYSIS and WEB_CRAWL are charged by usage, up to the hold placed at submit.","properties":{"creditsToCharge":{"type":"number"},"creditsCharged":{"type":["number","null"]}}},"CreditBalance":{"type":"object","required":["success","remaining","perCycle","cycleResetsAt","reserved","plan","topUpBalance"],"properties":{"success":{"type":"boolean","const":true},"remaining":{"type":"number","description":"Credits you can spend now, with up to two decimals. Tasks you already submitted hold their price in `reserved`, so it is not in this number. A submit that needs more returns `402 INSUFFICIENT_CREDITS`."},"perCycle":{"type":["number","null"],"description":"Credits your plan grants each billing cycle. `null` without an active plan."},"cycleResetsAt":{"type":["string","null"],"format":"date-time","description":"When the current billing cycle ends. At renewal your balance becomes the next cycle's plan credits plus the top-up credits you still hold. `null` without an active plan."},"reserved":{"type":"number","description":"Credits your queued and running tasks hold. A completed task is charged from its hold, and a failed task's hold returns to `remaining`."},"plan":{"type":"string","enum":["free","basic","pro","scale","max"],"description":"Your plan. `free` when no paid plan is active."},"topUpBalance":{"type":["object","null"],"description":"Top-up credits within `remaining`. They last three months from purchase, carry over renewals, and are spent after your plan's credits. `null` when you have none.","required":["credits","nextExpiresAt","nextCredits"],"properties":{"credits":{"type":"number","description":"Top-up credits left."},"nextExpiresAt":{"type":"string","format":"date-time","description":"When the next of them expire."},"nextCredits":{"type":"number","description":"How many expire then."}}}}},"Usage":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","required":["from","to","groupBy","credits","tasks","rows"],"properties":{"from":{"type":"string","format":"date","description":"First UTC date of the range."},"to":{"type":"string","format":"date","description":"Last UTC date of the range."},"groupBy":{"type":"array","items":{"type":"string","enum":["day","engine","key"]},"description":"The splits applied, always in the order day, engine, key."},"credits":{"type":"number","description":"Credits charged over the range, with up to two decimals. The sum of every row."},"tasks":{"type":"integer","description":"Tasks charged over the range."},"rows":{"type":"array","items":{"$ref":"#/components/schemas/UsageRow"}}}}}},"UsageRow":{"type":"object","required":["credits","tasks"],"description":"Credits and tasks charged for one combination of the splits you chose. A row has the fields of those splits and no others. Rows run oldest day first, then by engine, then API keys by name, then the other sources. A combination with no charge has no row.","properties":{"date":{"type":"string","format":"date","description":"The UTC date. Present with `day`."},"taskType":{"type":["string","null"],"description":"The engine that was charged. Present with `engine`. `null` for older charges that were recorded without an engine."},"source":{"type":["string","null"],"enum":["api","monitor","playground","dashboard",null],"description":"Where the spend came from. Present with `key`. `api` is a task sent with an API key. `monitor` is a monitor's runs, `playground` the dashboard Playground and `dashboard` other dashboard actions. `null` when the charge names none of them."},"apiKey":{"type":["object","null"],"description":"The API key that sent the tasks. Present with `key`; `null` unless `source` is `api`.","required":["id","keyPrefix","name","subAccountId"],"properties":{"id":{"type":"string","format":"uuid"},"keyPrefix":{"type":["string","null"],"description":"The first characters of the key, as the dashboard shows them. `null` for a key that no longer exists."},"name":{"type":["string","null"],"description":"The name you gave the key. `null` for a key that no longer exists."},"subAccountId":{"type":["string","null"],"format":"uuid","description":"The sub-account that owns the key, or `null` for your own keys."}}},"credits":{"type":"number","description":"Credits charged, with up to two decimals."},"tasks":{"type":"integer","description":"Tasks charged."}}},"QueueStatus":{"type":"object","required":["success","queuedTasks","processingTasks","priorityBreakdown","concurrency"],"properties":{"success":{"type":"boolean","const":true},"queuedTasks":{"type":"integer","description":"Your tasks waiting for an engine, with your sub-accounts' tasks."},"processingTasks":{"type":"integer","description":"Your tasks an engine is working on, with your sub-accounts' tasks."},"priorityBreakdown":{"type":"array","description":"The queued tasks by the `priority` they were submitted with, highest first. Priority does not guarantee the order tasks run in.","items":{"type":"object","required":["priority","count"],"properties":{"priority":{"type":"integer"},"count":{"type":"integer"}}}},"concurrency":{"type":"object","required":["used","max"],"description":"The limit on queued and processing tasks together.","properties":{"used":{"type":"integer","description":"`queuedTasks` plus `processingTasks`."},"max":{"type":"integer","description":"What your plan allows, or your contract when it sets another number. `max - used` is how many more tasks you can submit now."}}}}},"AsyncResponse":{"type":"object","required":["success","task","credits"],"properties":{"success":{"type":"boolean","const":true},"task":{"$ref":"#/components/schemas/TaskMeta"},"credits":{"$ref":"#/components/schemas/Credits"}}},"TaskResponse":{"type":"object","required":["success","task","credits"],"allOf":[{"if":{"properties":{"task":{"properties":{"taskType":{"const":"COMMERCE_SERP"}},"required":["taskType"]}},"required":["task"]},"then":{"properties":{"response":{"$ref":"#/components/schemas/CommerceSerpResult"}}}},{"if":{"properties":{"task":{"properties":{"taskType":{"const":"COMMERCE_PRODUCT"}},"required":["taskType"]}},"required":["task"]},"then":{"properties":{"response":{"$ref":"#/components/schemas/CommerceProductResult"}}}}],"properties":{"success":{"type":"boolean","const":true},"task":{"$ref":"#/components/schemas/TaskMeta"},"credits":{"$ref":"#/components/schemas/Credits"},"response":{"type":"object","description":"The engine-specific result. Absent until the task is terminal. See the Engines guide for per-engine shapes. With `include.citationAnalysis`, answer results also carry `citationAnalysis` (see Include). CITATION_ANALYSIS returns CitationAnalysisResult; see the Citation Analysis guide. PROMPT_RESEARCH returns PromptResearchResult; see the Prompt Research guide. GEO_SCORE returns GeoScoreResult; see the GEO Score guide. Answer engines with `include.analysis` add `analysis` (AnswerAnalysis).","additionalProperties":true},"error":{"type":"string","description":"Present when `task.status` is `FAILED`. A plain string — not the `{code, message, timestamp}` object used by request-level errors."}}},"AsyncBatchResult":{"type":"object","required":["success","summary","results"],"properties":{"success":{"type":"boolean"},"summary":{"type":"object","required":["total","succeeded","failed"],"properties":{"total":{"type":"integer"},"succeeded":{"type":"integer"},"failed":{"type":"integer"}}},"results":{"type":"array","description":"Positionally 1:1 with the submitted array, via `index`.","items":{"type":"object","required":["success","index"],"properties":{"success":{"type":"boolean"},"index":{"type":"integer","description":"Index into the request array."},"task":{"$ref":"#/components/schemas/TaskMeta"},"credits":{"$ref":"#/components/schemas/Credits"},"error":{"$ref":"#/components/schemas/ErrorDetail"}}}}}},"ErrorDetail":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","description":"Stable, safe to branch on. See the Errors guide for the full list."},"message":{"type":"string","description":"For humans. May change."},"details":{"description":"Context for the error. An array of `{field, message}` on most `VALIDATION_ERROR`s; an object elsewhere (for example `{id}` on `RESOURCE_NOT_FOUND`, `retryAfterSec` on 429 and 503 codes). Omitted when there is nothing to add.","oneOf":[{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}}}},{"type":"object","additionalProperties":true}]},"timestamp":{"type":"string","format":"date-time"}}},"ErrorResponse":{"type":"object","required":["success","error"],"properties":{"success":{"type":"boolean","const":false},"error":{"$ref":"#/components/schemas/ErrorDetail"}}},"WebhookBody":{"type":"object","description":"POSTed to `webhook.url` when a task reaches a terminal state. Five attempts in all: retries follow after about 2, 4, 8 and 16 minutes, with a 30 s timeout per attempt.","required":["task","credits","response"],"properties":{"task":{"$ref":"#/components/schemas/TaskMeta"},"credits":{"$ref":"#/components/schemas/Credits"},"response":{"type":"object","description":"The engine result on success, or `{ \"error\": \"<reason>\" }` on failure.","additionalProperties":true}}},"CitationAnalysisCitation":{"type":"object","required":["url"],"additionalProperties":false,"properties":{"url":{"type":"string","format":"uri","maxLength":2048},"body":{"type":"string","maxLength":300000,"description":"Exact source snapshot (markdown or plain text). A supplied body is analyzed as-is and never replaced with a current fetch. Strongly recommended: a cited page we cannot read is reported on that source with error and empty paragraphs. Max 300,000 characters per citation; the whole request body is at most 1 MiB."},"title":{"type":"string","description":"Optional source title; kept for existing integrations."},"kind":{"type":"string","enum":["inline","panel"],"description":"How the answer cites this source: inline (linked from the answer text) or panel (listed as a source only). Auto-detected from the answer’s links when omitted."},"cited":{"type":"boolean","default":true,"description":"false marks a page the engine retrieved (a search result) but did not cite. At least one citation must be cited; at most 100 cited and 50 non-cited."},"position":{"type":"integer","minimum":1,"description":"The engine's own rank for the page in its search results."},"query":{"type":"string","maxLength":500,"description":"The search that found the page; added to queries if missing."},"citedText":{"type":"array","maxItems":20,"items":{"type":"string","maxLength":2000},"description":"Passages the engine itself reported citing."},"publishedAt":{"type":"string","maxLength":64,"description":"Publication date as the engine reported it."}}},"CitationAnalysisRequest":{"type":"object","properties":{"taskId":{"type":"string","maxLength":128,"description":"Instead of answer and citations: the id of one of your COMPLETED answer tasks that is still readable through GET /v1/async/task/{id}. Its answer Markdown (text when there is none) becomes answer, and its cited URLs become citations in the engine's order (first 100, at most 10 discussion threads). Its prompt, country and engine are used unless you send them. Sending taskId together with answer or citations is a 400; an unknown or expired id is a 404. For CHATGPT the task's searches become queries and every retrieved page becomes a citation with cited, position, citedText, publishedAt and query; for Google AI Overview, organic results outside the overview's sources are added as non-cited pages. include.citationAnalysis fills them the same way."},"answer":{"type":"string","minLength":1,"maxLength":200000,"description":"Required unless taskId is sent. The AI answer to analyze, as raw markdown (keep link fragments intact). 1-200,000 characters at submission; the analysis itself has a smaller per-answer processing budget, and an answer above it fails explicitly instead of being truncated."},"citations":{"type":"array","maxItems":150,"items":{"$ref":"#/components/schemas/CitationAnalysisCitation"},"description":"Required unless taskId is sent. Cited pages (1-100, at least one) plus optional retrieved-but-not-cited pages (cited: false, at most 50); at most 10 discussion-thread URLs. Total HTTP body <=1 MiB."},"prompt":{"type":"string","maxLength":200000,"description":"The original question."},"country":{"type":"string"},"engine":{"type":"string","maxLength":64,"description":"The AI engine that produced the answer."},"brand":{"type":"string","maxLength":200,"description":"Your brand name. With it, the result adds visibility and actions."},"competitors":{"type":"array","maxItems":25,"items":{"type":"string","maxLength":200},"description":"Up to 25 competitor names, reported in brands with role competitor."},"brandDomains":{"type":"array","maxItems":10,"items":{"type":"string","maxLength":253,"pattern":"^[a-zA-Z0-9.-]{1,253}$"},"description":"Hostnames of your brand's own sites (e.g. coway.com): bare hostnames without scheme or path. Requires brand; sent without it, the request is rejected with 422. Without brandDomains, a host whose name contains the brand name counts as the brand's own site."},"brandAliases":{"type":"array","maxItems":10,"items":{"type":"string","maxLength":200},"description":"Other names of your brand (product lines, local spellings). Requires brand; sent without it, the request is rejected with 422."},"queries":{"type":"array","maxItems":20,"items":{"type":"string","maxLength":500},"description":"Searches the engine ran for this answer."},"idempotencyKey":{"type":"string"},"priority":{"type":"integer"},"webhook":{"type":"object","properties":{"url":{"type":"string","format":"uri"}},"required":["url"]}},"anyOf":[{"required":["answer","citations"]},{"required":["taskId"]}]},"CitationAnalysisResult":{"type":"object","description":"Version 4 result. Results stored before v4 keep their earlier shape, without version. Correspondence and presence, not causation.","required":["version","answer","queries","sources","brands","links","visibility","actions","insights"],"additionalProperties":false,"properties":{"version":{"type":"integer","enum":[4]},"answer":{"type":"string","description":"The submitted answer, unchanged. links[].answerRanges and brands[].answerRanges are UTF-16 offsets (start inclusive, end exclusive) into exactly this string. Link ranges always span whole extracted units of it; brand ranges are the exact name spans."},"queries":{"type":"array","description":"Searches the engine ran. Empty when the engine exposed none and none were sent.","items":{"type":"object","required":["id","text","sourceIds"],"additionalProperties":false,"properties":{"id":{"type":"string"},"text":{"type":"string"},"sourceIds":{"type":"array","items":{"type":"string"},"description":"sources[].id values this search found."}}}},"sources":{"type":"array","description":"One entry per page, cited or retrieved.","items":{"type":"object","required":["id","url","domain","channel","cited","position","queryIds","publishedAt","citedText","brandIds","own","paragraphs"],"additionalProperties":false,"properties":{"id":{"type":"string","description":"Opaque source id, unique within the result."},"url":{"type":"string","format":"uri"},"domain":{"type":"string"},"channel":{"type":"string","enum":["own","brand","editorial","retailer","review_platform","community","video","social","blog_platform","reference"],"description":"Who controls the page, judged from its host: own (the target's site; exactly when own is true), brand (another named brand's own site), editorial (a publisher; also any unrecognized host), retailer, review_platform, community, video, social, blog_platform, reference (encyclopedia or wiki; never an action target)."},"cited":{"type":"boolean","description":"true when the answer cites the page; false when the engine only retrieved it."},"position":{"type":["integer","null"],"description":"The engine's own rank for the page; null when it gave none."},"queryIds":{"type":"array","items":{"type":"string"},"description":"queries[].id values of the searches that found the page."},"publishedAt":{"type":["string","null"],"description":"Publication date as the engine reported it; null when unknown."},"citedText":{"type":"array","items":{"type":"string"},"description":"Passages the engine itself reported citing; empty when none."},"brandIds":{"type":"array","items":{"type":"string"},"description":"brands[].id values named on the readable page, its title or citedText."},"own":{"type":"boolean","description":"true when the page is on the target brand's own site; channel is then own."},"paragraphs":{"type":"array","description":"The paragraphs of a cited page included in the result, each with a globally unique id. Always empty for non-cited pages and for pages that could not be read (then error is present). A paragraph can be included with no link.","items":{"type":"object","required":["id","text"],"additionalProperties":false,"properties":{"id":{"type":"string","description":"Globally unique across the result; links[].paragraphId points here."},"text":{"type":"string"}}}},"error":{"type":"string","description":"Present only when the page could not be read; paragraphs is then empty, and the string is a short reason for that source. An unread page leaves uncertainty — it is not a finding that the source has no relationship to the answer."}}}},"brands":{"type":"array","description":"The target brand, competitors and other brands the answer names.","items":{"type":"object","required":["id","name","role","rank","answerRanges","citedSourceIds","retrievedSourceIds","ownSourceIds"],"additionalProperties":false,"properties":{"id":{"type":"string"},"name":{"type":"string"},"role":{"type":"string","enum":["target","competitor","answer"],"description":"target = the request brand; competitor = a request competitor; answer = another brand the answer names."},"rank":{"type":["integer","null"],"description":"Order of the brand's first answerRanges span in the answer, 1-based without gaps; null when not mentioned."},"answerRanges":{"type":"array","description":"The exact spans where the answer names the brand or one of its product names: UTF-16 offsets, start inclusive, end exclusive, so slice(start, end) returns the name as written. Case-insensitive, whole words except in scripts written without spaces; includes headings and table cells, never inside link URLs or image markup. Unlike links[].answerRanges, these are not whole answer units.","items":{"type":"object","required":["start","end"],"additionalProperties":false,"properties":{"start":{"type":"integer","minimum":0},"end":{"type":"integer","minimum":0}}}},"citedSourceIds":{"type":"array","items":{"type":"string"},"description":"Cited sources whose page names the brand."},"retrievedSourceIds":{"type":"array","items":{"type":"string"},"description":"Non-cited sources whose page names the brand."},"ownSourceIds":{"type":"array","items":{"type":"string"},"description":"Sources on the brand's own site; target only, empty for others."}}}},"links":{"type":"array","description":"One relationship per paragraph. Every paragraphId names a paragraph that exists in sources[].paragraphs[].id, and every answer range is an exact slice of answer.","items":{"type":"object","required":["id","paragraphId","answerRanges","explanation"],"additionalProperties":false,"properties":{"id":{"type":"string"},"paragraphId":{"type":"string","description":"Matches a sources[].paragraphs[].id in this result."},"answerRanges":{"type":"array","description":"The parts of answer this paragraph corresponds to. JavaScript UTF-16 offsets, start inclusive, end exclusive. Each range is a whole semantic unit of the answer (sentence, list item or table cell), never a free-form excerpt, so slice(start, end) returns exactly that unit. The same answer text is not repeated within one link.","items":{"type":"object","required":["start","end"],"additionalProperties":false,"properties":{"start":{"type":"integer","minimum":0},"end":{"type":"integer","minimum":0}}}},"explanation":{"type":"string","description":"A short sentence describing what the paragraph states about that part of the answer."}}}},"visibility":{"type":["object","null"],"description":"null when no brand was sent.","required":["brandId","stage","rank","answerBrands"],"additionalProperties":false,"properties":{"brandId":{"type":"string","description":"The brands[].id with role target."},"stage":{"type":"string","enum":["mentioned","on_cited_page","on_retrieved_page","not_found"],"description":"mentioned: the answer names the target. on_cited_page: not named, but a cited page names it. on_retrieved_page: only non-cited retrieved pages name it. not_found: no page that was read names it (not a claim about the web)."},"rank":{"type":["integer","null"]},"answerBrands":{"type":"integer","minimum":0,"description":"How many brands the answer names."}}},"actions":{"type":"array","description":"Prioritized suggestions grounded in the listed pages, not guarantees. Empty when visibility is null. Ordered owned, then platform, then outreach. Never fake or undisclosed reviews, posing as an independent reviewer, buying links, or editing pages the brand does not own.","items":{"type":"object","required":["id","type","control","priority","summary","steps","sourceIds","brandIds","queryIds","linkIds"],"additionalProperties":false,"properties":{"id":{"type":"string"},"type":{"type":"string","enum":["improve_page","publish_page","post_on_platform","pitch_publisher"],"description":"improve_page (owned): one per own site whose own pages were retrieved but not cited, or cited while the answer does not name the target. publish_page (owned): for a search where no own page was cited, a brief for a new page on the brand's own site modelled on the cited pages. post_on_platform (platform): a cited page on a retailer, review platform, community, video, social or blog platform (someone else's page) names rivals but not the target; the action is the brand's own listing, profile, answer or post there from its own account, never a request to the platform or page owner; at most one per domain. pitch_publisher (outreach): a cited editorial page names rivals but not the target, or names the target while the answer does not; only the publisher can change it."},"control":{"type":"string","enum":["owned","platform","outreach"],"description":"Fixed by type: owned for improve_page and publish_page, platform for post_on_platform, outreach for pitch_publisher."},"priority":{"type":"integer","minimum":1,"description":"1 = do first; unique and consecutive; owned actions first, then platform, then outreach."},"summary":{"type":"string","description":"One sentence in the answer's language."},"steps":{"type":"array","minItems":1,"maxItems":5,"items":{"type":"string"},"description":"One to five concrete steps in the answer's language."},"sourceIds":{"type":"array","items":{"type":"string"},"description":"improve_page: up to 3 of the brand's pages on that site, not-cited first. publish_page: the cited pages to model. post_on_platform: the cited page on that platform. pitch_publisher: the page to pitch."},"brandIds":{"type":"array","items":{"type":"string"},"description":"The target, or the rival brands those pages name."},"queryIds":{"type":"array","items":{"type":"string"},"description":"Related searches."},"linkIds":{"type":"array","items":{"type":"string"},"description":"Links from those sources: what the answer took from them."}}}},"insights":{"type":"array","description":"Up to four short summaries of what the pages add up to: cited channels, the format, freshness or criteria the cited pages share, the answer's brand order against cited coverage, and where the target sits. Correspondence, not advice. sourceIds and linkIds only name entries in this result, and at least one of them is non-empty.","items":{"type":"object","required":["summary","sourceIds","linkIds"],"additionalProperties":false,"properties":{"summary":{"type":"string"},"sourceIds":{"type":"array","description":"Ids of the sources the summary rests on.","items":{"type":"string"}},"linkIds":{"type":"array","description":"Ids of the links the summary rests on.","items":{"type":"string"}}}},"maxItems":4}}},"MonitorEngine":{"type":"string","description":"An engine a monitor can schedule: the prompt surfaces sold to customers plus the deprecated NAVER alias. GOOGLE_AIO and GOOGLE_AIMODE are accepted as input aliases and echoed as GOOGLE and AIMODE. CITATION_ANALYSIS is an analysis task, not a prompt surface, and cannot be scheduled on a monitor.","enum":["CHATGPT","GEMINI","PERPLEXITY","GOOGLE","AIMODE","NAVER_AI_BRIEF","NAVER_AI_TAB","NAVER"]},"MonitorCompetitor":{"type":"object","description":"A brand scored alongside yours in the same answers. The name is always one of its own aliases, so a bare name matches reliably.","required":["name"],"properties":{"name":{"type":"string","maxLength":80,"description":"__you__ is reserved for your own brand."},"aliases":{"type":"array","maxItems":20,"items":{"type":"string"},"description":"Other spellings of the same brand. The name is added automatically."},"source":{"type":"string","enum":["user","auto"],"readOnly":true,"description":"user: you added it. auto: the weekly competitor read found it in the monitor's own answers. Entries you send with source auto are ignored, so a monitor read and written back keeps its found competitors."},"domain":{"type":"string","readOnly":true,"description":"The competitor's site, when the competitor read found one."}}},"Monitor":{"type":"object","description":"One named prompt set in one market, and the schedule that repeats it.","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","maxLength":80},"mode":{"type":"string","enum":["BRAND","CATEGORY"],"default":"BRAND","description":"What the monitor measures, fixed at creation. BRAND follows one brand and its competitors. CATEGORY follows a market with no brand of its own and ranks every brand the answers name."},"category":{"type":["string","null"],"maxLength":80,"description":"CATEGORY only: the market the monitor follows. null on a BRAND monitor."},"promptTopics":{"type":"object","additionalProperties":{"type":"string","maxLength":60},"description":"CATEGORY only: each prompt's sub-field, keyed by the prompt's exact text. A prompt without an entry covers the whole category. Empty on a BRAND monitor."},"engines":{"type":"array","items":{"$ref":"#/components/schemas/MonitorEngine"},"description":"Each engine that joins a run submits one task per prompt, per point and per sample."},"prompts":{"type":"array","items":{"type":"string","maxLength":2000},"description":"The exact question texts the monitor asks, stored verbatim. Scored rows are keyed by this text, so editing the list does not rewrite history."},"aliases":{"type":"array","maxItems":20,"items":{"type":"string"},"description":"Spellings of your brand matched against the answer text. Matching ignores case and character width: Latin-script names match whole words, and Korean, Japanese, Chinese and Thai names match anywhere in the text. Empty on a CATEGORY monitor."},"domains":{"type":"array","maxItems":20,"items":{"type":"string"},"description":"Hosts matched against the answer citations; a registered domain also matches its subdomains. Empty means citations are not tracked and cited is always false. Always empty on a CATEGORY monitor."},"country":{"type":"string","description":"Two-letter country code passed to every task. It selects the market the engines answer for; it does not translate the prompts."},"intervalHours":{"type":"integer","minimum":1,"maximum":168,"description":"Hours between scheduled runs."},"enabled":{"type":"boolean","description":"false pauses the schedule without deleting the monitor or its history."},"alertBelowPct":{"type":["integer","null"],"minimum":1,"maximum":100,"description":"Email when the recent mention rate falls below this percentage. null means the alert is off, and it is always null on a CATEGORY monitor."},"competitors":{"type":"array","maxItems":50,"description":"BRAND: up to 10 you added, then up to 15 the competitor read found in this monitor's answers. CATEGORY: up to 25 you added, then up to 25 the read found, and the whole list is the roster the report ranks.","items":{"$ref":"#/components/schemas/MonitorCompetitor"}},"competitorsReadAt":{"type":["string","null"],"format":"date-time","description":"When the competitor read last ran. It runs once the first run is in, then every 7 days when the monitor has run since. null until then."},"nextRunAt":{"type":"string","format":"date-time","description":"When the next run becomes due. A run is admitted by the next sweep tick, not at this instant."},"lastRunAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"location":{"oneOf":[{"$ref":"#/components/schemas/LocationPoint"},{"type":"null"}],"description":"Ask every task from this point (ChatGPT, Gemini, Google AI Overview and AI Mode only). Exclusive with grid; setting one clears the other, null asks for the whole country."},"grid":{"oneOf":[{"$ref":"#/components/schemas/GridSpec"},{"type":"null"}],"description":"Ask every prompt and engine from each point of this grid. Each engine in a run adds prompts × size² × its samples tasks; the first run, which every engine joins, must stay within the account's tasksPerRun limit."},"engineSettings":{"allOf":[{"$ref":"#/components/schemas/MonitorEngineSettings"}]},"webhookUrl":{"type":["string","null"],"description":"Where change events are posted, or null when they are off."},"analysis":{"type":"boolean","description":"Ask every task for `include.analysis` with this monitor's names, domains and competitors. 2 extra credits per analyzed task."}}},"MonitorStats":{"type":"object","description":"Scored answers in a window, plus how many named the brand and how many cited a registered domain. These are counts, not rates; a rate is these numbers divided, and is published as null when the denominator is zero.","required":["runs","mentioned","cited"],"properties":{"runs":{"type":"integer"},"mentioned":{"type":"integer"},"cited":{"type":"integer"}}},"MonitorLeader":{"type":"object","description":"The brand a set of answers named most. mentionRate divides by sampleSize, the answers scored while the brand was on the monitor's list.","properties":{"name":{"type":"string"},"mentions":{"type":"integer","description":"Answers that named the brand."},"sampleSize":{"type":"integer","description":"Answers scored while the brand was on the monitor's list."},"mentionRate":{"type":["number","null"],"description":"100 x mentions / sampleSize."}}},"MonitorPause":{"type":"object","description":"A period the schedule was paused. resumedAt is null while the monitor is still paused.","required":["pausedAt","resumedAt"],"properties":{"pausedAt":{"type":"string","format":"date-time"},"resumedAt":{"type":["string","null"],"format":"date-time"}}},"MonitorRate":{"type":"object","description":"Counts plus their percentages. mentionRate is 100 x mentioned / runs; a null rate means there were no scored answers in the sample, which is not the same as a rate of zero.","required":["runs","mentioned","cited","competitorOnly","mentionRate","citationRate","competitorOnlyRate"],"properties":{"runs":{"type":"integer","description":"Scored answers in the sample. Completed observations that produced no answer are counted here as not mentioned; failed tasks are not counted at all."},"mentioned":{"type":"integer"},"cited":{"type":"integer"},"competitorOnly":{"type":"integer","description":"Answers that named a configured competitor while your brand was absent. This is the competitive-gap count, and the unit of opportunities."},"mentionRate":{"type":["number","null"]},"citationRate":{"type":["number","null"]},"competitorOnlyRate":{"type":["number","null"]}}},"MonitorHealth":{"type":"object","description":"Run health for tasks that are still individually visible, which covers the latest run at every cadence this product sells. A failed task writes no scored row, so this is the only place failures appear - a report that silently stopped growing looks identical to one whose engine broke.","required":["completed","failed","pending","topError"],"properties":{"completed":{"type":"integer"},"failed":{"type":"integer"},"pending":{"type":"integer","description":"Queued or still processing."},"topError":{"type":["string","null"],"description":"The most common failure code in this window, or null."}}},"StringList":{"description":"An array of strings, or a single newline-separated string (the shape a dashboard textarea submits). Entries are trimmed, blank lines dropped and duplicates removed.","oneOf":[{"type":"array","items":{"type":"string"}},{"type":"string"}]},"CreateMonitorRequest":{"type":"object","required":["name","engines","prompts","intervalHours"],"properties":{"name":{"type":"string","maxLength":80},"mode":{"type":"string","enum":["BRAND","CATEGORY"],"default":"BRAND","description":"BRAND follows one brand and its competitors and needs aliases. CATEGORY follows a market with no brand of its own and needs category. Fixed at creation."},"category":{"type":"string","minLength":1,"maxLength":80,"description":"Required with mode CATEGORY and refused with BRAND: the market the monitor follows, named as a buyer would name it."},"promptTopics":{"type":"object","additionalProperties":{"type":"string","minLength":1,"maxLength":60},"description":"CATEGORY only: maps a prompt (its exact text from prompts) to its sub-field. Up to 30 distinct sub-fields; names that differ only by case are one. A prompt without an entry covers the whole category."},"engines":{"allOf":[{"$ref":"#/components/schemas/StringList"}],"description":"One or more schedulable engines, at most 12. Cannot be empty.","items":{"$ref":"#/components/schemas/MonitorEngine"}},"prompts":{"allOf":[{"$ref":"#/components/schemas/StringList"}],"description":"1 to 100 prompts (1,000 on a contract account; capabilities reports yours), each at most 2,000 characters. Do not name your own brand in a prompt: it would always be mentioned and would measure nothing.","items":{"type":"string","maxLength":2000}},"aliases":{"allOf":[{"$ref":"#/components/schemas/StringList"}],"description":"Required for a BRAND monitor: 1 to 20 brand spellings. A CATEGORY monitor has no brand of its own and refuses a value. Short aliases that collide with ordinary words match often - that is the caller's call to make.","items":{"type":"string"}},"domains":{"allOf":[{"$ref":"#/components/schemas/StringList"}],"description":"Up to 20 hosts to track citations for. Defaults to empty (no citation tracking). A CATEGORY monitor refuses a value.","items":{"type":"string"}},"country":{"type":"string","default":"US","description":"Two-letter code. Default US."},"competitors":{"type":["array","string"],"description":"Optional. Competitors are found in the monitor's answers after its first run, so list only brands you want tracked from the start or that the read missed: up to 10 on a BRAND monitor and up to 25 on a CATEGORY monitor, where the list is the roster the report ranks, each an object with a name, or the dashboard's one-per-line form Name: alias, alias. Competitor names are matched in the same pass as your own aliases.","items":{"$ref":"#/components/schemas/MonitorCompetitor"}},"alertBelowPct":{"type":["integer","null"],"minimum":1,"maximum":100,"description":"Optional mention-rate alert threshold. Omit or null for no alert. A CATEGORY monitor refuses a value."},"intervalHours":{"type":"integer","minimum":1,"maximum":168},"location":{"oneOf":[{"$ref":"#/components/schemas/LocationPoint"},{"type":"null"}],"description":"Ask every task from this point (ChatGPT, Gemini, Google AI Overview and AI Mode only). Exclusive with grid; setting one clears the other, null asks for the whole country."},"grid":{"oneOf":[{"$ref":"#/components/schemas/GridSpec"},{"type":"null"}],"description":"Ask every prompt and engine from each point of this grid. Each engine in a run adds prompts × size² × its samples tasks; the first run, which every engine joins, must stay within the account's tasksPerRun limit."},"engineSettings":{"allOf":[{"$ref":"#/components/schemas/MonitorEngineSettings"}]},"webhookUrl":{"type":["string","null"],"format":"uri","description":"HTTPS URL on a public host that receives change events (see the monitorEvent webhook). Set it with an API key: events are signed with the key that sets it, so sending it again with a new key moves the signing to that key. null turns events off."},"analysis":{"type":"boolean","default":false,"description":"Ask every task for `include.analysis` with this monitor's names, domains and competitors. 2 extra credits per analyzed task."}}},"UpdateMonitorRequest":{"type":"object","description":"Any subset of the definition. Fields that are absent are left unchanged; changing intervalHours or re-enabling restarts the schedule clock from now.","properties":{"name":{"type":"string","maxLength":80},"mode":{"type":"string","enum":["BRAND","CATEGORY"],"description":"Accepted only when it equals the monitor's own mode: a monitor's mode is fixed at creation, and a different value is a 400."},"category":{"type":"string","minLength":1,"maxLength":80,"description":"CATEGORY monitors only."},"promptTopics":{"type":"object","additionalProperties":{"type":"string","maxLength":60},"description":"CATEGORY monitors only. Each key must be a prompt the monitor holds after the edit; removing a prompt removes its entry."},"engines":{"allOf":[{"$ref":"#/components/schemas/StringList"}],"items":{"$ref":"#/components/schemas/MonitorEngine"}},"prompts":{"allOf":[{"$ref":"#/components/schemas/StringList"}],"items":{"type":"string","maxLength":2000}},"aliases":{"allOf":[{"$ref":"#/components/schemas/StringList"}],"items":{"type":"string"}},"domains":{"allOf":[{"$ref":"#/components/schemas/StringList"}],"items":{"type":"string"}},"country":{"type":"string"},"competitors":{"type":["array","string"],"items":{"$ref":"#/components/schemas/MonitorCompetitor"}},"alertBelowPct":{"type":["integer","null"],"minimum":1,"maximum":100},"intervalHours":{"type":"integer","minimum":1,"maximum":168},"enabled":{"type":"boolean","description":"Pause or resume. Resuming restarts the clock from now."},"location":{"oneOf":[{"$ref":"#/components/schemas/LocationPoint"},{"type":"null"}],"description":"Ask every task from this point (ChatGPT, Gemini, Google AI Overview and AI Mode only). Exclusive with grid; setting one clears the other, null asks for the whole country."},"grid":{"oneOf":[{"$ref":"#/components/schemas/GridSpec"},{"type":"null"}],"description":"Ask every prompt and engine from each point of this grid. Each engine in a run adds prompts × size² × its samples tasks; the first run, which every engine joins, must stay within the account's tasksPerRun limit."},"engineSettings":{"allOf":[{"$ref":"#/components/schemas/MonitorEngineSettings"}]},"webhookUrl":{"type":["string","null"],"format":"uri","description":"HTTPS URL on a public host that receives change events (see the monitorEvent webhook). Set it with an API key: events are signed with the key that sets it, so sending it again with a new key moves the signing to that key. null turns events off."},"analysis":{"type":"boolean","default":false,"description":"Ask every task for `include.analysis` with this monitor's names, domains and competitors. 2 extra credits per analyzed task."}}},"MonitorListResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","required":["monitors","windowDays"],"properties":{"monitors":{"type":"array","items":{"allOf":[{"$ref":"#/components/schemas/Monitor"},{"type":"object","required":["stats"],"properties":{"stats":{"$ref":"#/components/schemas/MonitorStats"},"leader":{"oneOf":[{"$ref":"#/components/schemas/MonitorLeader"},{"type":"null"}],"description":"CATEGORY monitors only: the brand the answers named most in the 30-day window, or null when none was named yet."}}}]}},"windowDays":{"type":"integer","const":30,"description":"Every rollup in this response covers the last 30 days, independently of any window you pass elsewhere."}}}}},"MonitorResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","required":["monitor"],"properties":{"monitor":{"$ref":"#/components/schemas/Monitor"}}}}},"MonitorDeleteResponse":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"deleted":{"type":"boolean","const":true}}}}},"MonitorRunResponse":{"type":"object","description":"Accepted. The run is due now; its tasks appear as the sweep admits them. Poll GET /v1/monitors/{id}/analytics and its health block to watch the answers arrive.","properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"queued":{"type":"boolean","const":true}}}}},"MonitorResearchResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","required":["task","credits"],"properties":{"task":{"$ref":"#/components/schemas/TaskMeta"},"credits":{"$ref":"#/components/schemas/Credits"},"replayed":{"type":"boolean","description":"true when the request repeated an earlier one and points at the task it already made."}}}}},"MonitorSuggestRequest":{"type":"object","description":"The brand facts already known at setup. At least one of name or aliases is required.","properties":{"name":{"type":"string"},"aliases":{"$ref":"#/components/schemas/StringList"},"domains":{"$ref":"#/components/schemas/StringList"},"competitors":{"type":["array","string"],"description":"Names add topical context; only the name part of a Name: alias line is used.","items":{"type":"string"}},"country":{"type":"string","default":"US"}}},"MonitorSuggestResponse":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"prompts":{"type":"array","maxItems":12,"items":{"type":"string"},"description":"Candidate prompts, none of which names the brand. Nothing was stored."}}}}},"MonitorCapabilitiesResponse":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"engines":{"type":"array","description":"Engines a monitor may schedule, in preference order, with the credits one task on each costs.","items":{"type":"object","properties":{"engine":{"$ref":"#/components/schemas/MonitorEngine"},"creditsPerTask":{"type":"number"}}}},"limits":{"type":"object","description":"This account's numeric limits, each enforced on create and update. A contract account has platform-scale monitors, tasksPerRun and prompts.","properties":{"monitors":{"type":"integer"},"tasksPerRun":{"type":"integer","description":"Ceiling on one run's tasks: prompts × points × samples, summed over engines."},"prompts":{"type":"integer"},"competitors":{"type":"integer","description":"Competitor brands you may list on a BRAND monitor. roster has the limit for each mode."},"roster":{"type":"object","description":"Brands per mode: typed is what you may list, auto is what the weekly read may add beside them.","properties":{"BRAND":{"type":"object","properties":{"typed":{"type":"integer"},"auto":{"type":"integer"}}},"CATEGORY":{"type":"object","properties":{"typed":{"type":"integer"},"auto":{"type":"integer"}}}}},"categoryCharacters":{"type":"integer","description":"Longest category name."},"subFields":{"type":"integer","description":"Sub-fields a CATEGORY monitor may hold."},"subFieldCharacters":{"type":"integer","description":"Longest sub-field name."},"aliases":{"type":"integer"},"domains":{"type":"integer"},"intervalHours":{"type":"object","properties":{"min":{"type":"integer"},"max":{"type":"integer"}}},"analyticsDays":{"type":"integer","description":"Maximum report window in days."},"resultPageSize":{"type":"integer"},"evidencePageSize":{"type":"integer"},"sourcePageSize":{"type":"integer"},"answerTextCharacters":{"type":"integer","description":"Retained answer characters; longer answers are cut and marked with a trailing ellipsis."},"samples":{"type":"integer","description":"Most answers per prompt and engine in one run (engineSettings.samples)."}}},"modes":{"type":"object","description":"One line on what each monitor mode measures.","properties":{"BRAND":{"type":"string"},"CATEGORY":{"type":"string"}}},"metrics":{"type":"object","description":"The published definition of every metric a report returns, as prose. Read it before labelling a dashboard panel.","properties":{"mentionRate":{"type":"string"},"citationRate":{"type":"string"},"shareOfVoice":{"type":"string"},"opportunity":{"type":"string"},"noAnswer":{"type":"string"},"comparison":{"type":"string"},"categoryMentionRate":{"type":"string"},"categoryRank":{"type":"string"},"categoryNamedRate":{"type":"string"}}},"workflow":{"type":"array","items":{"type":"string"},"description":"The endpoints in the order a report is assembled."},"schedule":{"type":"object","properties":{"starts":{"type":"string","const":"on_create"},"cost":{"type":"string","description":"Credits one run spends."},"monthlyEstimate":{"type":"string"},"pausedRunAllowed":{"type":"boolean","const":false,"description":"A paused monitor cannot be run on demand."},"engineIntervals":{"type":"string","description":"How engineSettings.intervalHours spaces an engine's runs."}}},"events":{"type":"object","description":"The change events a monitor with a webhookUrl sends.","properties":{"types":{"type":"array","items":{"type":"string","enum":["monitor.mention.started","monitor.mention.stopped","monitor.competitor.ahead","monitor.source.first_cited"]}},"answersPerState":{"type":"integer","description":"Answers a prompt's state is read over; the first full window is the baseline and sends nothing."},"delivery":{"type":"string"}}},"analysisCreditsPerTask":{"type":"number","description":"Credits `analysis: true` adds to each task, charged only when the analysis succeeds."}}}}},"MonitorAnalyticsWindow":{"type":"object","description":"The window the report covers, half-open in UTC, and the equal interval immediately before it. previousUntil is always this window's since.","properties":{"since":{"type":"string","format":"date-time"},"until":{"type":"string","format":"date-time"},"previousSince":{"type":"string","format":"date-time"},"previousUntil":{"type":"string","format":"date-time"},"timezone":{"type":"string","const":"UTC","description":"Days, including the partial-day flags, are UTC days."},"bounds":{"type":"string","const":"[since, until)"}}},"MonitorAnalyticsFilters":{"type":"object","description":"The filters that were applied to every section, echoed back resolved: engine is the canonical id even when an alias was passed, and null means no filter.","properties":{"engine":{"type":["string","null"]},"prompt":{"type":["string","null"]}}},"MonitorChanges":{"type":"object","description":"Percentage-point change against the previous interval. Both fields are null when the comparison is not sound - no answers in one of the periods (insufficient_periods), rows scored before scoring context existed (legacy_scoring_unknown), or a definition that changed between the periods (scoring_definitions_changed). See quality.comparable.","properties":{"mentionRatePp":{"type":["number","null"]},"citationRatePp":{"type":["number","null"]}}},"MonitorEngineRate":{"allOf":[{"$ref":"#/components/schemas/MonitorRate"},{"type":"object","properties":{"engine":{"$ref":"#/components/schemas/MonitorEngine"}}}],"description":"One engine's rates inside the current window, so a weak engine is visible without reading the time series."},"MonitorSeriesPoint":{"allOf":[{"$ref":"#/components/schemas/MonitorRate"},{"type":"object","properties":{"day":{"type":"string","description":"UTC day, YYYY-MM-DD."},"engine":{"$ref":"#/components/schemas/MonitorEngine"},"partial":{"type":"boolean","description":"True when this UTC day is only partly inside the window. A partial day's lower count is arithmetic, not a decline, so dashboards should mark it instead of plotting it as a drop."}}}]},"MonitorBrand":{"type":"object","description":"One tracked brand in the current window. __you__ is your own brand. mentionRate divides by this brand's own sampleSize, not by the window total: a competitor is measured only over the answers that were scored while it was on the monitor, so adding one today cannot be diluted by rows collected before it existed. shareOfVoice is 100 x mentions / every tracked brand mention in the window, so the shares of one window add to 100; it is a share of the answers you collected for these prompts, not a share of any market. previous* are null when the comparison is not sound.","required":["name","mentions","sampleSize","mentionRate","shareOfVoice","previousMentionRate","previousShareOfVoice","configured"],"properties":{"name":{"type":"string"},"mentions":{"type":"integer"},"sampleSize":{"type":"integer","description":"Scored answers this brand was measured over: every scored answer for __you__, and for a competitor only those scored while it was in the monitor's roster. 0 means the brand is configured but nothing in this window measured it, which is why its mentionRate is null instead of 0%."},"mentionRate":{"type":["number","null"],"description":"100 x mentions / sampleSize. null when sampleSize is 0: a brand with no qualifying answers has no rate, and reporting one as 0% would read as a real disappearance."},"shareOfVoice":{"type":["number","null"],"description":"null when this brand has neither a qualifying sample nor a mention."},"previousMentionRate":{"type":["number","null"],"description":"null when the comparison is withheld, or when the brand had no qualifying sample in the previous interval either."},"previousShareOfVoice":{"type":["number","null"],"description":"null when the comparison is withheld, or when the previous interval had no qualifying sample for this brand."},"configured":{"type":"boolean","description":"True for your brand and for any competitor currently configured on the monitor; false for a name that is no longer configured but still appears in this window's history."}}},"MonitorVoicePoint":{"type":"object","description":"One brand on one UTC day of the current window. mentionRate divides by that day's answers that actually measured the brand, so a competitor added mid-window has a null rate on the days before it was configured.","properties":{"day":{"type":"string"},"name":{"type":"string"},"mentions":{"type":"integer"},"runs":{"type":"integer"},"mentionRate":{"type":["number","null"]},"shareOfVoice":{"type":["number","null"]}}},"MonitorCell":{"type":"object","description":"One prompt x engine cell in the current window, with the same cell in the previous interval for comparison. Each task id is the latest answer of its kind: evidenceTaskId named a competitor and not your brand, mentionTaskId named your brand, latestTaskId is any answer.","properties":{"prompt":{"type":"string"},"engine":{"$ref":"#/components/schemas/MonitorEngine"},"runs":{"type":"integer"},"mentioned":{"type":"integer"},"cited":{"type":"integer"},"competitorOnly":{"type":"integer"},"mentionRate":{"type":["number","null"]},"citationRate":{"type":["number","null"]},"competitorOnlyRate":{"type":["number","null"]},"previous":{"$ref":"#/components/schemas/MonitorRate"},"mentionRateChangePp":{"type":["number","null"]},"topCompetitor":{"type":["string","null"],"description":"The competitor mentioned most often in this cell, or null if none was."},"topCompetitorRate":{"type":["number","null"]},"evidenceTaskId":{"type":["string","null"],"description":"The latest answer that named a competitor and not your brand. Safe to request from GET /v1/monitors/{id}/answers/{taskId}."},"mentionTaskId":{"type":["string","null"],"description":"The latest answer that named your brand, or null if none did."},"latestTaskId":{"type":["string","null"],"description":"The latest answer of the cell."}}},"MonitorPromptRow":{"allOf":[{"$ref":"#/components/schemas/MonitorRate"},{"type":"object","properties":{"prompt":{"type":"string"},"previous":{"$ref":"#/components/schemas/MonitorRate"},"engines":{"type":"array","items":{"$ref":"#/components/schemas/MonitorCell"}}}}],"description":"One prompt's totals in the current window, weakest mention rate first, with its per-engine cells."},"MonitorQuality":{"type":"object","description":"What the sample is made of, and what cannot be said with it. Read this before presenting a number: it is where a withheld comparison, a partial UTC day, or a low sample is declared instead of silently rendered.","properties":{"comparable":{"type":"boolean","description":"False when changes is withheld."},"comparisonReason":{"type":["string","null"],"enum":["insufficient_periods","legacy_scoring_unknown","scoring_definitions_changed",null],"description":"Why a comparison is unavailable: no answers in one period, rows scored before scoring context was stored, or a scoring definition that changed between the periods."},"scoringVersions":{"type":"array","items":{"type":"string"},"description":"The scoring definitions present in the rows read, or legacy for rows scored before versions were stored."},"noAnswerObservations":{"type":"integer","description":"Completed observations whose answer text was empty. They count as not mentioned and stay in the denominator."},"unknownObservations":{"type":"integer","description":"Rows whose observation state predates scoring context (scoringContext null)."},"noAnswerIncluded":{"type":"boolean","const":true},"historicalFailures":{"type":"null","description":"Always null: a failed task writes no scored row and is never reconstructed as an absence. Failures are reported in health instead, for the tasks that are still visible."},"sampleSize":{"type":"integer","description":"Scored answers in the current window."},"previousSampleSize":{"type":"integer"},"configuredCells":{"type":"integer","description":"prompts x engines for this monitor, after the filters."},"observedCells":{"type":"integer","description":"Configured cells that actually produced scored answers in this window."},"missingCells":{"type":"integer"},"lowSample":{"type":"boolean","description":"True below 30 scored answers, where a rate is still noise."},"partialDays":{"type":"array","items":{"type":"string"},"description":"UTC days only partly inside the window."},"denominator":{"type":"string","const":"scored_answers","description":"What mentionRate and citationRate divide by."},"shareOfVoiceDenominator":{"type":"string","const":"tracked_brand_mentions","description":"What brands[].shareOfVoice divides by, so it is not the answer count."},"trackedBrandMentions":{"type":"integer"},"answerTextLimit":{"type":"integer","const":8000},"scoring":{"type":"string","const":"collection_time_definitions","description":"Historical rows keep the definitions they were scored with; changing aliases or competitors does not rewrite them."},"failedTasksIncluded":{"type":"boolean","const":false}}},"MonitorBrandAnalytics":{"type":"object","description":"The report of a BRAND monitor (data.monitor.mode is BRAND, the default): your brand against its competitors.","required":["monitor","window","filters","stats","previous","changes","engineRates","series","brands","voiceSeries","prompts","opportunities","pauses","quality","health","healthScope"],"properties":{"monitor":{"$ref":"#/components/schemas/Monitor"},"window":{"$ref":"#/components/schemas/MonitorAnalyticsWindow"},"filters":{"$ref":"#/components/schemas/MonitorAnalyticsFilters"},"stats":{"$ref":"#/components/schemas/MonitorRate"},"previous":{"$ref":"#/components/schemas/MonitorRate"},"changes":{"$ref":"#/components/schemas/MonitorChanges"},"engineRates":{"type":"array","items":{"$ref":"#/components/schemas/MonitorEngineRate"}},"series":{"type":"array","items":{"$ref":"#/components/schemas/MonitorSeriesPoint"}},"brands":{"type":"array","items":{"$ref":"#/components/schemas/MonitorBrand"},"description":"Your brand and every tracked competitor, most mentions first. Each carries its own sampleSize, so a rate is always read against the answers it was measured over, and a newly configured competitor with no qualifying answers reports a null rate rather than 0%."},"voiceSeries":{"type":"array","items":{"$ref":"#/components/schemas/MonitorVoicePoint"}},"prompts":{"type":"array","items":{"$ref":"#/components/schemas/MonitorPromptRow"},"description":"Per-prompt totals, weakest mention rate first."},"opportunities":{"type":"array","items":{"$ref":"#/components/schemas/MonitorCell"},"description":"Cells where a competitor was named and your brand was not, most misses first. The next content decision usually comes from the top of this list."},"pauses":{"type":"array","items":{"$ref":"#/components/schemas/MonitorPause"},"description":"The pauses that overlap the window, oldest first and capped at 200, so a chart can stop at them."},"quality":{"$ref":"#/components/schemas/MonitorQuality"},"health":{"$ref":"#/components/schemas/MonitorHealth"},"healthScope":{"type":"string","const":"recent_visible_tasks","description":"health is a separate recent-tasks scope on purpose: it is never part of the report denominator."}}},"MonitorCategoryStats":{"type":"object","description":"Scored answers in a period and how many of them named at least one tracked brand. namedRate is 100 x named / runs, or null when there were no scored answers.","required":["runs","named","namedRate"],"properties":{"runs":{"type":"integer"},"named":{"type":"integer","description":"Answers that name at least one brand on the monitor's list."},"namedRate":{"type":["number","null"]}}},"MonitorCategoryBrand":{"type":"object","description":"One tracked brand in the current window. mentionRate divides by this brand's own sampleSize, the answers scored while it was on the monitor's list, so adding a brand today cannot be diluted by answers collected before it existed. shareOfVoice is 100 x mentions / every tracked brand mention in the window, so the shares of one window add to 100.","required":["name","rank","mentions","sampleSize","mentionRate","shareOfVoice","previousMentionRate","previousShareOfVoice","changePp","configured"],"properties":{"name":{"type":"string"},"rank":{"type":["integer","null"],"description":"Place among the brands the answers named, by the number of answers naming the brand. null when no answer in the window named it."},"mentions":{"type":"integer","description":"Answers that named the brand."},"sampleSize":{"type":"integer","description":"Answers scored while the brand was on the monitor's list: the denominator of mentionRate."},"mentionRate":{"type":["number","null"],"description":"100 x mentions / sampleSize. null when sampleSize is 0."},"shareOfVoice":{"type":["number","null"],"description":"null when no tracked brand was named in the window."},"previousMentionRate":{"type":["number","null"],"description":"null when the comparison is withheld or the brand had no sample in the previous interval."},"previousShareOfVoice":{"type":["number","null"]},"changePp":{"type":["number","null"],"description":"mentionRate minus previousMentionRate, in points. null when either is null."},"configured":{"type":"boolean","description":"True while the brand is on the monitor's list; false for a brand that left the list but was named in this window."}}},"MonitorCategoryReport":{"type":"object","description":"A category monitor's ranking. Every figure counts answers that name a brand, so it says which brands the engines name most for the monitor's questions.","required":["name","brands","topics","engines","series","prompts"],"properties":{"name":{"type":["string","null"],"description":"The category the monitor follows."},"brands":{"type":"array","items":{"$ref":"#/components/schemas/MonitorCategoryBrand"},"description":"Every brand on the monitor's list and every other brand the answers named in the window, most answers first. A brand no answer named has rank null."},"topics":{"type":"array","description":"One row per sub-field, in the order the monitor asks them. topic null is the prompts that cover the whole category.","items":{"type":"object","properties":{"topic":{"type":["string","null"]},"prompts":{"type":"integer"},"runs":{"type":"integer"},"named":{"type":"integer"},"namedRate":{"type":["number","null"]},"leaders":{"type":"array","maxItems":3,"items":{"$ref":"#/components/schemas/MonitorLeader"},"description":"The brands named most in this sub-field."}}}},"engines":{"type":"array","description":"One row per engine that produced answers in the window.","items":{"type":"object","properties":{"engine":{"$ref":"#/components/schemas/MonitorEngine"},"runs":{"type":"integer"},"named":{"type":"integer"},"namedRate":{"type":["number","null"]},"leaders":{"type":"array","maxItems":3,"items":{"$ref":"#/components/schemas/MonitorLeader"},"description":"The brands this engine names most."}}}},"series":{"type":"array","description":"Per UTC day, the five leading brands on the monitor's list.","items":{"type":"object","properties":{"day":{"type":"string","description":"UTC day, YYYY-MM-DD."},"name":{"type":"string"},"mentions":{"type":"integer"},"sampleSize":{"type":"integer"},"runs":{"type":"integer","description":"All scored answers of the day."},"mentionRate":{"type":["number","null"]},"partial":{"type":"boolean","description":"True when this UTC day is only partly inside the window."}}}},"prompts":{"type":"array","description":"One row per prompt, in the order the monitor asks them, then prompts that were removed but still have answers in the window.","items":{"type":"object","properties":{"prompt":{"type":"string"},"topic":{"type":["string","null"]},"retired":{"type":"boolean","description":"True for a prompt the monitor no longer asks."},"runs":{"type":"integer"},"named":{"type":"integer"},"namedRate":{"type":["number","null"]},"leaders":{"type":"array","maxItems":3,"items":{"$ref":"#/components/schemas/MonitorLeader"}},"engines":{"type":"array","items":{"type":"object","properties":{"engine":{"$ref":"#/components/schemas/MonitorEngine"},"runs":{"type":"integer"},"named":{"type":"integer"},"evidenceTaskId":{"type":["string","null"],"description":"An answer of this cell that named a brand, to open with GET /v1/monitors/{id}/answers/{taskId}."}}}}}}}}},"MonitorCategoryAnalytics":{"type":"object","description":"The report of a CATEGORY monitor (data.monitor.mode is CATEGORY). It has no brand of its own, so it ranks the brands the answers name. Every rate is 0 to 100, and the window, filters and quality rules are the brand report's. The brand sections (engineRates, series, brands, voiceSeries, prompts, opportunities) are replaced by category.","required":["monitor","window","filters","stats","previous","changes","category","pauses","quality","health","healthScope"],"properties":{"monitor":{"$ref":"#/components/schemas/Monitor"},"window":{"$ref":"#/components/schemas/MonitorAnalyticsWindow"},"filters":{"$ref":"#/components/schemas/MonitorAnalyticsFilters"},"stats":{"$ref":"#/components/schemas/MonitorCategoryStats"},"previous":{"$ref":"#/components/schemas/MonitorCategoryStats"},"changes":{"type":"object","description":"Percentage-point change of namedRate against the previous interval. null when the comparison is not sound: see quality.comparable.","properties":{"namedRatePp":{"type":["number","null"]}}},"category":{"$ref":"#/components/schemas/MonitorCategoryReport"},"pauses":{"type":"array","items":{"$ref":"#/components/schemas/MonitorPause"},"description":"The pauses that overlap the window, oldest first and capped at 200, so a chart can stop at them."},"quality":{"$ref":"#/components/schemas/MonitorQuality"},"health":{"$ref":"#/components/schemas/MonitorHealth"},"healthScope":{"type":"string","const":"recent_visible_tasks"}}},"MonitorAnalyticsResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"description":"The shape follows data.monitor.mode: BRAND (the default) returns the brand report, CATEGORY returns the category report.","oneOf":[{"$ref":"#/components/schemas/MonitorBrandAnalytics"},{"$ref":"#/components/schemas/MonitorCategoryAnalytics"}]}}},"MonitorSourceRow":{"type":"object","description":"One cited domain or page in the window. citations and prompts count distinct answers, so a page cited three times in one answer counts once.","properties":{"key":{"type":"string","description":"The grouping value: a host for domain, the full URL for page. Opaque - use it as an identity, not as a URL."},"domain":{"type":"string","description":"Host with www stripped and any credentials or port removed."},"url":{"type":["string","null"],"description":"Present when groupBy=page, null when groupBy=domain."},"label":{"type":["string","null"],"description":"The title the engine gave, when it gave one."},"citations":{"type":"integer","description":"Distinct answers in the window citing this key."},"prompts":{"type":"integer","description":"Distinct prompts among those answers."},"own":{"type":"boolean","description":"True when this host is one of the monitor's registered domains (or a subdomain of one)."},"evidenceTaskId":{"type":"string","description":"A task id citing this key, safe to request from GET /v1/monitors/{id}/answers/{taskId}."}}},"MonitorSourcesResponse":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"results":{"type":"array","items":{"$ref":"#/components/schemas/MonitorSourceRow"}},"nextCursor":{"type":["string","null"],"description":"Pass back unchanged as cursor; null means this was the last page."},"groupBy":{"type":"string","enum":["domain","page"]},"window":{"type":"object","description":"The resolved half-open window, echoed so a client can pin the same cohort across pages.","properties":{"since":{"type":"string","format":"date-time"},"until":{"type":"string","format":"date-time"}}},"filters":{"$ref":"#/components/schemas/MonitorAnalyticsFilters"},"counting":{"type":"string","const":"distinct_answers","description":"How citations and prompts are counted."},"ownership":{"type":"string","const":"current_monitor_domains","description":"own is decided against the monitor's domains as configured now, not as they were at collection time."}}}}},"MonitorCitationSource":{"type":"object","properties":{"key":{"type":"string","description":"The domain, or the normalized page URL."},"domain":{"type":"string"},"label":{"type":"string","description":"The domain, or the page's cited title (falls back to its URL)."},"kind":{"type":"string","enum":["owned","editorial","review_media","pr_wire","institution","reviews","commerce","social","blog","community","video","brand","content","other"]},"owned":{"type":"boolean","description":"Matches one of the monitor's domains as configured now."},"citations":{"type":"integer"},"answers":{"type":"integer","description":"Distinct answers citing this source."},"prompts":{"type":"integer","description":"Distinct prompts whose answers cite this source."},"daily":{"type":"array","description":"Only days with at least one citation.","items":{"type":"object","properties":{"day":{"type":"string","format":"date","description":"UTC day, YYYY-MM-DD."},"citations":{"type":"integer"}}}}}},"MonitorCitationsResponse":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"totals":{"type":"object","properties":{"answers":{"type":"integer"},"citedAnswers":{"type":"integer"},"citations":{"type":"integer"},"ownedCitations":{"type":"integer"}}},"days":{"type":"array","description":"One entry per UTC day with at least one answer. A day with answers but no citations has citations 0; a day with no answers is absent.","items":{"type":"object","properties":{"day":{"type":"string","format":"date","description":"UTC day, YYYY-MM-DD."},"answers":{"type":"integer"},"citations":{"type":"integer"},"ownedCitations":{"type":"integer"}}}},"domains":{"type":"array","items":{"$ref":"#/components/schemas/MonitorCitationSource"}},"pages":{"type":"array","items":{"$ref":"#/components/schemas/MonitorCitationSource"}},"types":{"type":"array","description":"Across all sources in the window, ignoring kind, q and offset.","items":{"type":"object","properties":{"key":{"type":"string","enum":["owned","editorial","review_media","pr_wire","institution","reviews","commerce","social","blog","community","video","brand","content","other"]},"citations":{"type":"integer"},"domains":{"type":"integer"}}}},"pagination":{"type":"object","properties":{"offset":{"type":"integer"},"limit":{"type":"integer","const":20},"totalDomains":{"type":"integer"},"totalPages":{"type":"integer"}}},"windowDays":{"type":"integer","enum":[7,30,90]},"engine":{"type":"string","description":"The engine filter, or all."},"prompt":{"type":["string","null"]},"since":{"type":"string","format":"date-time"},"until":{"type":"string","format":"date-time"}}}}},"MonitorStoredSource":{"type":"object","description":"One citation as the engine gave it. The order is the engine's, and the list is deduplicated by URL.","properties":{"url":{"type":"string"},"label":{"type":["string","null"]},"position":{"type":"integer","description":"1-based place in the engine's citation list. It is not a ranking of your brand."}}},"MonitorScoringContext":{"type":["object","null"],"description":"The definition this answer was scored with, stored at completion. null on rows scored before this was recorded - they are the reason a comparison can be withheld as legacy_scoring_unknown.","properties":{"aliases":{"type":"array","items":{"type":"string"}},"domains":{"type":"array","items":{"type":"string"}},"competitors":{"type":"array","items":{"$ref":"#/components/schemas/MonitorCompetitor"}},"country":{"type":"string"},"version":{"type":"string","description":"Stable hash of the definition above. Two rows with the same version are comparable; a different one means the question changed."},"scoredAt":{"type":"string","format":"date-time"},"answerPresent":{"type":"boolean","description":"False for a completed observation whose answer was empty."},"evidenceTruncated":{"type":"boolean","description":"True when the retained answer text was cut at the character limit."}}},"MonitorResultRow":{"type":"object","description":"One scored answer. position is the character offset of the earliest alias hit inside the answer text - a prominence proxy, not a rank, and null when the brand was absent (which position 0 would otherwise spell).","properties":{"id":{"type":"string","format":"uuid","description":"Scored-row id. The pagination cursor is built from it, so do not sort by it as if it were time."},"taskId":{"type":"string"},"engine":{"$ref":"#/components/schemas/MonitorEngine"},"prompt":{"type":"string"},"mentioned":{"type":"boolean"},"cited":{"type":"boolean"},"position":{"type":["integer","null"]},"ranAt":{"type":"string","description":"ISO instant with microsecond precision, in UTC. Used verbatim in the cursor."},"competitorHits":{"type":"array","items":{"type":"string"},"description":"Names of this monitor's competitors that the answer mentioned, empty when none were."},"answerText":{"type":["string","null"],"description":"Only with includeEvidence. The retained answer, markdown when the engine gave markdown, at most 8,000 characters with a trailing ellipsis when it was cut, and null when the engine returned no text."},"sources":{"type":"array","items":{"$ref":"#/components/schemas/MonitorStoredSource"},"description":"Only with includeEvidence."},"scoringContext":{"$ref":"#/components/schemas/MonitorScoringContext","description":"Only with includeEvidence. null on rows scored before it was recorded."}}},"MonitorResultsResponse":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"monitor":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}}},"since":{"type":"string","format":"date-time"},"until":{"type":"string","format":"date-time"},"filters":{"type":"object","description":"The filters that were applied, echoed back with null for the ones that were not.","properties":{"engine":{"type":["string","null"]},"prompt":{"type":["string","null"]},"mentioned":{"type":["boolean","null"]},"cited":{"type":["boolean","null"]},"competitor":{"type":["string","null"]}}},"truncated":{"type":"boolean","description":"True when more rows matched than this page returned."},"nextCursor":{"type":["string","null"],"description":"Pass back unchanged as cursor with the SAME since and until. Changing the window mid-pagination can skip or repeat rows."},"results":{"type":"array","items":{"$ref":"#/components/schemas/MonitorResultRow"}}}}}},"MonitorAnswerRow":{"type":"object","properties":{"taskId":{"type":"string"},"engine":{"$ref":"#/components/schemas/MonitorEngine"},"prompt":{"type":"string"},"mentioned":{"type":"boolean"},"cited":{"type":"boolean"},"position":{"type":["integer","null"],"description":"Character offset of the earliest alias hit, or null when the brand was absent."},"ranAt":{"type":"string","format":"date-time"},"answerText":{"type":["string","null"],"description":"At most 8,000 characters, cut with a trailing ellipsis; null when the engine returned no answer text."},"sources":{"type":"array","items":{"$ref":"#/components/schemas/MonitorStoredSource"}},"competitorHits":{"type":"array","items":{"type":"string"}},"scoringContext":{"$ref":"#/components/schemas/MonitorScoringContext"},"analysis":{"oneOf":[{"$ref":"#/components/schemas/AnswerAnalysis"},{"type":"null"}],"description":"The task's analysis when the monitor asked for it; null otherwise."}}},"MonitorAnswerResponse":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"answer":{"$ref":"#/components/schemas/MonitorAnswerRow"},"display":{"type":["object","null"],"description":"Display fields of the original task response, read back from the task rather than from the 8,000-character scored excerpt. Only the fields the engine returned are present: markdown, text, sources, searchQueries, layout, map, products, shoppingCards, inlineProducts, citationPills, videos and sponsored, with a Google AI Overview's under aioverview. null once the task is no longer stored, or when it carries none of these fields."},"mode":{"type":"string","enum":["BRAND","CATEGORY"],"description":"The monitor's mode. On a CATEGORY monitor aliases is empty and competitors is the whole list of brands the report ranks."},"aliases":{"type":"array","items":{"type":"string"},"description":"The aliases this row was scored with when that is known, otherwise the monitor's current aliases. The reader needs them to see what matched."},"competitors":{"type":"array","items":{"$ref":"#/components/schemas/MonitorCompetitor"}},"scoringKnown":{"type":"boolean","description":"False when this row predates stored scoring context; the answer is intact but the definition shown is the monitor's current one."},"evidenceTruncated":{"type":["boolean","null"],"description":"null when scoringKnown is false."}}}}},"MonitorDetailResponse":{"type":"object","description":"Legacy period detail. stats, previous, engineRates, series, shareOfVoice and voiceSeries share the window from days; cells is all-time and unfiltered; topDomains and topPages are capped at 12 and 20 rows with no cursor. shareOfVoice here is the original answer-penetration view: each brand's mentions are counted against the answers collected, so the numbers can add up to more than 100. Use GET /v1/monitors/{id}/analytics for the report contract with the true share denominator.","properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"monitor":{"$ref":"#/components/schemas/Monitor"},"stats":{"$ref":"#/components/schemas/MonitorStats"},"previous":{"$ref":"#/components/schemas/MonitorStats"},"engineRates":{"type":"array","items":{"$ref":"#/components/schemas/MonitorStats"}},"topDomains":{"type":"array","maxItems":12,"items":{"type":"object","properties":{"domain":{"type":"string"},"citations":{"type":"integer"},"prompts":{"type":"integer"},"own":{"type":"boolean"}}}},"topPages":{"type":"array","maxItems":20,"items":{"type":"object","properties":{"url":{"type":"string"},"domain":{"type":"string"},"label":{"type":["string","null"]},"citations":{"type":"integer"},"prompts":{"type":"integer"},"own":{"type":"boolean"}}}},"shareOfVoice":{"type":"object","description":"Answer penetration, the legacy view: mentions per brand over the window's answers. A brand mentioned in every answer scores 100 while several brands in one answer all count, so the brands do not sum to 100.","properties":{"runs":{"type":"integer"},"brands":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"__you__ is your own brand."},"mentions":{"type":"integer"}}}}}},"voiceSeries":{"type":"array","items":{"type":"object","properties":{"day":{"type":"string","format":"date-time"},"name":{"type":"string"},"mentions":{"type":"integer"}}}},"health":{"$ref":"#/components/schemas/MonitorHealth"},"series":{"type":"array","items":{"type":"object","properties":{"day":{"type":"string","format":"date-time"},"engine":{"$ref":"#/components/schemas/MonitorEngine"},"runs":{"type":"integer"},"mentioned":{"type":"integer"},"cited":{"type":"integer"}}}},"cells":{"type":"array","description":"The latest scored answer per prompt and engine, across all time, with no window or engine filter. Each taskId can be read through GET /v1/monitors/{id}/answers/{taskId}.","items":{"type":"object","properties":{"prompt":{"type":"string"},"engine":{"$ref":"#/components/schemas/MonitorEngine"},"mentioned":{"type":"boolean"},"cited":{"type":"boolean"},"position":{"type":["integer","null"]},"ranAt":{"type":"string","format":"date-time"},"taskId":{"type":"string"}}}},"windowDays":{"type":"integer","enum":[7,30,90]}}}}},"MonitorPromptResponse":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"monitor":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"engines":{"type":"array","items":{"$ref":"#/components/schemas/MonitorEngine"}},"aliases":{"type":"array","items":{"type":"string"}}}},"prompt":{"type":"string"},"series":{"type":"array","items":{"type":"object","properties":{"day":{"type":"string","format":"date-time"},"engine":{"$ref":"#/components/schemas/MonitorEngine"},"runs":{"type":"integer"},"mentioned":{"type":"integer"},"cited":{"type":"integer"}}}},"topDomains":{"type":"array","maxItems":12,"items":{"type":"object","properties":{"domain":{"type":"string"},"citations":{"type":"integer"},"prompts":{"type":"integer"},"own":{"type":"boolean"}}}},"topPages":{"type":"array","maxItems":20,"items":{"type":"object","properties":{"url":{"type":"string"},"domain":{"type":"string"},"label":{"type":["string","null"]},"citations":{"type":"integer"},"prompts":{"type":"integer"},"own":{"type":"boolean"}}}},"results":{"type":"array","maxItems":100,"items":{"type":"object","properties":{"taskId":{"type":"string"},"engine":{"$ref":"#/components/schemas/MonitorEngine"},"prompt":{"type":"string"},"mentioned":{"type":"boolean"},"cited":{"type":"boolean"},"position":{"type":["integer","null"]},"ranAt":{"type":"string","format":"date-time"},"competitorHits":{"type":"array","items":{"type":"string"}}}}},"windowDays":{"type":"integer","enum":[7,30,90]}}}}},"MonitorDelivery":{"type":"object","description":"One alert delivery attempt record from the notification outbox.","properties":{"id":{"type":"string"},"status":{"type":"string","description":"Outbox state, typically pending, sent or failed."},"attempts":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"sentAt":{"type":["string","null"],"format":"date-time"},"lastError":{"type":["string","null"]},"payload":{"type":"object","description":"The message that was queued: monitor, rate, threshold, window and run count."}}},"MonitorAlertsResponse":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"alertBelowPct":{"type":["integer","null"]},"armed":{"type":"boolean","description":"True when the next crossing will send mail. The alert fires on the crossing and re-arms after the rate recovers, so a monitor parked below its threshold sends one email, not one per run."},"deliveries":{"type":"array","maxItems":20,"items":{"$ref":"#/components/schemas/MonitorDelivery"}}}}}},"PromptResearchPrompt":{"type":"object","required":["prompt","topic","persona","intent","funnelStage","brandMentions","monthlySearchVolume","demandShare"],"additionalProperties":false,"properties":{"prompt":{"type":"string","description":"The question, in the market's language, as a person would ask an AI assistant. Never names a brand."},"topic":{"type":"string","description":"The broader subtopic the need belongs to. Prompts on one subtopic share the label; topics[] sums them."},"persona":{"type":["string","null"],"description":"Who is asking, when the searches name an audience, condition or situation (men, parents of babies, oily skin); null otherwise."},"intent":{"type":"string","enum":["informational","commercial","transactional"],"description":"informational (how, what, why), commercial (choosing, comparing, recommending) or transactional (price, where to buy)."},"funnelStage":{"type":"string","enum":["awareness","consideration","purchase","post_purchase"],"description":"awareness (learning about the need or category), consideration (comparing options), purchase (price, where to buy) or post_purchase (using what they bought)."},"brandMentions":{"type":"string","enum":["likely","sometimes","rarely"],"description":"Whether a good answer to the prompt names brands, products or providers: likely (it recommends, ranks or compares options), sometimes (it explains, usually with example products) or rarely (it explains a concept, method or usage without products)."},"fit":{"type":"string","enum":["core","related","none"],"description":"Present only when the request had brandDescription. core: the description says the brand offers what the prompt asks for. related: anything the description does not mention. none: the description itself rules it out; such a prompt is never in monitorSet."},"monthlySearchVolume":{"type":"integer","minimum":0,"description":"Monthly searches for the need behind the prompt."},"demandShare":{"type":"number","minimum":0,"maximum":1,"description":"This prompt's share of the demand behind every usable prompt found, to four decimals. Compares needs within one seed; not a share of AI conversations."},"rank":{"type":"integer","minimum":1,"description":"Only in monitorSet.prompts[]: the order to add the prompt to a monitor, from 1."}}},"PromptResearchMonitorSetPrompt":{"description":"A prompts[] entry with its rank in the set.","allOf":[{"$ref":"#/components/schemas/PromptResearchPrompt"},{"required":["rank"]}]},"PromptResearchMonitorSet":{"type":"object","required":["prompts","coverage"],"additionalProperties":false,"properties":{"prompts":{"type":"array","description":"The prompts a monitor should track, in the order to add them, chosen from every usable prompt found, including those past limit, favoring prompts many people ask whose answers give a monitor something to measure, spread across topics and personas. At most monitorSize entries; prompts with fit none are never chosen. The first n entries are the set for monitorSize n.","items":{"$ref":"#/components/schemas/PromptResearchMonitorSetPrompt"}},"coverage":{"type":"object","required":["demandShare","topics","personas"],"additionalProperties":false,"properties":{"demandShare":{"type":"number","minimum":0,"maximum":1,"description":"The chosen prompts' share of the searches behind every usable prompt found."},"topics":{"type":"object","required":["covered","total"],"additionalProperties":false,"description":"How many of the topics found the set covers.","properties":{"covered":{"type":"integer","minimum":0},"total":{"type":"integer","minimum":0}}},"personas":{"type":"object","required":["covered","total"],"additionalProperties":false,"description":"How many of the personas found the set covers.","properties":{"covered":{"type":"integer","minimum":0},"total":{"type":"integer","minimum":0}}}}}}},"PromptResearchBrand":{"type":"object","required":["brand","monthlySearchVolume"],"additionalProperties":false,"properties":{"brand":{"type":"string"},"monthlySearchVolume":{"type":"integer","minimum":0,"description":"Monthly searches for the brand in this space."}}},"PromptResearchTopic":{"type":"object","required":["topic","monthlySearchVolume","demandShare","promptCount"],"additionalProperties":false,"properties":{"topic":{"type":"string"},"monthlySearchVolume":{"type":"integer","minimum":0,"description":"The sum of its prompts' monthlySearchVolume."},"demandShare":{"type":"number","minimum":0,"maximum":1,"description":"Share of the demand behind every usable prompt found."},"promptCount":{"type":"integer","minimum":1}}},"PromptResearchPersona":{"type":"object","required":["persona","monthlySearchVolume","demandShare","promptCount"],"additionalProperties":false,"properties":{"persona":{"type":"string"},"monthlySearchVolume":{"type":"integer","minimum":0,"description":"The sum of its prompts' monthlySearchVolume."},"demandShare":{"type":"number","minimum":0,"maximum":1,"description":"Share of the demand behind every usable prompt found."},"promptCount":{"type":"integer","minimum":1}}},"PromptResearchRequest":{"type":"object","required":["seed","country"],"additionalProperties":false,"properties":{"seed":{"type":"string","minLength":1,"maxLength":30,"description":"The topic: letters, digits and single spaces, such as sunscreen. A short product or category term works best; a sentence finds nothing."},"country":{"type":"string","enum":["KR","US"],"description":"Market: KR (South Korea) or US (United States). Any other value is a 422 REGION_UNSUPPORTED."},"limit":{"type":"integer","minimum":1,"maximum":50,"default":20,"description":"Prompts to return."},"exclude":{"type":"array","maxItems":20,"items":{"type":"string","minLength":1,"maxLength":30},"description":"Terms to leave out, such as a subtopic you do not want. A prompt containing one is left out. Put your own brand in brand."},"monitorSize":{"type":"integer","minimum":1,"maximum":50,"default":20,"description":"Prompts in monitorSet."},"monitorEngines":{"type":"array","minItems":1,"maxItems":12,"items":{"$ref":"#/components/schemas/MonitorEngine"},"description":"The engines your monitor will run. A monitor runs at most 200 prompt × engine tasks at a time, so monitorSize × the number of engines above 200 is a 422 VALIDATION_ERROR on monitorSize. It does not change the result."},"brand":{"type":"string","minLength":1,"maxLength":80,"description":"Your brand, with at least two letters or digits; punctuation is allowed. Prompts containing it are left out, as with exclude."},"brandAliases":{"type":"array","maxItems":10,"items":{"type":"string","minLength":1,"maxLength":80},"description":"Other names or spellings of your brand, left out the same way. Requires brand."},"brandDescription":{"type":"string","maxLength":500,"description":"What your brand sells and to whom. Requires brand. Adds fit to every prompt, which monitorSet weighs."},"idempotencyKey":{"type":"string","description":"Optional. Deduplicates submissions; a duplicate is a 409."},"priority":{"type":"integer","minimum":1,"maximum":10,"default":1,"description":"Optional. Echoed in task metadata; values outside 1-10 are clamped. It does not guarantee execution order."},"webhook":{"type":"object","description":"Optional. Omit to collect the result by polling instead.","required":["url"],"properties":{"url":{"type":"string","format":"uri","description":"Receives a POST when the task reaches a terminal state."}}}}},"PromptResearchResult":{"type":"object","required":["seed","country","language","demandSource","seedMonthlySearchVolume","promptsFound","prompts","monitorSet","topics","personas","brands"],"properties":{"seed":{"type":"string"},"country":{"type":"string"},"language":{"type":"string","description":"Language of the prompts: ko for KR, en for US."},"demandSource":{"type":"object","required":["period","fetchedAt"],"properties":{"period":{"type":"string","enum":["last_30_days","monthly_average_last_12_months"],"description":"last_30_days for KR; monthly_average_last_12_months for US."},"fetchedAt":{"type":"string","format":"date-time"}}},"seedMonthlySearchVolume":{"type":["integer","null"],"description":"Monthly searches for the seed itself; null when there is no count for it."},"promptsFound":{"type":"integer","description":"Usable prompts before limit was applied."},"prompts":{"type":"array","description":"Ranked by monthlySearchVolume, highest first; at most limit entries.","items":{"$ref":"#/components/schemas/PromptResearchPrompt"}},"monitorSet":{"$ref":"#/components/schemas/PromptResearchMonitorSet"},"topics":{"type":"array","description":"Demand summed by topic over every usable prompt found, including those past limit, highest first.","items":{"$ref":"#/components/schemas/PromptResearchTopic"}},"personas":{"type":"array","description":"Demand summed by persona over every usable prompt found, highest first. Prompts without a persona are left out.","items":{"$ref":"#/components/schemas/PromptResearchPersona"}},"brands":{"type":"array","description":"Brands, manufacturers and product lines searched in this space. Kept out of prompts because prompts do not name brands.","items":{"$ref":"#/components/schemas/PromptResearchBrand"}}}},"ProductLookupEngine":{"type":"string","description":"An engine a product lookup can ask. GOOGLE is Google AI Overviews and AIMODE is Google AI Mode. NAVER_AI_TAB answers in KR only.","enum":["CHATGPT","GOOGLE","AIMODE","GEMINI","BING_COPILOT","NAVER_AI_TAB"]},"ProductLookupRequest":{"type":"object","required":["product","country"],"properties":{"product":{"type":"string","minLength":1,"maxLength":200,"description":"The product's name, such as belif Moisturizing Eye Bomb. A product page URL or a GTIN is a 400 VALIDATION_ERROR."},"country":{"type":"string","enum":["US","KR"],"description":"Market: US (United States) or KR (South Korea), case-insensitive. Any other value is a 422 REGION_UNSUPPORTED."},"competitors":{"type":"array","maxItems":5,"items":{"type":"string","minLength":1,"maxLength":200},"description":"Other products' names, asked what the product is asked. A name that is the product's or is listed twice is a 400; names that differ only in case, punctuation or spacing are the same name."},"prompts":{"type":"array","maxItems":3,"items":{"type":"string","minLength":1,"maxLength":300},"description":"Shopper prompts, such as best moisturizing eye cream. Each is asked of each engine once, as written."},"engines":{"type":"array","minItems":1,"maxItems":6,"uniqueItems":true,"items":{"$ref":"#/components/schemas/ProductLookupEngine"},"description":"The engines to ask, case-insensitive. Default for US: CHATGPT, GOOGLE, AIMODE and BING_COPILOT. Default for KR: NAVER_AI_TAB, CHATGPT and AIMODE. NAVER_AI_TAB in a US lookup is a 400."},"idempotencyKey":{"type":"string","minLength":1,"maxLength":200,"description":"Names the lookup; without it the server picks a UUID. Sending the lookup again under the same key admits only the asks that are missing."},"priority":{"type":"integer","minimum":1,"maximum":10,"default":1,"description":"Set on every ask. Values outside 1-10 are clamped. It does not guarantee execution order."},"webhook":{"type":"object","description":"Optional. Each ask's task is posted here when it reaches a terminal state.","required":["url"],"properties":{"url":{"type":"string","format":"uri"}}}}},"ProductLookupAsk":{"type":"object","required":["engine","taskType","role","success"],"properties":{"engine":{"$ref":"#/components/schemas/ProductLookupEngine"},"taskType":{"allOf":[{"$ref":"#/components/schemas/ProductLookupEngine"}],"description":"The ask's task type, the same as engine."},"role":{"type":"string","enum":["product","competitor","prompt"],"description":"Whether the ask is about the product, a competitor or a shopper prompt."},"prompt":{"type":"string","description":"The text asked, on CHATGPT, GEMINI and BING_COPILOT."},"query":{"type":"string","description":"The text asked, on GOOGLE, AIMODE and NAVER_AI_TAB."},"success":{"type":"boolean"},"task":{"allOf":[{"$ref":"#/components/schemas/TaskMeta"}],"description":"The ask's task, when it was admitted or already existed."},"error":{"allOf":[{"$ref":"#/components/schemas/ErrorDetail"}],"description":"Why the ask was refused, such as INSUFFICIENT_CREDITS or PLAN_CONCURRENCY_LIMIT."}}},"ProductLookupCreateResponse":{"type":"object","properties":{"success":{"type":"boolean"},"lookup":{"type":"object","properties":{"id":{"type":"string","description":"Your idempotencyKey, or the UUID the server picked."},"product":{"type":"string"},"competitors":{"type":"array","items":{"type":"string"}},"prompts":{"type":"array","items":{"type":"string"}},"country":{"type":"string","enum":["US","KR"]},"engines":{"type":"array","items":{"$ref":"#/components/schemas/ProductLookupEngine"},"description":"The engines asked."}}},"summary":{"type":"object","properties":{"total":{"type":"integer"},"succeeded":{"type":"integer"},"failed":{"type":"integer"}}},"credits":{"type":"object","description":"creditsToCharge adds up the prices of the asks in asks[], held from your balance until each ask finishes. creditsCharged is what those asks have been charged already: 0 on a first submit, and on a resend the charges of the asks that had finished.","properties":{"creditsToCharge":{"type":"number"},"creditsCharged":{"type":"number"}}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/ProductLookupAsk"}}}},"ProductLookupPrice":{"type":"object","properties":{"value":{"type":"number"},"currency":{"type":"string","description":"An ISO 4217 code when the symbol is unambiguous in the market, otherwise the symbol as shown."},"raw":{"type":"string","description":"The price as the engine shows it."}}},"ProductLookupPriceRange":{"type":"object","description":"Single-unit prices in the market's currency (USD for US, KRW for KR). Listings with match.variant are left out.","properties":{"currency":{"type":"string"},"min":{"type":"number"},"max":{"type":"number"}}},"ProductLookupMatch":{"type":"object","description":"Why a listing is judged to be a looked-up product. No engine returns a GTIN, so the judgment uses names.","properties":{"score":{"type":"number","minimum":0,"maximum":1,"description":"Share of the product name's words found in the listing."},"missing":{"type":"array","items":{"type":"string"},"description":"Words of the product name the listing lacks."},"variant":{"type":"array","items":{"type":"string"},"description":"Words that mark another pack or form of the product, such as set, mini, 1+1 or stick."},"accessory":{"type":"array","items":{"type":"string"},"description":"Words that mark a part rather than the product, such as a replacement filter."}}},"ProductLookupRecord":{"type":"object","description":"One merchant's listing of a product as an engine shows it. Only the fields the engine gives are set.","properties":{"position":{"type":"integer","description":"Order in the answer, from 1."},"title":{"type":"string","description":"The product name on the record. On a chatgpt_widget listing, the card's heading, which can be the shop's name."},"merchant":{"type":"string","description":"Who sells it."},"source":{"type":"string","enum":["shopify","google_shopping","merchant_feed","chatgpt_catalog","chatgpt_widget","microsoft_shopping","naver_shopping"],"description":"Where the listing comes from. ChatGPT's product catalog holds shopify, google_shopping and merchant_feed records, and chatgpt_catalog when the record does not say. chatgpt_widget is a shop and price ChatGPT wrote in a widget card without a record. Google AI Overviews, AI Mode and Gemini show google_shopping, Copilot microsoft_shopping and Naver AI Tab naver_shopping."},"url":{"type":"string","description":"The merchant's page when the engine links one, otherwise the engine's own product page."},"price":{"$ref":"#/components/schemas/ProductLookupPrice"},"oldPrice":{"allOf":[{"$ref":"#/components/schemas/ProductLookupPrice"}],"description":"The price before a discount the engine shows."},"available":{"type":"boolean","description":"Whether it is in stock. ChatGPT only."},"rating":{"type":"number","minimum":0,"maximum":5},"reviewCount":{"type":"integer"},"image":{"type":"string"},"description":{"type":"string"},"brand":{"type":"string"},"modelSees":{"type":"object","description":"ChatGPT only: what ChatGPT gave its answering model about the record. A merchant feed record's rating and review count are only here.","properties":{"title":{"type":"string"},"description":{"type":"string"},"rating":{"type":"number"},"reviewCount":{"type":"integer"},"brand":{"type":"string"},"productPage":{"type":"string"}}},"reviews":{"type":"object","description":"The review summary and pros and cons the engine shows.","properties":{"summary":{"type":"string"},"pros":{"type":"array","items":{"type":"string"}},"cons":{"type":"array","items":{"type":"string"}}}},"ids":{"type":"object","additionalProperties":{"type":"string"},"description":"Catalog identifiers that tie records of one product together, such as chatgptProductId and feedId on ChatGPT, googleCatalogId, googleProductGroupId and googleProductDocId on Google engines, bingProductId and bingGroupId on Copilot, and naverProductId on Naver AI Tab."},"pictured":{"type":"string","description":"chatgpt_widget only: what the picture beside the card shows, as the answer searched for it."}}},"ProductLookupListing":{"allOf":[{"$ref":"#/components/schemas/ProductLookupRecord"},{"type":"object","properties":{"ask":{"type":"integer","description":"Which of the engine's asks showed the listing, from 1, in the order of via."},"match":{"$ref":"#/components/schemas/ProductLookupMatch"}}}]},"ProductLookupCitedPage":{"type":"object","properties":{"url":{"type":"string"},"domain":{"type":"string","description":"The host without www. or m."},"title":{"type":"string"},"ask":{"type":"integer","description":"In engines[]: which ask's answer cites the page, from 1."}}},"ProductLookupVia":{"type":"object","description":"One ask and its task.","properties":{"taskType":{"$ref":"#/components/schemas/ProductLookupEngine"},"prompt":{"type":"string","description":"The text asked, on engines that take a prompt."},"query":{"type":"string","description":"The text asked, on engines that take a query."},"taskId":{"type":"string","format":"uuid"},"status":{"$ref":"#/components/schemas/TaskStatus"},"completedAt":{"type":["string","null"],"format":"date-time"},"credits":{"type":"number","description":"What the ask was charged: 0 until it finishes, and 0 when it fails."},"error":{"type":"string","description":"Why the ask failed, starting with its code."}}},"ProductLookupEngineResult":{"type":"object","description":"One engine's answers about one product.","properties":{"engine":{"$ref":"#/components/schemas/ProductLookupEngine"},"status":{"allOf":[{"$ref":"#/components/schemas/TaskStatus"}],"description":"COMPLETED once every ask finished and one completed; FAILED when every ask failed."},"found":{"type":["boolean","null"],"description":"Whether an answer showed a listing of the product, a record or a ChatGPT widget card. null while asks are running and nothing is found yet, and when every ask failed."},"via":{"type":"array","items":{"$ref":"#/components/schemas/ProductLookupVia"},"description":"The engine's asks, in order."},"listings":{"type":"array","items":{"$ref":"#/components/schemas/ProductLookupListing"},"description":"Listings judged to be the product, or another pack or form of it. A listing that two asks showed is listed once, and a widget card with the same shop and price as a record or an earlier card is left out."},"otherListings":{"type":"array","items":{"$ref":"#/components/schemas/ProductLookupListing"},"description":"Other products the answers showed. A renamed or translated version of the product can be here."},"citedPages":{"type":"array","items":{"$ref":"#/components/schemas/ProductLookupCitedPage"},"description":"The pages the answers cite. For ChatGPT, the sources its answer cites."}}},"ProductLookupSummary":{"type":"object","description":"One product's answers across engines.","properties":{"foundIn":{"type":"array","items":{"$ref":"#/components/schemas/ProductLookupEngine"},"description":"Engines whose answers showed the product."},"notFoundIn":{"type":"array","items":{"$ref":"#/components/schemas/ProductLookupEngine"},"description":"Engines whose asks finished without showing it."},"pending":{"type":"array","items":{"$ref":"#/components/schemas/ProductLookupEngine"},"description":"Engines with asks still queued or processing."},"failed":{"type":"array","items":{"$ref":"#/components/schemas/ProductLookupEngine"},"description":"Engines whose asks all failed."},"merchants":{"type":"array","description":"Each merchant of the product's listings, with the engines that showed it and its prices there, most engines first.","items":{"type":"object","properties":{"merchant":{"type":"string"},"engines":{"type":"array","items":{"$ref":"#/components/schemas/ProductLookupEngine"}},"price":{"$ref":"#/components/schemas/ProductLookupPriceRange"}}}},"priceRange":{"$ref":"#/components/schemas/ProductLookupPriceRange"},"citedDomains":{"type":"array","description":"Each site the answers cite, with the engines that cite it, most engines first.","items":{"type":"object","properties":{"domain":{"type":"string"},"engines":{"type":"array","items":{"$ref":"#/components/schemas/ProductLookupEngine"}}}}},"credits":{"type":"number","description":"Credits charged for this product's asks so far."}}},"ProductLookupProduct":{"type":"object","properties":{"product":{"type":"string"},"summary":{"$ref":"#/components/schemas/ProductLookupSummary"},"engines":{"type":"array","items":{"$ref":"#/components/schemas/ProductLookupEngineResult"}}}},"ProductLookupComparisonRow":{"type":"object","properties":{"product":{"type":"string"},"role":{"type":"string","enum":["product","competitor"]},"engines":{"type":"array","items":{"type":"object","properties":{"engine":{"$ref":"#/components/schemas/ProductLookupEngine"},"status":{"$ref":"#/components/schemas/TaskStatus"},"found":{"type":["boolean","null"]},"listings":{"type":"integer","description":"Listings judged to be the product, widget cards included."},"merchants":{"type":"integer","description":"Merchants among those listings."},"mostReviewed":{"type":"object","description":"The listing with the most reviews. For ChatGPT, the count its answering model was given (modelSees). Copilot puts one product's review count on every merchant's offer, so merchant is the first offer that carries it.","properties":{"reviewCount":{"type":"integer"},"rating":{"type":"number"},"merchant":{"type":"string"}}},"priceRange":{"$ref":"#/components/schemas/ProductLookupPriceRange"},"prompts":{"type":"object","description":"Only when the lookup has shopper prompts: how many of them the engine answered, and how many of those answers showed or named the product.","properties":{"answered":{"type":"integer"},"appeared":{"type":"integer"}}}}}}}},"ProductLookupPromptEngine":{"type":"object","description":"One engine's answer to one shopper prompt.","properties":{"engine":{"$ref":"#/components/schemas/ProductLookupEngine"},"status":{"$ref":"#/components/schemas/TaskStatus"},"via":{"type":"array","items":{"$ref":"#/components/schemas/ProductLookupVia"}},"shown":{"type":"array","items":{"type":"string"},"description":"The lookup's products (the product and competitors) that the answer showed as a record or widget card, in the order shown. A record counts only when it contains the product name's first word, the brand."},"named":{"type":"array","items":{"type":"string"},"description":"The lookup's products that the answer's text names, in the order named."},"listings":{"type":"array","description":"Every product record and widget card in the answer. One that is a looked-up product carries product and match.","items":{"allOf":[{"$ref":"#/components/schemas/ProductLookupRecord"},{"type":"object","properties":{"product":{"type":"string","description":"The looked-up product this listing is."},"match":{"$ref":"#/components/schemas/ProductLookupMatch"}}}]}},"citedPages":{"type":"array","items":{"$ref":"#/components/schemas/ProductLookupCitedPage"}}}},"ProductLookupResponse":{"type":"object","properties":{"success":{"type":"boolean"},"lookup":{"type":"object","properties":{"id":{"type":"string"},"product":{"type":"string"},"competitors":{"type":"array","items":{"type":"string"}},"prompts":{"type":"array","items":{"type":"string"}},"country":{"type":"string","enum":["US","KR"]},"status":{"allOf":[{"$ref":"#/components/schemas/TaskStatus"}],"description":"QUEUED until an ask starts, PROCESSING while any ask is unfinished, then COMPLETED, or FAILED when every ask failed."},"createdAt":{"type":"string","format":"date-time"},"completedAt":{"type":["string","null"],"format":"date-time","description":"When the last ask finished."},"credits":{"type":"number","description":"Credits charged for every ask of the lookup so far."}}},"summary":{"allOf":[{"$ref":"#/components/schemas/ProductLookupSummary"}],"description":"The product's answers across engines."},"engines":{"type":"array","items":{"$ref":"#/components/schemas/ProductLookupEngineResult"},"description":"The product's answers, one entry per engine asked."},"competitors":{"type":"array","items":{"$ref":"#/components/schemas/ProductLookupProduct"},"description":"Each competitor's summary and engines, in the order of lookup.competitors."},"comparison":{"type":"array","items":{"$ref":"#/components/schemas/ProductLookupComparisonRow"},"description":"The product and each competitor, engine by engine."},"prompts":{"type":"array","description":"What each engine answered to each shopper prompt.","items":{"type":"object","properties":{"prompt":{"type":"string"},"engines":{"type":"array","items":{"$ref":"#/components/schemas/ProductLookupPromptEngine"}}}}}}},"PlaceLookupEngine":{"type":"string","enum":["CHATGPT","GEMINI","GOOGLE","BING_COPILOT","NAVER_AI_TAB"],"description":"An engine a place lookup asks. NAVER_AI_TAB answers for KR only."},"PlaceLookupPlace":{"type":"object","additionalProperties":false,"required":["name"],"description":"The store and its official details. address or location is required.","properties":{"name":{"type":"string","minLength":1,"maxLength":200,"description":"The store's name. For a chain, include the branch."},"address":{"type":"string","maxLength":500,"description":"The street address."},"location":{"$ref":"#/components/schemas/LocationPoint","description":"The store's pin. With it, each record carries distanceMeters and a pin more than 300 m away is reported as location_mismatch."},"phone":{"type":"string","maxLength":50,"description":"The official phone number, in any format."},"website":{"type":"string","format":"uri","description":"The official website, an http or https URL."},"googlePlaceId":{"type":"string","description":"The store's Google Place ID. A record with this ID is the store."},"naverPlaceId":{"type":"string","description":"The store's Naver Place ID, or its map.naver.com or place.naver.com page."},"yelpUrl":{"type":"string","format":"uri","description":"The store's yelp.com/biz/ page."}}},"PlaceLookupRequest":{"type":"object","additionalProperties":false,"required":["place","country"],"properties":{"place":{"$ref":"#/components/schemas/PlaceLookupPlace"},"country":{"type":"string","description":"The store's country, an ISO 3166-1 alpha-2 code such as US or KR."},"engines":{"type":"array","items":{"$ref":"#/components/schemas/PlaceLookupEngine"},"minItems":1,"uniqueItems":true,"description":"Engines to ask. Default: all five in KR, CHATGPT, GEMINI, GOOGLE and BING_COPILOT elsewhere."},"idempotencyKey":{"type":"string","minLength":1,"maxLength":200,"description":"Names the lookup and becomes lookup.id. Without it the server mints a UUID. The same request under it adds only the missing questions."},"priority":{"type":"integer","minimum":1,"maximum":10,"default":1,"description":"Set on every task. Out-of-range values are clamped. It does not guarantee execution order."}}},"PlaceLookupSubmitResult":{"type":"object","properties":{"success":{"type":"boolean"},"lookup":{"type":"object","properties":{"id":{"type":"string"}}},"tasks":{"type":"array","description":"Two entries per engine, in engine order.","items":{"type":"object","properties":{"engine":{"$ref":"#/components/schemas/PlaceLookupEngine"},"ask":{"type":"integer","enum":[1,2],"description":"Which of the engine's two questions."},"success":{"type":"boolean"},"task":{"$ref":"#/components/schemas/TaskMeta"},"status":{"type":"string","enum":["PENDING"],"description":"Present while the question waits for room; the entry then has no task. It starts on its own as room frees up."},"error":{"$ref":"#/components/schemas/ErrorDetail"}}}}}},"PlaceLookupAsk":{"type":"object","description":"One question as it was sent, and its task.","properties":{"taskType":{"$ref":"#/components/schemas/PlaceLookupEngine"},"prompt":{"type":"string"},"query":{"type":"string"},"location":{"$ref":"#/components/schemas/LocationPoint"},"taskId":{"type":"string","format":"uuid","description":"Present once the question has started."},"status":{"type":"string","enum":["PENDING","QUEUED","PROCESSING","COMPLETED","FAILED","TIMEOUT"],"description":"PENDING while the question waits for room in the plan or the engine's queue."},"collectedAt":{"type":"string","format":"date-time"},"places":{"type":"integer","description":"How many places the answer showed."},"error":{"type":"string","description":"A failed question's error, starting with its code."}}},"PlaceMatch":{"type":"object","properties":{"same":{"type":"boolean"},"by":{"type":"array","items":{"type":"string","enum":["place_id","phone","website","location","address","name"]},"description":"The details that agree with the store."},"nameScore":{"type":"number","minimum":0,"maximum":1,"description":"Name similarity."},"distanceMeters":{"type":"number","description":"From place.location to the record's pin."},"otherBusiness":{"type":"boolean","description":"Present as true when the record's phone and website both differ from the store's."}}},"PlaceRecord":{"type":"object","description":"One engine's record of the store. Only fields the answer carries are present.","properties":{"position":{"type":"integer","description":"Order among the places in the answer, from 1."},"name":{"type":"string"},"localName":{"type":"string","description":"CHATGPT only: the record's other name."},"source":{"type":"string","enum":["google_maps","naver_place","yelp","tripadvisor","unknown"],"description":"The record's map database."},"provider":{"type":"string","description":"CHATGPT only: the feed ChatGPT names for the record, such as yelp-feed."},"resolvedBy":{"type":"string","enum":["address"],"description":"CHATGPT only: ChatGPT found the record by an address the model wrote."},"placeId":{"type":"string","description":"The record's ID at its source."},"url":{"type":"string","description":"The record's page at its source."},"address":{"type":"string"},"latitude":{"type":"number"},"longitude":{"type":"number"},"phone":{"type":"string"},"category":{"type":"string"},"rating":{"type":"number"},"reviewCount":{"type":"integer"},"website":{"type":"string"},"openState":{"type":"string","description":"The engine's open-now label at answer time."},"closed":{"type":"string","enum":["permanently","temporarily"],"description":"CHATGPT only."},"image":{"type":"string"},"description":{"type":"string"},"match":{"$ref":"#/components/schemas/PlaceMatch"}}},"PlaceLookupEngineResult":{"type":"object","properties":{"engine":{"$ref":"#/components/schemas/PlaceLookupEngine"},"status":{"type":"string","enum":["PROCESSING","COMPLETED","FAILED"],"description":"COMPLETED once both questions ended, FAILED when both failed."},"found":{"type":["boolean","null"],"description":"true once an answer shows the store; false when both questions ended without it; null while a question runs and when both failed."},"via":{"type":"array","items":{"$ref":"#/components/schemas/PlaceLookupAsk"}},"record":{"$ref":"#/components/schemas/PlaceRecord"},"issues":{"type":"array","items":{"type":"string","enum":["other_business_record","phone_mismatch","website_mismatch","location_mismatch","closed_permanently","closed_temporarily"]},"description":"What is wrong with the record. Present only when something is."}}},"PlaceLookupResult":{"type":"object","properties":{"success":{"type":"boolean"},"lookup":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["PROCESSING","COMPLETED"]},"place":{"$ref":"#/components/schemas/PlaceLookupPlace"},"country":{"type":"string"},"engines":{"type":"array","items":{"$ref":"#/components/schemas/PlaceLookupEngineResult"}},"summary":{"type":"object","properties":{"foundIn":{"type":"array","items":{"$ref":"#/components/schemas/PlaceLookupEngine"}},"notFoundIn":{"type":"array","items":{"$ref":"#/components/schemas/PlaceLookupEngine"}},"failed":{"type":"array","items":{"$ref":"#/components/schemas/PlaceLookupEngine"}},"pending":{"type":"array","items":{"$ref":"#/components/schemas/PlaceLookupEngine"}},"differences":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","enum":["name","phone","website","location"]},"values":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"engines":{"type":"array","items":{"$ref":"#/components/schemas/PlaceLookupEngine"}}}}},"spreadMeters":{"type":"number","description":"location only: the largest distance between two pins."}}}}}},"credits":{"type":"number","description":"Credits charged so far for the lookup's questions."}}}}},"LocationPoint":{"type":"object","additionalProperties":false,"required":["latitude","longitude"],"properties":{"latitude":{"type":"number","minimum":-90,"maximum":90},"longitude":{"type":"number","minimum":-180,"maximum":180}},"example":{"latitude":37.4979,"longitude":127.0276}},"GridSpec":{"type":"object","additionalProperties":false,"required":["center","size","radiusMeters"],"description":"A square grid of points. Row 0 is the north edge and column 0 the west edge; points sit 2 × radiusMeters ÷ (size − 1) apart.","properties":{"center":{"$ref":"#/components/schemas/LocationPoint"},"size":{"type":"integer","enum":[3,5,7,9],"description":"Points per side. Odd, so the center is one of the points."},"radiusMeters":{"type":"number","minimum":100,"maximum":50000,"description":"Distance from the center to the middle of each edge."}}},"GridRequest":{"type":"object","required":["taskType","payload","grid"],"properties":{"taskType":{"type":"string","enum":["CHATGPT","GEMINI","GOOGLE","AIMODE","GOOGLE_SERP"],"description":"An engine that answers for a location."},"payload":{"$ref":"#/components/schemas/Payload","description":"The task payload without location: each point's task gets its own."},"grid":{"$ref":"#/components/schemas/GridSpec"},"idempotencyKey":{"type":"string","maxLength":200,"description":"Names the grid. Each point's key is <id>:r<row>c<col>, so sending the same grid again admits only the missing points. Minted when absent and returned as grid.id."},"priority":{"type":"integer","minimum":1,"maximum":10},"webhook":{"type":"object","properties":{"url":{"type":"string","format":"uri"}}}}},"GridResult":{"type":"object","properties":{"success":{"type":"boolean"},"grid":{"type":"object","properties":{"id":{"type":"string"},"center":{"$ref":"#/components/schemas/LocationPoint"},"size":{"type":"integer"},"radiusMeters":{"type":"number"},"spacingMeters":{"type":"number"}}},"summary":{"type":"object","properties":{"total":{"type":"integer"},"succeeded":{"type":"integer"},"failed":{"type":"integer"}}},"points":{"type":"array","description":"Row by row from the north-west corner.","items":{"type":"object","properties":{"row":{"type":"integer"},"col":{"type":"integer"},"location":{"$ref":"#/components/schemas/LocationPoint"},"success":{"type":"boolean"},"task":{"$ref":"#/components/schemas/TaskMeta"},"error":{"$ref":"#/components/schemas/ErrorDetail"}}}}}},"GridReadResult":{"type":"object","properties":{"success":{"type":"boolean"},"grid":{"type":"object","properties":{"id":{"type":"string"}}},"summary":{"type":"object","properties":{"total":{"type":"integer"},"queued":{"type":"integer"},"processing":{"type":"integer"},"completed":{"type":"integer"},"failed":{"type":"integer"}}},"points":{"type":"array","items":{"type":"object","properties":{"row":{"type":"integer"},"col":{"type":"integer"},"location":{"$ref":"#/components/schemas/LocationPoint"},"task":{"$ref":"#/components/schemas/TaskMeta"},"credits":{"$ref":"#/components/schemas/Credits"},"response":{"$ref":"#/components/schemas/TaskResponse"}}}}}},"BatchItemRequest":{"type":"object","required":["taskType","payload"],"description":"One task of a batch: the fields of a single task request, plus an optional `customId`. `webhook` is set once on the batch.","properties":{"customId":{"type":"string","maxLength":128,"description":"Your own id for the item, returned with its result."},"taskType":{"$ref":"#/components/schemas/TaskType"},"payload":{"$ref":"#/components/schemas/Payload"},"priority":{"type":"integer","minimum":1,"maximum":10,"default":1},"idempotencyKey":{"type":"string","description":"Unique inside the batch. Omitted, the item's task is created with a key derived from the batch id and its index, so it is created once."}},"allOf":[{"if":{"properties":{"taskType":{"const":"COMMERCE_SERP"}},"required":["taskType"]},"then":{"properties":{"payload":{"$ref":"#/components/schemas/CommerceSerpPayload"}}}},{"if":{"properties":{"taskType":{"const":"COMMERCE_PRODUCT"}},"required":["taskType"]},"then":{"properties":{"payload":{"$ref":"#/components/schemas/CommerceProductPayload"}}}}]},"BatchRequest":{"type":"object","required":["items"],"properties":{"items":{"type":"array","minItems":1,"maxItems":10000,"items":{"$ref":"#/components/schemas/BatchItemRequest"}},"webhook":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri"}},"description":"Each item's task posts its result here, and the batch posts one `batch.completed` event when it finishes."},"metadata":{"type":"object","additionalProperties":true,"description":"Up to 8 KB of JSON, returned with the batch."},"idempotencyKey":{"type":"string","maxLength":256,"description":"Sending the same key again returns the first batch."}}},"BatchCounts":{"type":"object","required":["pending","queued","processing","completed","failed","rejected"],"description":"Items by status. `pending` items wait for room in your plan's active-task limit and in the engine's queue; `rejected` items were refused when their task was created (for example `INSUFFICIENT_CREDITS`).","properties":{"pending":{"type":"integer"},"queued":{"type":"integer"},"processing":{"type":"integer"},"completed":{"type":"integer"},"failed":{"type":"integer"},"rejected":{"type":"integer"}}},"Batch":{"type":"object","required":["id","status","total","counts","createdAt","completedAt","metadata"],"properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["OPEN","COMPLETED"],"description":"`COMPLETED` once no item is pending, queued or processing."},"total":{"type":"integer"},"counts":{"$ref":"#/components/schemas/BatchCounts"},"createdAt":{"type":"string","format":"date-time"},"completedAt":{"type":["string","null"],"format":"date-time"},"idempotencyKey":{"type":"string"},"webhook":{"type":"object","properties":{"url":{"type":"string"}}},"metadata":{"type":["object","null"]}}},"SubAccount":{"type":"object","required":["id","name","externalId","status","monthlyCreditLimit","concurrencyLimit","createdAt","suspendedAt","usage"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"externalId":{"type":["string","null"],"description":"Your id for this customer, unique among your sub-accounts."},"status":{"type":"string","enum":["active","suspended"]},"monthlyCreditLimit":{"type":["number","null"],"minimum":0.01,"multipleOf":0.01,"maximum":20000000,"description":"Credits it may be charged per UTC calendar month. Null means no cap."},"concurrencyLimit":{"type":["integer","null"],"minimum":1,"maximum":100000,"description":"Its queued and running tasks, inside your own limit. Null means it shares your limit."},"createdAt":{"type":"string","format":"date-time"},"suspendedAt":{"type":["string","null"],"format":"date-time"},"usage":{"type":"object","required":["month","credits","tasks","reservedCredits"],"description":"This UTC month.","properties":{"month":{"type":"string","description":"YYYY-MM, UTC."},"credits":{"type":"number","description":"Credits charged this month."},"tasks":{"type":"integer","description":"Tasks charged this month."},"reservedCredits":{"type":"number","description":"Credits held by its tasks still queued or running. The monthly limit counts these too."}}}}},"SubAccountCreateRequest":{"type":"object","required":["name"],"additionalProperties":false,"properties":{"name":{"type":"string","minLength":1,"maxLength":128},"externalId":{"type":["string","null"],"minLength":1,"maxLength":128,"description":"Your id for this customer. A second create with the same value returns 409, so retries are safe."},"monthlyCreditLimit":{"type":["number","null"],"minimum":0.01,"multipleOf":0.01,"maximum":20000000,"description":"Credits it may be charged per UTC calendar month."},"concurrencyLimit":{"type":["integer","null"],"minimum":1,"maximum":100000,"description":"Its queued and running tasks, inside your own limit."}}},"SubAccountUpdateRequest":{"type":"object","minProperties":1,"additionalProperties":false,"properties":{"name":{"type":"string","minLength":1,"maxLength":128},"externalId":{"type":["string","null"],"minLength":1,"maxLength":128},"monthlyCreditLimit":{"type":["number","null"],"minimum":0.01,"multipleOf":0.01,"maximum":20000000,"description":"Null removes the cap."},"concurrencyLimit":{"type":["integer","null"],"minimum":1,"maximum":100000,"description":"Null removes the cap."},"status":{"type":"string","enum":["active","suspended"]}}},"SubAccountResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/SubAccount"}}},"SubAccountDetailResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"allOf":[{"$ref":"#/components/schemas/SubAccount"},{"type":"object","required":["activeTasks"],"properties":{"activeTasks":{"type":"integer","description":"Its tasks queued or running now."}}}]}}},"SubAccountListResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","required":["subAccounts","nextCursor"],"properties":{"subAccounts":{"type":"array","items":{"$ref":"#/components/schemas/SubAccount"}},"nextCursor":{"type":["string","null"],"description":"Pass as cursor for the next page. Null on the last page."}}}}},"SubAccountUsageResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","required":["from","to","credits","tasks","subAccounts"],"properties":{"from":{"type":"string","format":"date"},"to":{"type":"string","format":"date"},"credits":{"type":"number","description":"Total over every sub-account in the range."},"tasks":{"type":"integer"},"subAccounts":{"type":"array","items":{"type":"object","required":["id","name","externalId","credits","tasks"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"externalId":{"type":["string","null"]},"credits":{"type":"number"},"tasks":{"type":"integer"}}}}}}}},"SubAccountDailyUsageResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","required":["id","from","to","credits","tasks","days"],"properties":{"id":{"type":"string","format":"uuid"},"from":{"type":"string","format":"date"},"to":{"type":"string","format":"date"},"credits":{"type":"number","description":"Total over days."},"tasks":{"type":"integer","description":"Total over days."},"days":{"description":"One row per UTC date and taskType that had a charge, oldest first. Days without charges are left out.","type":"array","items":{"type":"object","required":["date","taskType","credits","tasks"],"properties":{"date":{"type":"string","format":"date"},"taskType":{"type":"string","description":"The engine, or OTHER for a charge that is not a task."},"credits":{"type":"number"},"tasks":{"type":"integer"}}}}}}}},"SubAccountKeyRequest":{"type":"object","additionalProperties":false,"properties":{"name":{"type":"string","minLength":1,"maxLength":64,"default":"default"},"allowedTaskTypes":{"type":"array","items":{"type":"string"},"description":"Self-serve engines the key may submit. Empty or absent means all of them."},"dailyCreditLimit":{"type":["number","null"],"minimum":0.01,"multipleOf":0.01,"maximum":20000000},"expiresAt":{"type":["string","null"],"format":"date-time","description":"Between 5 minutes and 2 years from now."}}},"SubAccountKey":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"keyPrefix":{"type":"string","description":"The first 11 characters of the key, for display."},"createdAt":{"type":"string","format":"date-time"},"allowedTaskTypes":{"type":"array","items":{"type":"string"},"description":"Engines the key may submit. Empty means every self-serve engine."},"dailyCreditLimit":{"type":["number","null"],"description":"The key's per-UTC-day spending cap, null for no cap. This endpoint returns it in hundredths of a credit (a 50-credit cap reads 5000), unlike POST /v1/sub-accounts/{id}/keys, which accepts and returns credits."},"expiresAt":{"type":["string","null"],"format":"date-time"},"revokedAt":{"type":["string","null"],"format":"date-time"},"lastUsedAt":{"type":["string","null"],"format":"date-time"}}},"SubAccountKeyListResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","required":["keys"],"properties":{"keys":{"type":"array","items":{"$ref":"#/components/schemas/SubAccountKey"}}}}}},"SubAccountKeyCreatedResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"keyPrefix":{"type":"string","description":"The first 11 characters of the key, for display."},"createdAt":{"type":"string","format":"date-time"},"allowedTaskTypes":{"type":"array","items":{"type":"string"},"description":"Engines the key may submit. Empty means every self-serve engine."},"dailyCreditLimit":{"type":["number","null"],"description":"Credits the key may spend per UTC day. Null means no cap."},"expiresAt":{"type":["string","null"],"format":"date-time"},"key":{"type":"string","description":"The API key (vt_...). Shown in this response only."}}}}},"BatchResponse":{"type":"object","required":["success","batch"],"properties":{"success":{"type":"boolean","const":true},"batch":{"$ref":"#/components/schemas/Batch"}}},"BatchItem":{"type":"object","required":["index","taskType","status"],"properties":{"index":{"type":"integer","description":"Position in the submitted `items` array."},"customId":{"type":"string"},"taskType":{"$ref":"#/components/schemas/TaskType"},"status":{"type":"string","enum":["PENDING","QUEUED","PROCESSING","COMPLETED","FAILED","REJECTED"]},"taskId":{"type":"string","format":"uuid","description":"Also readable with GET /v1/async/task/{id}."},"completedAt":{"type":"string","format":"date-time"},"error":{"type":"object","description":"Why the item was rejected, or the task's error when `include=response`."},"response":{"type":"object","description":"With `include=response`: the task's result, as GET /v1/async/task/{id} returns it, for one day after the task completes."}}},"BatchItemsResponse":{"type":"object","required":["success","items","nextCursor"],"properties":{"success":{"type":"boolean","const":true},"items":{"type":"array","items":{"$ref":"#/components/schemas/BatchItem"}},"nextCursor":{"type":["string","null"],"description":"Pass as `cursor` for the next page; null on the last page."}}},"AnswerAnalysis":{"type":"object","description":"The `analysis` field of an answer task with `include.analysis`. Brand names, the requested-brand match, recommendation and sentiment are a model's judgment; positions, ranks and source kinds are computed by rules. See the Engines guide, Answer analysis.","required":["version","status"],"properties":{"version":{"type":"integer","enum":[1]},"status":{"type":"string","enum":["ok","no_answer","failed"],"description":"`no_answer`: the engine completed without answer text, nothing is mentioned and the analysis is not charged. `failed`: the analysis could not run; the task still completes and only the engine price is charged."},"error":{"type":"string","enum":["ANALYSIS_FAILED","ANALYSIS_TIMEOUT","ANALYSIS_UNAVAILABLE"],"description":"Present when `status` is `failed`."},"brands":{"type":"array","description":"Every brand the answer names, in the order it first names each one. A product counts for its maker.","items":{"type":"object","properties":{"name":{"type":"string","description":"The name you sent, or for any other brand its own name, the same in every language."},"domain":{"type":["string","null"],"description":"The brand's site: the first of the domains you sent, or the one found for it."},"writtenAs":{"type":"string","description":"The brand's name as the answer first writes it: the first of `spellings`."},"spellings":{"type":"array","items":{"type":"string"},"description":"Every way the answer writes the brand's name, in the order it first uses each. A product or description written after the name is not part of a spelling."},"rank":{"type":"integer","minimum":1},"role":{"type":["string","null"],"enum":["brand","competitor",null]},"recommended":{"type":["boolean","null"],"description":"Null when the name matched but the model did not read it as a brand in this answer."},"sentiment":{"type":["string","null"],"enum":["positive","neutral","negative",null]},"sentimentScore":{"type":["number","null"],"enum":[0.9,0.5,0,-0.5,-0.9,null]}}}},"targets":{"type":"array","description":"The `brand` and `competitors` you sent, in your order.","items":{"type":"object","properties":{"name":{"type":"string"},"role":{"type":"string","enum":["brand","competitor"]},"mentioned":{"type":"boolean"},"rank":{"type":["integer","null"]},"recommended":{"type":["boolean","null"]},"sentiment":{"type":["string","null"],"enum":["positive","neutral","negative",null]},"sentimentScore":{"type":["number","null"]},"cited":{"type":"boolean","description":"A citation is on one of its domains. False when no domains were sent."}}}},"sources":{"type":"array","description":"The answer's citations in the engine's order.","items":{"type":"object","properties":{"position":{"type":"integer","minimum":1},"url":{"type":"string"},"domain":{"type":["string","null"]},"kind":{"type":"string","enum":["owned","competitor","editorial","review_media","pr_wire","institution","reviews","commerce","social","blog","community","video","brand","content","other"]},"brand":{"type":["string","null"],"description":"The brand whose domain this is, for `owned` and `competitor`."}}}}}},"ExportDeleteResponse":{"type":"object","properties":{"success":{"type":"boolean","const":true}}},"ExportIdentityResponse":{"type":"object","properties":{"success":{"type":"boolean","const":true},"identity":{"type":"object","properties":{"accountKey":{"type":"string","description":"Names this account's folder and tables."},"gcp":{"type":"object","properties":{"serviceAccount":{"type":"string"}}},"aws":{"type":"object","properties":{"federatedPrincipal":{"type":"string"},"audience":{"type":"string"},"oaud":{"type":"string"},"roleSessionName":{"type":"string"},"trustPolicy":{"type":"object"}}}}}}},"ExportRunResponse":{"type":"object","properties":{"success":{"type":"boolean","const":true},"run":{"$ref":"#/components/schemas/ExportRun"}}},"ExportRunListResponse":{"type":"object","properties":{"success":{"type":"boolean","const":true},"runs":{"type":"array","items":{"$ref":"#/components/schemas/ExportRun"}},"nextCursor":{"type":["string","null"]}}},"ExportRun":{"type":"object","properties":{"id":{"type":"string"},"data":{"type":"string","enum":["tasks","monitor_results"]},"windowStart":{"type":"string","format":"date-time"},"windowEnd":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["pending","running","delivered","failed"]},"attempts":{"type":"integer"},"nextAttemptAt":{"type":["string","null"],"format":"date-time"},"rows":{"type":["integer","null"]},"bytes":{"type":["integer","null"]},"files":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"rows":{"type":"integer"},"bytes":{"type":"integer"}}}},"error":{"type":["string","null"],"description":"The storage provider's reason for the last failure."},"deliveredAt":{"type":["string","null"],"format":"date-time"}}},"ExportListResponse":{"type":"object","properties":{"success":{"type":"boolean","const":true},"exports":{"type":"array","items":{"$ref":"#/components/schemas/Export"}}}},"ExportResponse":{"type":"object","properties":{"success":{"type":"boolean","const":true},"export":{"$ref":"#/components/schemas/Export"}}},"Export":{"type":"object","properties":{"id":{"type":"string"},"destination":{"$ref":"#/components/schemas/ExportDestination"},"interval":{"type":"string","enum":["hourly","daily"]},"data":{"type":"array","items":{"type":"string","enum":["tasks","monitor_results"]}},"enabled":{"type":"boolean"},"schemaVersion":{"type":"integer"},"nextWindowStart":{"type":"string","format":"date-time","description":"Start of the first window not yet scheduled."},"createdAt":{"type":"string","format":"date-time"},"deliveredThrough":{"type":["string","null"],"format":"date-time","description":"End of the latest delivered window."},"failedRuns":{"type":"integer","description":"Windows that stopped after the last automatic retry."},"retryingRuns":{"type":"integer","description":"Windows waiting for an automatic retry."}}},"CreateExportRequest":{"type":"object","required":["destination"],"properties":{"destination":{"$ref":"#/components/schemas/ExportDestination"},"interval":{"type":"string","enum":["hourly","daily"],"default":"daily","description":"Window length. Fixed for the life of the export."},"data":{"type":"array","items":{"type":"string","enum":["tasks","monitor_results"]},"description":"Data sets to deliver. Default: both."},"startAt":{"type":"string","format":"date-time","description":"Deliver from the window containing this time, up to 30 days back. Default: now."}}},"ExportDestination":{"type":"object","required":["type"],"description":"Where files land. S3 and GCS take bucket and an optional prefix; S3 also takes region and roleArn. BigQuery takes projectId and datasetId. Responses add path (S3, GCS) or tables and location (BigQuery).","properties":{"type":{"type":"string","enum":["s3","gcs","bigquery"]},"bucket":{"type":"string"},"prefix":{"type":"string","description":"Folder inside the bucket. Stored ending in /."},"region":{"type":"string","description":"S3 bucket region, e.g. us-east-1."},"roleArn":{"type":"string","description":"IAM role that trusts the export identity (GET /v1/exports/identity)."},"projectId":{"type":"string"},"datasetId":{"type":"string"},"path":{"type":"string","readOnly":true,"description":"Folder this account's files land in: <prefix><accountKey>/."},"tables":{"type":"array","items":{"type":"string"},"readOnly":true},"location":{"type":"string","readOnly":true,"description":"BigQuery dataset location, read when connecting."}}},"MonitorEngineSettings":{"type":"object","description":"Per-engine cadence and answers per prompt, keyed by engine. An engine without an entry joins every run once. Values equal to the defaults are dropped, and an update that removes an engine removes its entry.","additionalProperties":{"type":"object","additionalProperties":false,"properties":{"intervalHours":{"type":"integer","minimum":1,"maximum":168,"description":"A multiple of the monitor's intervalHours. The engine joins every k-th run, counting from the first run, which every engine joins."},"samples":{"type":"integer","minimum":1,"maximum":10,"description":"Answers per prompt and point in each run, each its own task in its own session. Default 1."}}},"example":{"CHATGPT":{"samples":5},"GOOGLE":{"intervalHours":168}}},"MonitorEvent":{"type":"object","required":["id","type","createdAt","data","delivery"],"properties":{"id":{"type":"string","description":"Also the querying-webhook-id header of every delivery."},"type":{"type":"string","enum":["monitor.mention.started","monitor.mention.stopped","monitor.competitor.ahead","monitor.source.first_cited"]},"createdAt":{"type":"string","format":"date-time"},"data":{"$ref":"#/components/schemas/MonitorEventData"},"delivery":{"type":"object","properties":{"status":{"type":"string","enum":["pending","delivered","failed"]},"attempts":{"type":"integer"},"deliveredAt":{"type":["string","null"],"format":"date-time"},"lastError":{"type":["string","null"]}}}}},"MonitorEventData":{"type":"object","description":"The prompt, engine and point the event is about, the answer that crossed (taskId, readable with GET /v1/monitors/{id}/answers/{taskId}), and the event's own fields.","properties":{"engine":{"$ref":"#/components/schemas/MonitorEngine"},"prompt":{"type":"string"},"location":{"type":["object","null"],"properties":{"latitude":{"type":"number"},"longitude":{"type":"number"}}},"taskId":{"type":"string"},"answers":{"type":"integer","description":"mention and competitor events: answers the state is read over (5)."},"mentions":{"type":"integer","description":"mention and competitor events: of those answers, how many name the brand."},"competitor":{"type":"string","description":"monitor.competitor.ahead: the competitor now ahead."},"competitorMentions":{"type":"integer","description":"monitor.competitor.ahead: answers naming the competitor."},"domain":{"type":"string","description":"monitor.source.first_cited: the newly cited site."},"url":{"type":"string","description":"monitor.source.first_cited: the cited page."},"label":{"type":["string","null"]}}},"MonitorEventBody":{"type":"object","required":["event","id","createdAt","monitor","data"],"properties":{"event":{"type":"string","enum":["monitor.mention.started","monitor.mention.stopped","monitor.competitor.ahead","monitor.source.first_cited"]},"id":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"monitor":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}}},"data":{"$ref":"#/components/schemas/MonitorEventData"}}},"MonitorEventsResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"webhookUrl":{"type":["string","null"],"description":"The monitor's current webhookUrl, where redeliveries go; null when events are not sent. It is on the page, not on each event."},"events":{"type":"array","items":{"$ref":"#/components/schemas/MonitorEvent"}},"nextCursor":{"type":["string","null"],"description":"Pass as cursor for the next, older page; null on the last."}}}}},"MonitorEventResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"event":{"$ref":"#/components/schemas/MonitorEvent"}}}}},"MonitorShareRequest":{"type":"object","required":["access"],"properties":{"access":{"type":"string","enum":["PRIVATE","LINK","PUBLIC"]},"slug":{"type":["string","null"],"description":"Required the first time access is LINK or PUBLIC. Omitted, null or empty keeps the current slug. Trimmed and lowercased, then 3 to 40 lowercase letters, digits or single hyphens, starting and ending with a letter or digit; words the site uses for its own pages are reserved (400)."},"locale":{"type":"string","enum":["en","ko","ja","zh","es","fr","de","pt"],"description":"Omit to keep the report's current language."}}},"MonitorShare":{"type":"object","required":["access","slug","locale","url"],"properties":{"access":{"type":"string","enum":["PRIVATE","LINK","PUBLIC"],"description":"PRIVATE: only you. LINK: anyone with the URL, not indexed. PUBLIC: anyone, and search engines may index it."},"slug":{"type":["string","null"],"description":"The address segment, kept when access goes back to PRIVATE. null until one is set."},"locale":{"type":"string","enum":["en","ko","ja","zh","es","fr","de","pt"],"description":"The language the report renders in for every reader."},"url":{"type":["string","null"],"description":"https://querying.ai/<slug>, or null when no slug is set. It serves the report only while access is LINK or PUBLIC."}}},"MonitorShareUpdateResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/MonitorShare"}}},"MonitorShareResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"allOf":[{"$ref":"#/components/schemas/MonitorShare"},{"type":"object","required":["suggestedSlug"],"properties":{"suggestedSlug":{"type":["string","null"],"description":"The current slug when one is set. Otherwise one derived from the first usable domain (without its TLD) or the name, or null when it is already taken or nothing usable can be derived."}}}]}}},"GeoScoreRequest":{"type":"object","required":["url"],"additionalProperties":false,"properties":{"url":{"type":"string","format":"uri","maxLength":2048,"description":"The page to score: an http or https URL on a public host, on the default port."},"country":{"type":"string","enum":["US","KR"],"default":"US","description":"Where the person reading the page is. The page is rendered from an address in that country, in its language and time zone. Any other value is a 422 REGION_UNSUPPORTED."},"idempotencyKey":{"type":"string","description":"Optional. Deduplicates submissions; a duplicate is a 409."},"priority":{"type":"integer","minimum":1,"maximum":10,"default":1,"description":"Optional. Echoed in task metadata; values outside 1-10 are clamped. It does not guarantee execution order."},"webhook":{"type":"object","description":"Optional. Omit to collect the result by polling instead.","required":["url"],"properties":{"url":{"type":"string","format":"uri","description":"Receives a POST when the task reaches a terminal state."}}}}},"GeoScoreMissReason":{"type":"string","enum":["blocked","javascript_only","structured_data_only","image_only"],"description":"Why ChatGPT search does not keep a piece (status), or ChatGPT does not receive it when it opens the page (direct). blocked: the crawler could not get the page: the site refused our OAI-SearchBot requests and renders (search), or ChatGPT could not open the page (direct). javascript_only: it shows only after scripts run: loaded after the page opens, or, on opening, drawn from the HTML's script data. structured_data_only: it is only in JSON-LD or meta tags. image_only: it is written only inside an image: search keeps no text from inside images, and on opening ChatGPT cannot read this one (the HTML has no img with that picture as its src, the src is too small a file, or it is AVIF)."},"GeoScoreRobotsVerdict":{"type":"object","required":["allowed","named"],"properties":{"allowed":{"type":"boolean"},"rule":{"type":"string","description":"The deciding line, such as Disallow: /."},"named":{"type":"boolean","description":"Whether a group names this agent; otherwise the * group decided."}}},"GeoScoreItem":{"type":"object","required":["label","value","where","status","direct"],"description":"One piece of what a person reads on the page.","properties":{"label":{"type":"string","description":"The piece, or its section heading with the piece."},"value":{"type":"string","description":"The piece as the page shows it."},"where":{"type":"string","enum":["html","structured_data","script","rendered_only","frame","image"],"description":"Where the page has it in the HTML ChatGPT-User receives. rendered_only: in no such HTML, only on the rendered page."},"line":{"type":"integer","description":"Its line in the page's HTML text, when it is there."},"status":{"type":"string","enum":["read","missing"],"description":"Whether ChatGPT search keeps it: the copy of the page its crawler keeps holds it in its text, alt text included."},"reason":{"$ref":"#/components/schemas/GeoScoreMissReason"},"direct":{"type":"object","required":["status"],"description":"Whether ChatGPT receives it when it opens the page itself: in the HTML's text, alt text included, or in an image it can read.","properties":{"status":{"type":"string","enum":["read","missing"]},"reason":{"$ref":"#/components/schemas/GeoScoreMissReason"}}},"rendering":{"type":"object","required":["status"],"description":"Whether the copy of the page rendered for AI agents holds it in its text, alt text included. Present when the result has rendering.","properties":{"status":{"type":"string","enum":["read","missing"]}}},"foundIn":{"type":"string","description":"Where the page has a piece search or ChatGPT does not have, such as a line of the HTML, a JSON-LD path, or an image URL with whether ChatGPT can read the image."}}},"GeoScoreFile":{"description":"A file the result links to. Its url is its own access key and opens it without an API key until expiresAt, 30 days after the task.","oneOf":[{"type":"object","required":["status","url","expiresAt"],"properties":{"status":{"type":"string","const":"ok"},"url":{"type":"string","format":"uri"},"expiresAt":{"type":"string","format":"date-time"}}},{"type":"object","required":["status","error"],"properties":{"status":{"type":"string","const":"failed"},"error":{"type":"string","const":"EVIDENCE_FAILED"}}}]},"GeoScoreIssue":{"type":"object","required":["code","basis","points","title","detail","fix","facts","evidence"],"properties":{"code":{"type":"string","enum":["search_opt_out","blocked","javascript_only","structured_data_only","image_only"]},"basis":{"type":"string","enum":["confirmed"],"description":"Our own reading of the page shows it: its HTML, the crawler's copy, its images, robots.txt, HTTP answers."},"points":{"type":["integer","null"],"description":"Score points the issue costs. An issue that holds the score at 0 is worth the score ChatGPT search could give once it reaches the page."},"title":{"type":"string"},"detail":{"type":"string","description":"What causes it."},"fix":{"type":"string","description":"How to fix it."},"facts":{"type":"array","items":{"type":"object","required":["label","value"],"properties":{"label":{"type":"string"},"value":{"type":"string"},"foundIn":{"type":"string"}}}},"evidence":{"type":"array","items":{"type":"string"}}}},"GeoScoreResult":{"type":"object","required":["level","url","finalUrl","score","direct","access","reading","causes","analysis","reference","images"],"properties":{"level":{"type":"string","const":"url"},"url":{"type":"string"},"finalUrl":{"type":"string","description":"The page ChatGPT-User receives after redirects."},"renderedUrl":{"type":"string","description":"The page a person sees after redirects. Another URL than finalUrl means the site serves another version by country."},"score":{"type":["integer","null"],"minimum":0,"maximum":100,"description":"What ChatGPT search keeps of what a person reads on the page, 0-100: the share of its pieces in the copy of the page the search crawler keeps. 0 when robots.txt keeps the page out of ChatGPT search or the site refuses the crawler; null when no browser could show the page, as a person or as the crawler."},"direct":{"type":"object","required":["score","read"],"description":"What ChatGPT receives when it opens the page itself, as when a person gives it the URL.","properties":{"score":{"type":["integer","null"],"minimum":0,"maximum":100,"description":"The share of the page's pieces it receives: the HTML's text and the images it can read. 0 when it could not open the page."},"read":{"type":"integer","description":"Pieces it receives."}}},"pageType":{"type":"string","enum":["product","article","business","software","listing","other"]},"access":{"type":"object","required":["verdict","chatgpt","search","robots","noindex","probes"],"properties":{"verdict":{"type":"string","enum":["open","search_only","blocked","search_opt_out"],"description":"open: ChatGPT opened the page. search_only: it could not, and found the page only among its search results; direct.score is 0. blocked: it could not open the page and did not find it in search; direct.score is 0. search_opt_out: robots.txt keeps the page out of ChatGPT search, so the score is 0."},"chatgpt":{"type":"object","required":["opened","inSearch","searchedFor","observedAt"],"properties":{"opened":{"type":"boolean"},"inSearch":{"type":"boolean","description":"ChatGPT's search returned the page itself."},"lines":{"type":"integer","description":"Lines ChatGPT's reader made of the page."},"searchedFor":{"type":"array","items":{"type":"string"}},"observedAt":{"type":"string","format":"date-time"}}},"search":{"type":"object","required":["refused"],"description":"ChatGPT search's crawler, OAI-SearchBot.","properties":{"refused":{"type":"boolean","description":"The site refused our OAI-SearchBot requests and renders, so ChatGPT search is taken to keep nothing of the page and the score is 0."},"lines":{"type":"integer","description":"Lines of text in the copy of the page the crawler keeps."}}},"blockedBy":{"type":"string","enum":["user_agent","openai_addresses","site"],"description":"Who refused ChatGPT. user_agent: the site refuses the ChatGPT-User agent from any address. openai_addresses: it serves that agent from our address and refuses OpenAI's. site: it refuses our browser too."},"robots":{"type":"object","description":"robots.txt for each OpenAI agent.","properties":{"OAI-SearchBot":{"$ref":"#/components/schemas/GeoScoreRobotsVerdict"},"ChatGPT-User":{"$ref":"#/components/schemas/GeoScoreRobotsVerdict"},"GPTBot":{"$ref":"#/components/schemas/GeoScoreRobotsVerdict"}}},"noindex":{"type":"object","required":["noindex"],"properties":{"noindex":{"type":"boolean"},"source":{"type":"string","enum":["meta","header"]}}},"probes":{"type":"array","description":"The page fetched as each OpenAI agent and as a browser.","items":{"type":"object","required":["agent","blocked"],"properties":{"agent":{"type":"string","enum":["ChatGPT-User","OAI-SearchBot","GPTBot","browser"]},"status":{"type":"integer"},"blocked":{"type":"boolean","description":"Refused: an error status, a bot wall or no answer."},"note":{"type":"string"}}}}}},"reading":{"type":"object","required":["score","facts","read","locations","items"],"properties":{"score":{"type":["integer","null"],"description":"The share of pieces ChatGPT search keeps, before robots.txt holds the score at 0. A refused crawler keeps none."},"facts":{"type":"integer","description":"Pieces of the page checked."},"read":{"type":"integer","description":"Pieces ChatGPT search keeps."},"locations":{"type":"object","additionalProperties":{"type":"integer"},"description":"Pieces counted by where the page has them in the HTML ChatGPT-User receives."},"items":{"type":"array","items":{"$ref":"#/components/schemas/GeoScoreItem"}}}},"causes":{"type":"array","description":"Pieces ChatGPT search does not keep, grouped by reason.","items":{"type":"object","required":["reason","labels"],"properties":{"reason":{"$ref":"#/components/schemas/GeoScoreMissReason"},"labels":{"type":"array","items":{"type":"string"}}}}},"analysis":{"type":"object","required":["summary","potential","direct","issues"],"properties":{"summary":{"type":"string"},"potential":{"type":["integer","null"],"description":"The score with every confirmed issue fixed."},"direct":{"type":"string","description":"What ChatGPT receives when it opens the page itself, against what search keeps, or who refused it and the fix."},"framework":{"type":"string","description":"What the HTML says built the page, such as Next.js."},"issues":{"type":"array","description":"Issues that hold the score at 0 first, then the rest by points.","items":{"$ref":"#/components/schemas/GeoScoreIssue"}}}},"reference":{"type":"string","enum":["rendered","html","none"],"description":"Where the pieces came from: the rendered page, its HTML when the browser met a wall, or none when both did."},"markdown":{"type":"string","description":"The page a person sees, the text of its images in place, as Markdown: the page's own content the score checks under its headings and labels, the menus, reviews and other parts around it folded to a line each, and each piece ChatGPT search does not keep marked where it sits, _(missing: reason)_ on an English page. The header and the marks are in the page's language: English, Korean, Japanese, Chinese, Spanish, French, German or Portuguese, and English for any other."},"screenshot":{"$ref":"#/components/schemas/GeoScoreFile","description":"The first four screens of the page as a person sees it, as a JPEG of a 1366×900 window. Absent when the picture could not be taken."},"images":{"type":"object","required":["read","reused","unread"],"description":"The page's large images. The task is charged 5 credits for each image read now and 2 for each image reused; unread images are free.","properties":{"read":{"type":"integer","description":"Images whose text was read for this task."},"reused":{"type":"integer","description":"Images whose text the account read in the last 90 days, reused without reading them again. 2 credits each."},"unread":{"type":"integer","description":"Images the host refused or that could not be read. They are not charged."}}},"rendering":{"type":"object","required":["score","read"],"description":"The page rendered for AI agents: the HTML a person's browser drew, without scripts, with the text of each image added to its alt text. The copy itself is not part of the result. Absent when no browser could show the page or its drawn HTML is too large to copy.","properties":{"score":{"type":["integer","null"],"minimum":0,"maximum":100,"description":"The share of the page's pieces the copy holds in its text: what an AI agent served the copy receives without opening an image."},"read":{"type":"integer","description":"Pieces the copy holds."}}}}},"AiRenderingSite":{"type":"object","required":["id","host","refreshDays","country","keyPrefix","createdAt","updatedAt"],"properties":{"id":{"type":"string"},"host":{"type":"string","description":"The site's host name, lower case, without a port."},"refreshDays":{"type":"integer","minimum":1,"maximum":28,"description":"Days between renders of a published page. Default 28."},"country":{"type":"string","enum":["US","KR"],"description":"Where the site's pages are rendered from. Default US."},"keyPrefix":{"type":"string","description":"The first 11 characters of the site key, which reads the site's copy list."},"pages":{"type":"integer","description":"Published pages. Absent from a site that was just updated or given a new key."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"AiRenderingPage":{"type":"object","required":["id","url","path","status","copy","taskId","renderedAt","expiresAt","publishedAt","refreshAt","refreshTaskId"],"properties":{"id":{"type":"string"},"url":{"type":"string","description":"The page, tracking parameters removed."},"path":{"type":"string","description":"Path and query that identify the page on its site."},"status":{"type":"string","enum":["rendering","failed","ready","expired"],"description":"Whether the page has a copy for the site to serve. ready: the copy is in the site's copy list. rendering: the first copy is being made. failed: the first render failed; the page is rendered again at refreshAt. expired: the copy's file expired and left the list until the next render."},"copy":{"type":["string","null"],"description":"The page's copy, as an HTML file. Its URL is its access key."},"taskId":{"type":["string","null"],"description":"The task that made the copy: an AI_RENDERING task or the GEO Score it was published from."},"renderedAt":{"type":["string","null"],"format":"date-time"},"expiresAt":{"type":["string","null"],"format":"date-time","description":"When the copy's file expires, 30 days after it was made."},"publishedAt":{"type":"string","format":"date-time"},"refreshAt":{"type":"string","format":"date-time","description":"When the page is rendered next."},"refreshTaskId":{"type":["string","null"],"description":"The AI_RENDERING task rendering the page now or last tried. Read it with GET /v1/async/task/{id}."}}},"AiRenderingSiteRequest":{"type":"object","required":["host"],"additionalProperties":false,"properties":{"host":{"type":"string","description":"The public host name the site's CDN serves, such as www.example.com. Which AI agents get a copy is set in the site's CDN."},"refreshDays":{"type":"integer","minimum":1,"maximum":28},"country":{"type":"string","enum":["US","KR"]}}},"AiRenderingSiteUpdate":{"type":"object","additionalProperties":false,"properties":{"refreshDays":{"type":"integer","minimum":1,"maximum":28,"description":"Moves the next render of each page with a copy to its last render plus the new interval."},"country":{"type":"string","enum":["US","KR"],"description":"Used from the next render."}}},"AiRenderingPublishRequest":{"type":"object","additionalProperties":false,"description":"Send url to render the page now, or taskId to publish the copy a completed GEO Score made.","properties":{"url":{"type":"string","description":"A page on the site's host. With taskId, the page to publish the GEO Score's copy on; by default the page the GEO Score scored."},"taskId":{"type":"string","description":"A completed GEO_SCORE task of the account, scored from the site's country."}}},"AiRenderingSiteKeyResponse":{"type":"object","required":["success","site","key"],"properties":{"success":{"type":"boolean"},"site":{"$ref":"#/components/schemas/AiRenderingSite"},"key":{"type":"string","description":"The site key, rs_ and 64 hex characters. It is shown only in this response; querying.ai stores its hash."}}},"AiRenderingSiteDetail":{"type":"object","required":["success","site","pages"],"properties":{"success":{"type":"boolean"},"site":{"$ref":"#/components/schemas/AiRenderingSite"},"pages":{"type":"array","items":{"$ref":"#/components/schemas/AiRenderingPage"},"description":"Published pages, newest first."}}},"AiRenderingPageResponse":{"type":"object","required":["success","page"],"properties":{"success":{"type":"boolean"},"page":{"$ref":"#/components/schemas/AiRenderingPage"},"taskId":{"type":"string","description":"The AI_RENDERING task rendering the page. Only when the page was published by url."}}},"AiRenderingCopy":{"type":"object","required":["path","url","copy","renderedAt","expiresAt"],"properties":{"path":{"type":"string","description":"Path and query that identify the page on its site, tracking parameters removed."},"url":{"type":"string","description":"The page."},"copy":{"type":"string","description":"The copy's HTML file, downloadable without a key: its URL is its access key."},"renderedAt":{"type":"string","format":"date-time","description":"When the copy was rendered. It changes when the page is rendered again."},"expiresAt":{"type":"string","format":"date-time","description":"When the copy's file expires. Do not send the copy after it."}}},"AiRenderingCopyList":{"type":"object","required":["success","host","copies"],"properties":{"success":{"type":"boolean"},"host":{"type":"string","description":"The site's host name."},"copies":{"type":"array","items":{"$ref":"#/components/schemas/AiRenderingCopy"},"description":"Every published page whose copy has not expired, by path."}}}}},"webhooks":{"taskCompleted":{"post":{"summary":"Task result callback","description":"Sent to the `webhook.url` you supplied at submit time, for both `COMPLETED` and `FAILED` tasks. Return any `2xx` to acknowledge.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookBody"}}}},"responses":{"200":{"description":"Acknowledged. Any non-2xx or a timeout triggers a retry."}}}},"monitorEvent":{"post":{"summary":"Monitor change event","description":"Sent to a monitor's webhookUrl when a prompt's state crosses: the brand starts or stops appearing in at least half of its last five answers, a competitor is in at least half and in more of them than the brand, or an answer cites a site the monitor never saw cited. One event per crossing. Signed with the querying-webhook-* headers using the SHA-256 digest of the API key that set webhookUrl; querying-webhook-id is the event id. Retried at 2, 4, 8 and 16 minutes.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorEventBody"}}}},"responses":{"200":{"description":"Acknowledged. Any non-2xx or a timeout triggers a retry."}}}}}}