curl --request POST \
--url https://api.paywithlocus.com/api/wrapped/credits/router/web-research \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"query": "<string>",
"maxResults": 10,
"mode": "balanced",
"maxProviders": 4,
"topic": "general",
"recencyDays": 183,
"country": "<string>",
"includeDomains": [
"<string>"
],
"excludeDomains": [
"<string>"
],
"includeImages": false,
"providers": [
"<string>"
],
"maxCredits": "<string>",
"rails": [],
"externalUserId": "<string>",
"attribution": {}
}
'import requests
url = "https://api.paywithlocus.com/api/wrapped/credits/router/web-research"
payload = {
"query": "<string>",
"maxResults": 10,
"mode": "balanced",
"maxProviders": 4,
"topic": "general",
"recencyDays": 183,
"country": "<string>",
"includeDomains": ["<string>"],
"excludeDomains": ["<string>"],
"includeImages": False,
"providers": ["<string>"],
"maxCredits": "<string>",
"rails": [],
"externalUserId": "<string>",
"attribution": {}
}
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
query: '<string>',
maxResults: 10,
mode: 'balanced',
maxProviders: 4,
topic: 'general',
recencyDays: 183,
country: '<string>',
includeDomains: ['<string>'],
excludeDomains: ['<string>'],
includeImages: false,
providers: ['<string>'],
maxCredits: '<string>',
rails: [],
externalUserId: '<string>',
attribution: {}
})
};
fetch('https://api.paywithlocus.com/api/wrapped/credits/router/web-research', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.paywithlocus.com/api/wrapped/credits/router/web-research",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'query' => '<string>',
'maxResults' => 10,
'mode' => 'balanced',
'maxProviders' => 4,
'topic' => 'general',
'recencyDays' => 183,
'country' => '<string>',
'includeDomains' => [
'<string>'
],
'excludeDomains' => [
'<string>'
],
'includeImages' => false,
'providers' => [
'<string>'
],
'maxCredits' => '<string>',
'rails' => [
],
'externalUserId' => '<string>',
'attribution' => [
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"Idempotency-Key: <idempotency-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.paywithlocus.com/api/wrapped/credits/router/web-research"
payload := strings.NewReader("{\n \"query\": \"<string>\",\n \"maxResults\": 10,\n \"mode\": \"balanced\",\n \"maxProviders\": 4,\n \"topic\": \"general\",\n \"recencyDays\": 183,\n \"country\": \"<string>\",\n \"includeDomains\": [\n \"<string>\"\n ],\n \"excludeDomains\": [\n \"<string>\"\n ],\n \"includeImages\": false,\n \"providers\": [\n \"<string>\"\n ],\n \"maxCredits\": \"<string>\",\n \"rails\": [],\n \"externalUserId\": \"<string>\",\n \"attribution\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.paywithlocus.com/api/wrapped/credits/router/web-research")
.header("Idempotency-Key", "<idempotency-key>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"query\": \"<string>\",\n \"maxResults\": 10,\n \"mode\": \"balanced\",\n \"maxProviders\": 4,\n \"topic\": \"general\",\n \"recencyDays\": 183,\n \"country\": \"<string>\",\n \"includeDomains\": [\n \"<string>\"\n ],\n \"excludeDomains\": [\n \"<string>\"\n ],\n \"includeImages\": false,\n \"providers\": [\n \"<string>\"\n ],\n \"maxCredits\": \"<string>\",\n \"rails\": [],\n \"externalUserId\": \"<string>\",\n \"attribution\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.paywithlocus.com/api/wrapped/credits/router/web-research")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"query\": \"<string>\",\n \"maxResults\": 10,\n \"mode\": \"balanced\",\n \"maxProviders\": 4,\n \"topic\": \"general\",\n \"recencyDays\": 183,\n \"country\": \"<string>\",\n \"includeDomains\": [\n \"<string>\"\n ],\n \"excludeDomains\": [\n \"<string>\"\n ],\n \"includeImages\": false,\n \"providers\": [\n \"<string>\"\n ],\n \"maxCredits\": \"<string>\",\n \"rails\": [],\n \"externalUserId\": \"<string>\",\n \"attribution\": {}\n}"
response = http.request(request)
puts response.read_body{
"objective": "structured_answer",
"route": {
"strategy": "web_search",
"successfulProviders": 1,
"attemptedProviders": 1
},
"object": "locus.web_research",
"capability": "web.research",
"routerVersion": "2026-09-14.v28",
"query": "<string>",
"partial": true,
"evidence": [
{
"kind": "structured_data",
"title": "<string>",
"url": "<string>",
"sourceCount": 2,
"excerpt": "<string>",
"publishedAt": "<string>",
"score": 0.5
}
],
"images": [
{
"url": "<string>",
"title": "<string>",
"sourceUrl": "<string>"
}
],
"structuredData": {
"format": "json",
"source": {
"name": "<string>",
"url": "<string>"
},
"value": true
},
"billing": {
"chargedCredits": "<string>",
"successfulProviders": 1,
"attemptedProviders": 1
},
"answer": "<string>",
"references": [
{
"id": "<string>",
"url": "<string>",
"title": "<string>",
"startIndex": 1,
"endIndex": 1
}
],
"completionStatus": "complete",
"stopReason": "completed",
"effort": "light",
"output": true,
"routingPolicy": {
"requestedMode": "shadow",
"effectiveMode": "static",
"accepted": true,
"applied": true,
"policyId": "<string>",
"predictedRouteId": "<string>",
"predictedDecision": "single",
"confidence": 0.5,
"fallbackReason": "policy_unavailable"
}
}Run Web Research
With effort set, returns a grounded answer with citations. Without effort, uses the legacy structured-source or multi-provider evidence contract.
curl --request POST \
--url https://api.paywithlocus.com/api/wrapped/credits/router/web-research \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"query": "<string>",
"maxResults": 10,
"mode": "balanced",
"maxProviders": 4,
"topic": "general",
"recencyDays": 183,
"country": "<string>",
"includeDomains": [
"<string>"
],
"excludeDomains": [
"<string>"
],
"includeImages": false,
"providers": [
"<string>"
],
"maxCredits": "<string>",
"rails": [],
"externalUserId": "<string>",
"attribution": {}
}
'import requests
url = "https://api.paywithlocus.com/api/wrapped/credits/router/web-research"
payload = {
"query": "<string>",
"maxResults": 10,
"mode": "balanced",
"maxProviders": 4,
"topic": "general",
"recencyDays": 183,
"country": "<string>",
"includeDomains": ["<string>"],
"excludeDomains": ["<string>"],
"includeImages": False,
"providers": ["<string>"],
"maxCredits": "<string>",
"rails": [],
"externalUserId": "<string>",
"attribution": {}
}
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
query: '<string>',
maxResults: 10,
mode: 'balanced',
maxProviders: 4,
topic: 'general',
recencyDays: 183,
country: '<string>',
includeDomains: ['<string>'],
excludeDomains: ['<string>'],
includeImages: false,
providers: ['<string>'],
maxCredits: '<string>',
rails: [],
externalUserId: '<string>',
attribution: {}
})
};
fetch('https://api.paywithlocus.com/api/wrapped/credits/router/web-research', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.paywithlocus.com/api/wrapped/credits/router/web-research",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'query' => '<string>',
'maxResults' => 10,
'mode' => 'balanced',
'maxProviders' => 4,
'topic' => 'general',
'recencyDays' => 183,
'country' => '<string>',
'includeDomains' => [
'<string>'
],
'excludeDomains' => [
'<string>'
],
'includeImages' => false,
'providers' => [
'<string>'
],
'maxCredits' => '<string>',
'rails' => [
],
'externalUserId' => '<string>',
'attribution' => [
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"Idempotency-Key: <idempotency-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.paywithlocus.com/api/wrapped/credits/router/web-research"
payload := strings.NewReader("{\n \"query\": \"<string>\",\n \"maxResults\": 10,\n \"mode\": \"balanced\",\n \"maxProviders\": 4,\n \"topic\": \"general\",\n \"recencyDays\": 183,\n \"country\": \"<string>\",\n \"includeDomains\": [\n \"<string>\"\n ],\n \"excludeDomains\": [\n \"<string>\"\n ],\n \"includeImages\": false,\n \"providers\": [\n \"<string>\"\n ],\n \"maxCredits\": \"<string>\",\n \"rails\": [],\n \"externalUserId\": \"<string>\",\n \"attribution\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.paywithlocus.com/api/wrapped/credits/router/web-research")
.header("Idempotency-Key", "<idempotency-key>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"query\": \"<string>\",\n \"maxResults\": 10,\n \"mode\": \"balanced\",\n \"maxProviders\": 4,\n \"topic\": \"general\",\n \"recencyDays\": 183,\n \"country\": \"<string>\",\n \"includeDomains\": [\n \"<string>\"\n ],\n \"excludeDomains\": [\n \"<string>\"\n ],\n \"includeImages\": false,\n \"providers\": [\n \"<string>\"\n ],\n \"maxCredits\": \"<string>\",\n \"rails\": [],\n \"externalUserId\": \"<string>\",\n \"attribution\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.paywithlocus.com/api/wrapped/credits/router/web-research")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"query\": \"<string>\",\n \"maxResults\": 10,\n \"mode\": \"balanced\",\n \"maxProviders\": 4,\n \"topic\": \"general\",\n \"recencyDays\": 183,\n \"country\": \"<string>\",\n \"includeDomains\": [\n \"<string>\"\n ],\n \"excludeDomains\": [\n \"<string>\"\n ],\n \"includeImages\": false,\n \"providers\": [\n \"<string>\"\n ],\n \"maxCredits\": \"<string>\",\n \"rails\": [],\n \"externalUserId\": \"<string>\",\n \"attribution\": {}\n}"
response = http.request(request)
puts response.read_body{
"objective": "structured_answer",
"route": {
"strategy": "web_search",
"successfulProviders": 1,
"attemptedProviders": 1
},
"object": "locus.web_research",
"capability": "web.research",
"routerVersion": "2026-09-14.v28",
"query": "<string>",
"partial": true,
"evidence": [
{
"kind": "structured_data",
"title": "<string>",
"url": "<string>",
"sourceCount": 2,
"excerpt": "<string>",
"publishedAt": "<string>",
"score": 0.5
}
],
"images": [
{
"url": "<string>",
"title": "<string>",
"sourceUrl": "<string>"
}
],
"structuredData": {
"format": "json",
"source": {
"name": "<string>",
"url": "<string>"
},
"value": true
},
"billing": {
"chargedCredits": "<string>",
"successfulProviders": 1,
"attemptedProviders": 1
},
"answer": "<string>",
"references": [
{
"id": "<string>",
"url": "<string>",
"title": "<string>",
"startIndex": 1,
"endIndex": 1
}
],
"completionStatus": "complete",
"stopReason": "completed",
"effort": "light",
"output": true,
"routingPolicy": {
"requestedMode": "shadow",
"effectiveMode": "static",
"accepted": true,
"applied": true,
"policyId": "<string>",
"predictedRouteId": "<string>",
"predictedDecision": "single",
"confidence": 0.5,
"fallbackReason": "policy_unavailable"
}
}Authorizations
Tenant secret key (lcr_…). Server-side only.
Headers
Required only when the end-user JWT carries sid. Send the original high-entropy session value; sid is its SHA-256 fingerprint. Ignored for secret-key authentication.
16 - 128^[A-Za-z0-9][A-Za-z0-9._:-]{15,127}$Reuse the same value only when retrying the same logical request.
1 - 255Body
Search or research request.
^\s*(?:\S|\S[\s\S]{0,398}\S)\s*$1 <= x <= 20fast, balanced, comprehensive 1 <= x <= 13Legacy mode selector retained for compatible clients.
balanced, cost, quality, speed general, news 1 <= x <= 365^[A-Za-z]{2}$201\S201\S13Provider ID. Available values: agent402, agentstools, andi, brave, dataforseo, exa, firecrawl, linkup, parallel, perplexity, seltz, serper, tavily. Matching ignores case and surrounding whitespace.
^\s*(?:[aA][gG][eE][nN][tT]402|[aA][gG][eE][nN][tT][sS][tT][oO][oO][lL][sS]|[aA][nN][dD][iI]|[bB][rR][aA][vV][eE]|[dD][aA][tT][aA][fF][oO][rR][sS][eE][oO]|[eE][xX][aA]|[fF][iI][rR][eE][cC][rR][aA][wW][lL]|[lL][iI][nN][kK][uU][pP]|[pP][aA][rR][aA][lL][lL][eE][lL]|[pP][eE][rR][pP][lL][eE][xX][iI][tT][yY]|[sS][eE][lL][tT][zZ]|[sS][eE][rR][pP][eE][rR]|[tT][aA][vV][iI][lL][yY])\s*$Aggregate hard charge ceiling in workspace credits. Decimal strings support up to six fractional digits; numeric values are rounded down to six digits.
^\s*(?=[0-9.]{1,100}\s*$)0*(?:(?:[1-9]\d{0,11})(?:\.\d{1,6})?|1000000000000(?:\.0{1,6})?|0\.(?=\d{0,5}[1-9])\d{1,6})\s*$Legacy access-path field retained for compatible clients.
api-key, mpp, x402 Optional end-user billing attribution for a tenant secret key.
1\SOptional JSON ledger metadata such as a task or customer identifier.
Explicitly request a grounded answer. Omit only for the legacy evidence-only contract.
light, medium, heavy Optional bounded JSON object schema for the answer. Requires effort and preserves the same grounded-reference envelope.
Show child attributes
Show child attributes
Response
Result, sources, and billing receipt
- Option 1
- Option 2
- Option 3
find_sources, structured_answer, resolved_answer "structured_answer"- Option 1
- Option 2
- Option 3
- Option 4
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
complete, partial completed, provider_incomplete light, medium, heavy Exact JSON value returned by the selected structured endpoint.
Show child attributes
Show child attributes