Documentation Index
Fetch the complete documentation index at: https://webscraping.titannet.io/docs/llms.txt
Use this file to discover all available pages before exploring further.
The api_call action type is for HTTP tool steps: call partner APIs, internal microservices, or other structured endpoints with payloads and validation defined in your task (and template or script). It is not “scraping HTML”; it is first-class orchestration alongside search, crawl, and scrape.
Examples use TITAN_API_URL and TITAN_TOKEN. Tab titles match other integration pages. Rust: ureq + serde_json.
When to use api_call
- A vendor exposes REST or GraphQL you must call before or after web steps.
- You need stable JSON from an API plus on-page signals only available via
scrape.
- You want one Titan task to represent API + web work with shared execution history and billing.
The service applies extra validation for certain api_call URL and payload combinations—expect clear 400 errors from POST /api/v1/tasks when configuration is inconsistent.
Single-action example (POST /api/v1/tasks)
Secrets (API keys, OAuth client secrets) must not appear in payload on create if your policy forbids it—use secret_payload on POST /api/v1/tasks/:id/run instead, or inject via your vault integration at run time.
cURL
Go
TypeScript
Python
Rust
curl -sS -X POST "$TITAN_API_URL/api/v1/tasks" \
-H "Authorization: Bearer $TITAN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Shipping quotes API pull",
"objective": "POST to the carrier quote API and normalize the JSON response",
"execution_type": "single",
"urls": ["https://api.carrier.example/v1/quotes"],
"action_type": "api_call",
"input_source": "static_urls",
"template_slug": "carrier-quote-json",
"payload": {
"origin_zip": "94107",
"destination_zip": "10001",
"weight_kg": 12.5
},
"limits": {
"timeout_seconds": 20,
"max_retries": 2
}
}'
body := map[string]any{
"name": "Shipping quotes API pull",
"objective": "POST to the carrier quote API and normalize the JSON response",
"execution_type": "single",
"urls": []string{"https://api.carrier.example/v1/quotes"},
"action_type": "api_call",
"input_source": "static_urls",
"template_slug": "carrier-quote-json",
"payload": map[string]any{
"origin_zip": "94107", "destination_zip": "10001", "weight_kg": 12.5,
},
"limits": map[string]any{"timeout_seconds": 20, "max_retries": 2},
}
b, _ := json.Marshal(body)
req, _ := http.NewRequest("POST", os.Getenv("TITAN_API_URL")+"/api/v1/tasks", bytes.NewReader(b))
req.Header.Set("Authorization", "Bearer "+os.Getenv("TITAN_TOKEN"))
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
out, _ := io.ReadAll(resp.Body)
fmt.Println(string(out))
const base = process.env.TITAN_API_URL!;
const token = process.env.TITAN_TOKEN!;
const res = await fetch(`${base}/api/v1/tasks`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Shipping quotes API pull",
objective: "POST to the carrier quote API and normalize the JSON response",
execution_type: "single",
urls: ["https://api.carrier.example/v1/quotes"],
action_type: "api_call",
input_source: "static_urls",
template_slug: "carrier-quote-json",
payload: {
origin_zip: "94107",
destination_zip: "10001",
weight_kg: 12.5,
},
limits: { timeout_seconds: 20, max_retries: 2 },
}),
});
console.log(await res.text());
import json
import os
import urllib.request
payload = {
"name": "Shipping quotes API pull",
"objective": "POST to the carrier quote API and normalize the JSON response",
"execution_type": "single",
"urls": ["https://api.carrier.example/v1/quotes"],
"action_type": "api_call",
"input_source": "static_urls",
"template_slug": "carrier-quote-json",
"payload": {
"origin_zip": "94107",
"destination_zip": "10001",
"weight_kg": 12.5,
},
"limits": {"timeout_seconds": 20, "max_retries": 2},
}
req = urllib.request.Request(
f"{os.environ['TITAN_API_URL']}/api/v1/tasks",
data=json.dumps(payload).encode(),
headers={
"Authorization": f"Bearer {os.environ['TITAN_TOKEN']}",
"Content-Type": "application/json",
},
method="POST",
)
with urllib.request.urlopen(req) as resp:
print(resp.read().decode())
use serde_json::json;
let base = std::env::var("TITAN_API_URL").expect("TITAN_API_URL");
let token = std::env::var("TITAN_TOKEN").expect("TITAN_TOKEN");
let body = json!({
"name": "Shipping quotes API pull",
"objective": "POST to the carrier quote API and normalize the JSON response",
"execution_type": "single",
"urls": ["https://api.carrier.example/v1/quotes"],
"action_type": "api_call",
"input_source": "static_urls",
"template_slug": "carrier-quote-json",
"payload": {
"origin_zip": "94107",
"destination_zip": "10001",
"weight_kg": 12.5
},
"limits": { "timeout_seconds": 20, "max_retries": 2 }
});
let resp = ureq::post(format!("{base}/api/v1/tasks"))
.set("Authorization", &format!("Bearer {token}"))
.set("Content-Type", "application/json")
.send_json(body)
.expect("create");
println!("{}", resp.into_string().expect("body"));
Chained example (api_call → scrape)
Use an execution_plan when the API response contains URLs you must scrape next:
{
"name": "Resolve listings via API then scrape PDPs",
"objective": "Fetch listing URLs from our marketplace API, then scrape each PDP",
"execution_type": "single",
"execution_plan": {
"steps": [
{
"step_id": "listings",
"action_type": "api_call",
"input_source": "static_urls",
"template_slug": "marketplace-listing-api",
"limits": { "timeout_seconds": 15 }
},
{
"step_id": "pdps",
"action_type": "scrape",
"input_source": "previous_step",
"template_slug": "commerce-pdp",
"output_schema": {
"type": "object",
"properties": {
"price": { "type": "number" }
}
}
}
]
}
}
Trigger via executions API
Replace the UUID with a real task_id. Modular tasks load the stored workflow; you generally do not override execution_plan on this call.
cURL
Go
TypeScript
Python
Rust
curl -sS -X POST "$TITAN_API_URL/api/v1/executions" \
-H "Authorization: Bearer $TITAN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"task_id": "00000000-0000-0000-0000-000000000000",
"payload": { "refresh": true }
}'
body := map[string]any{
"task_id": "00000000-0000-0000-0000-000000000000",
"payload": map[string]bool{"refresh": true},
}
b, _ := json.Marshal(body)
req, _ := http.NewRequest("POST", os.Getenv("TITAN_API_URL")+"/api/v1/executions", bytes.NewReader(b))
req.Header.Set("Authorization", "Bearer "+os.Getenv("TITAN_TOKEN"))
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
out, _ := io.ReadAll(resp.Body)
fmt.Println(string(out))
const base = process.env.TITAN_API_URL!;
const token = process.env.TITAN_TOKEN!;
const res = await fetch(`${base}/api/v1/executions`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
task_id: "00000000-0000-0000-0000-000000000000",
payload: { refresh: true },
}),
});
console.log(await res.text());
import json
import os
import urllib.request
payload = {
"task_id": "00000000-0000-0000-0000-000000000000",
"payload": {"refresh": True},
}
req = urllib.request.Request(
f"{os.environ['TITAN_API_URL']}/api/v1/executions",
data=json.dumps(payload).encode(),
headers={
"Authorization": f"Bearer {os.environ['TITAN_TOKEN']}",
"Content-Type": "application/json",
},
method="POST",
)
with urllib.request.urlopen(req) as resp:
print(resp.read().decode())
use serde_json::json;
let base = std::env::var("TITAN_API_URL").expect("TITAN_API_URL");
let token = std::env::var("TITAN_TOKEN").expect("TITAN_TOKEN");
let body = json!({
"task_id": "00000000-0000-0000-0000-000000000000",
"payload": { "refresh": true }
});
let resp = ureq::post(format!("{base}/api/v1/executions"))
.set("Authorization", &format!("Bearer {token}"))
.set("Content-Type", "application/json")
.send_json(body)
.expect("trigger");
println!("{}", resp.into_string().expect("body"));