Copilot API
Copilot's Bing-grounded answer with every source it cited.
Price
$2.74 per 1,000 requests at Starter, down to $2.74 at Max, deducted from your prepaid USD balance.
Endpoint
POST /v1/monitor/copilot
Countries
Any country.
Request
curl -X POST "https://api.answerline.dev/v1/monitor/copilot" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"prompt":"Cheapest way to send money abroad","country":"US"}'
Request options
| Field | Type | Description |
|---|---|---|
prompt * |
string |
Prompt submitted to Copilot, up to 2,000 characters. A longer prompt is refused with a 400 that states its length. |
country * |
string |
Code of the country or region used to localize the response |
include |
object |
Flags that add extra output formats to the response (optional) |
include.html |
boolean |
`true` is refused with a validation error on this engine. |
include.markdown |
boolean |
Add a markdown version of the response to the result |
include.rawResponse |
boolean |
Return the answer as normalized stream events. For the engine's answer as received, use `include.rawWire`. |
include.rawWire |
boolean |
Return the engine's own response as received in result.rawWire: the answer stream, the rendered results pages or the RSS feed, without Gemini's detected location or ChatGPT's session tokens; null where it was not captured. Free. See https://answerline.dev/docs/output-formats#raw-wire |
include.screenshot |
boolean |
Return a full-page PNG screenshot of the engine's page as it showed the finished answer, in result.screenshot: a link, or one link per results page on Google Search. On ChatGPT, Gemini, AI Mode, Google Search, Perplexity and Grok; other engines refuse it with a 400. Absent when the answer was read without a rendered page. Free. See https://answerline.dev/docs/output-formats#screenshots |
state |
string |
State code for targeting below the country level (e.g., "CA"; "DC" included). Allowed only when country is "US". Served for Gemini only; ChatGPT, Copilot, Perplexity and Grok refuse `state` with a 400, uncharged. "DC" fails uncharged: no exit serves it. |
answerDepth |
"any" | "full" | "quick" |
How deep an answer the engine writes, where it offers a choice. any (the default): a full answer when the engine can give one now, else its short one. full: a full answer or a retryable error, never charged. quick: the short one, the fastest. Perplexity offers the choice; every other engine has one depth and ignores the field. provenance.answerDepth says what was served. Same price for every value. See https://answerline.dev/docs/engine-features/#answer-depth |
What you get back
Field in result | Type | Description |
|---|---|---|
text | string | Text of Copilot's reply |
markdown | string | Copilot's reply as Markdown; returned only if include.markdown is true |
sources | object[] | Sources the response cites |
citationPills | object[] | Citation pills that appear inline in the Copilot answer. Every element pairs one pill with one source: a pill backed by N sources (a chip made from consecutive citation events) yields N elements with the same `citationPillId`, each holding that source's own `label`, `url` and `domain`. Grouping by `citationPillId` rebuilds the pills. Not present in `result` if the answer has no pills. |
The Copilot answer versus Microsoft’s developer offerings
This endpoint returns the answer the consumer Copilot app gives a user, as text and markdown, with the sources it cites and its citation chips. The searches it ran, product cards and map results are coming.
Developers used to reach Bing results through the Bing Search APIs. Microsoft’s lifecycle notice (checked 2026-09-17, learn.microsoft.com) states those APIs retired on August 11, 2025 and encourages customers to migrate to Grounding with Bing Search as part of Azure AI Agents. Grounding lets your own agent use web data when it generates a response. The answer comes from your model and instructions, not Copilot’s.
For measurement that leaves what only the consumer answer has: Copilot’s own wording (which brands it names, in which order, with which caveats) and the pages it cites for it. Its commercial and local modules and its query fan-out are coming: shoppingCards with structured prices, sellers and ratings, map with businesses, addresses, coordinates, review aggregations and open state, and searchQueries with the web searches Copilot ran. None of the three is returned yet.
An annotated response
The excerpt follows the result schema for POST /v1/monitor/copilot. Values are illustrative.
{
"success": true,
"result": {
"text": "The cheapest option depends on the amount and destination...",
// Cited pages in order: url and label.
"sources": [
{
"position": 1,
"url": "https://www.example-finance.com/guides/international-transfer-fees",
"label": "International transfer fees compared"
}
],
// One entry per (chip, source) pair; see Copilot sources. Omitted when the answer shows no chips.
"citationPills": [
{ "citationPillId": 1, "position": 1, "url": "https://www.example-finance.com/guides/international-transfer-fees", "domain": "example-finance.com", "label": "International transfer fees compared" }
]
// searchQueries, shoppingCards and map are coming; not returned yet.
}
}
Shopping cards and map results are coming; Copilot shopping and map results describes their fields.
Synchronous calls
A synchronous call can take up to five minutes.
Python (requests)
import os
import requests
API = "https://api.answerline.dev"
HEADERS = {"Authorization": f"Bearer {os.environ['API_KEY']}"}
resp = requests.post(
f"{API}/v1/monitor/copilot",
headers=HEADERS,
json={"prompt": "Cheapest way to send money abroad", "country": "US"},
timeout=330,
)
if resp.status_code != 200:
raise RuntimeError(f"{resp.status_code} {resp.headers.get('X-Request-Id')} {resp.text}")
result = resp.json()["result"]
print(result["text"][:200])
for src in result.get("sources", []):
print(src.get("position"), src.get("url"), src.get("label"))
TypeScript (fetch)
const API = "https://api.answerline.dev";
const res = await fetch(`${API}/v1/monitor/copilot`, {
method: "POST",
headers: { Authorization: `Bearer ${process.env.API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({ prompt: "Best noise-cancelling headphones under $300", country: "US" }),
signal: AbortSignal.timeout(330_000),
});
if (!res.ok) throw new Error(`${res.status} ${res.headers.get("X-Request-Id")} ${await res.text()}`);
const { result } = await res.json();
for (const s of result.sources ?? []) {
console.log(s.position, s.url, s.label);
}
console.log("credits charged:", res.headers.get("X-Credits-Charged"));
Batches: async tasks and a webhook
Tasks cost $0.00274, wait in your queue until they start and post their result to your webhook. POST /v1/async/task/batch takes 1 to 500 tasks, each admitted on its own and answered by index.
Python: submit a batch
import datetime
import os
import requests
API = "https://api.answerline.dev"
HEADERS = {"Authorization": f"Bearer {os.environ['API_KEY']}"}
day = datetime.date.today().isoformat()
prompts = ["Best credit union for a first mortgage", "Cheapest way to send money abroad"]
tasks = [
{
"taskType": "COPILOT",
"payload": {"prompt": prompt, "country": "US"},
"idempotencyKey": f"copilot-{i}-US-{day}",
"webhook": {"url": "https://your-app.example/hooks/answers"},
}
for i, prompt in enumerate(prompts)
]
resp = requests.post(f"{API}/v1/async/task/batch", headers=HEADERS, json=tasks, timeout=60)
resp.raise_for_status()
print(resp.json()["summary"])
TypeScript: receive and verify deliveries (Express)
The body is the GET /v1/async/task/{taskId} shape. Verify Webhook-Signature over the raw body before parsing.
import express from "express";
import { createHmac, timingSafeEqual } from "node:crypto";
function verify(raw: Buffer, header: string | undefined, secret: string, toleranceSeconds = 300): boolean {
const pairs = (header ?? "").split(",").map((part) => part.split("="));
const stamps = pairs.filter(([k]) => k === "t").map(([, v]) => v);
const sigs = pairs.filter(([k]) => k === "v1").map(([, v]) => v);
if (stamps.length !== 1 || !/^\d+$/.test(stamps[0]) || sigs.length === 0) return false;
if (Math.abs(Date.now() / 1000 - Number(stamps[0])) > toleranceSeconds) return false;
const expected = createHmac("sha256", secret).update(`${stamps[0]}.`).update(raw).digest();
return sigs.some((sig) => {
const given = Buffer.from(sig, "hex");
return given.length === expected.length && timingSafeEqual(given, expected);
});
}
const app = express();
app.post("/hooks/answers", express.raw({ type: "application/json" }), (req, res) => {
if (!verify(req.body, req.get("webhook-signature"), process.env.WEBHOOK_SECRET!)) return res.sendStatus(400);
const delivery = JSON.parse(req.body.toString("utf8"));
if (delivery.test) return res.sendStatus(204);
const { task, response, credits } = delivery;
if (task.status === "COMPLETED") {
const { sources = [] } = response.result;
const domains = [...new Set(sources.map((s: any) => new URL(s.url).hostname))].sort();
console.log(task.idempotencyKey, domains, credits.creditsCharged);
} else {
console.warn(task.idempotencyKey, "failed:", response.error.code);
}
res.sendStatus(204);
});
app.listen(3000);
Deliveries can repeat or arrive out of order: deduplicate on task.id. See webhooks.
Geo targeting
| Field | Values | Notes |
|---|---|---|
country |
ISO 3166-1 alpha-2 | Required. GET /v1/countries?model=copilot lists supported codes. |
state |
Not available | A request that sends state is refused with a 400 and not billed. |
Include flags and what they cost
| Flag | Adds to result |
Price |
|---|---|---|
include.markdown |
markdown |
0 |
include.rawResponse |
rawResponse, the answer as normalized stream events |
0 |
include.rawWire |
rawWire: always null on Copilot (what it holds) |
0 |
At the Starter tier every Copilot request costs $0.00274.
result.provenance reads searchMode forced: every answer searches the web (all fields).
Common workloads
- AI visibility tracking on Microsoft’s assistant. See AI visibility tracking and monitoring Copilot.
- Citation share: which domains Copilot cites for your category, from
sources. See competitor analysis. - Coming with
map,shoppingCardsandsearchQueries: local presence, product and price monitoring, and keyword discovery from the searches Copilot runs.
Pitfalls
sources depends on the answer and can be empty; default it to an empty list in your code. citationPills is omitted when the answer shows no chips. searchQueries, shoppingCards and map are not returned yet.
Before comparing Copilot with ChatGPT or Google AI Mode, map each engine’s sources to a common record (URL, domain, position).
A large batch is many tasks in your queue, which holds about 100,000 tasks of a typical prompt at a time; there is no concurrency cap and no request rate limit. See rate limits.
Copilot answers differ between runs of the same prompt and market. Take several samples per period and report rates with sample sizes; see AI answer volatility.
How failures are billed
An accepted request reserves its price, $0.00274 on every tier, and is charged only on success. Failures are charged nothing and release the reservation, including tasks that never start within 4 hours (QUEUE_WAIT_EXCEEDED; resubmit them) and queued tasks you delete with DELETE /v1/async/queue. Batch items refused with INSUFFICIENT_CREDITS create nothing and claim no idempotency key, so you can resubmit them unchanged after topping up. See credits.
Related: monitoring Copilot answers and the Copilot API options compared.
Questions
How much does a Copilot request cost?
At the Starter tier a request costs $0.00274. The Copilot include flags (markdown, rawResponse and rawWire) add nothing to the price.
Does this endpoint use the Bing Search API?
No. It returns the answer the consumer Copilot app shows its users. Microsoft retired the Bing Search APIs on August 11, 2025 and points customers to Grounding with Bing Search in Azure AI Agents instead.
Does the Copilot result include map results?
Not yet; map results are coming. Today a Copilot result carries the answer text, markdown and its cited sources. Each map entry will be a business or place from the answer: name, position, Google Place ID, address and coordinates, phone number, website, review aggregations per provider, photos, open state, category and price level where available.
Can I target a US state with Copilot?
No. Copilot takes a country only. A request that sends state is refused with a 400 and not billed.
Are failed Copilot requests charged?
No. Failed requests are charged nothing and their reservation is released. Only completed requests are charged.