GeoTasker API
Generate animated geospatial story videos programmatically. Create narrated explainer videos with maps, charts, and data visualizations.
Authentication
All requests require an API key. Pass it via the X-API-Key header or as a Bearer token.
| Method | Example |
|---|---|
| Header (preferred) | X-API-Key: gt_live_a1b2c3... |
| Bearer token | Authorization: Bearer gt_live_a1b2c3... |
API keys use the format gt_live_<64 hex chars>. Keys are created from your dashboard and can have scopes:
render— required forPOST /rendergenerate— required forPOST /generate
curl https://geotasker.ai/api/v1/videos \
-H "X-API-Key: gt_live_your_key_here"Rate Limits
Limits are enforced per API key using a sliding window. When exceeded, the API returns 429 with a Retry-After header.
| Tier | Per Minute | Per Hour | Per Day |
|---|---|---|---|
| Free | 5 | 20 | 50 |
| Pro | 30 | 200 | 1,000 |
| Enterprise | 100 | 1,000 | 10,000 |
POST /render
/api/v1/renderRender a story JSON directly into a video (no AI)Submit a complete story JSON and render it into a narrated video. No AI agent is involved — your story is rendered as‑is. Requires the render scope.
Request Body
| Field | Type | Description |
|---|---|---|
storyrequired | object | Story JSON in MultiSegmentStory format |
options | object | Render options (see below) |
options.narration | boolean | Enable AI narration Default: true |
options.background_music | boolean | Enable background music Default: true |
options.music_style | string | Music style: Cinematic, Ambient, Classical, Jazz, Electronic, etc. Default: "Cinematic" |
options.resolution | string | Video resolution Default: "1080p" |
options.fps | integer | Frames per second (24-60) Default: 30 |
options.language | string | Narration language code (en, bn, hi, etc.) Default: "en" |
webhook_url | string | URL to POST when render completes or fails |
Response
| Field | Type | Description |
|---|---|---|
id | string | Video task ID for polling |
status | string | Always "accepted" on success |
poll_url | string | Relative URL to poll for status |
estimated_duration_seconds | integer | Estimated render time (~180s) |
curl -X POST https://geotasker.ai/api/v1/render \
-H "X-API-Key: gt_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"story": {
"segments": [
{
"type": "map",
"estimated_duration": 10,
"narration": "The Silk Road stretched across Central Asia...",
"renderer": "mapbox",
"story": {
"camera": {
"center": [65, 40],
"zoom": 3,
"keyframes": [
{"at": 0, "center": [30, 35], "zoom": 4},
{"at": 10, "center": [110, 35], "zoom": 4}
]
}
}
}
]
},
"options": {
"resolution": "1080p",
"music_style": "Cinematic"
}
}'POST /generate
/api/v1/generateAI generates a story from a text prompt, then rendersDescribe what you want in plain text. The AI agent creates the story JSON, gathers geospatial data, and renders the video. Requires the generate scope.
Request Body
| Field | Type | Description |
|---|---|---|
promptrequired | string | Text description of the video (10-5,000 chars) |
options | object | Render options (same as /render) |
webhook_url | string | URL to POST when render completes or fails |
Response
Same shape as POST /render. Estimated duration is ~300s since the AI agent needs time to generate the story.
curl -X POST https://geotasker.ai/api/v1/generate \
-H "X-API-Key: gt_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"prompt": "Create a 60-second video about why the US wants Greenland, showing the Arctic military bases and natural resources",
"options": {
"resolution": "1080p",
"language": "en"
}
}'GET /videos/{id}
/api/v1/videos/{id}Poll render status and get the resultPoll this endpoint until status is "completed" or "failed". We recommend polling every 5–10 seconds.
Status Lifecycle
accepted→rendering→completedorfailedResponse
| Field | Type | Description |
|---|---|---|
id | string | Video task ID |
status | string | accepted | rendering | completed | failed |
progress | integer | null | Render progress 0-100 (when rendering) |
message | string | null | Current step description |
video_url | string | null | Presigned S3 URL (valid 1 hour, only when completed) |
duration_seconds | number | null | Video duration (when completed) |
render_time_seconds | number | null | Time spent rendering (when completed) |
error | string | null | Error message (when failed) |
created_at | string | ISO 8601 timestamp |
# Poll until completed
curl https://geotasker.ai/api/v1/videos/YOUR_TASK_ID \
-H "X-API-Key: gt_live_your_key_here"
# Example response (rendering):
# {"id":"...","status":"rendering","progress":45,"message":"Rendering segment 3/8..."}
# Example response (completed):
# {"id":"...","status":"completed","video_url":"https://...","duration_seconds":62.5}GET /videos
/api/v1/videosList recent videosReturns your most recent videos (last 7 days), ordered newest first.
Query Parameters
| Param | Type | Description |
|---|---|---|
limit | integer | Max videos to return Default: 20 |
Response
Array of video objects:
| Field | Type | Description |
|---|---|---|
id | string | Video task ID |
status | string | accepted | rendering | completed | failed |
source | string | "render" or "generate" |
created_at | string | ISO 8601 timestamp |
video_url | string | null | Presigned URL (when completed) |
curl "https://geotasker.ai/api/v1/videos?limit=5" \
-H "X-API-Key: gt_live_your_key_here"Story JSON Schema
The story object passed to /render follows the MultiSegmentStory format. A story consists of an array of segments, each rendered sequentially into the final video.
Segment Types
| Type | Renderers | Description |
|---|---|---|
map | mapbox, folium, kepler, deckgl, custom | Animated map with camera movements, markers, routes |
text | html, pil | Title cards, fact screens, text overlays |
chart | matplotlib, chart.js, d3 | Bar, line, pie, donut, racing bar charts |
code | manim, custom python | Mathematical animations, custom visualizations |
Full Example
{
"segments": [
{
"type": "text",
"estimated_duration": 5,
"narration": "The ancient Silk Road connected East and West for centuries.",
"title": "The Silk Road",
"subtitle": "A Journey Through Time",
"style": "cinematic"
},
{
"type": "map",
"estimated_duration": 15,
"narration": "Starting from Chang'an in China, merchants traveled westward through Central Asia, carrying silk, spices, and precious stones.",
"renderer": "mapbox",
"story": {
"camera": {
"center": [65, 40],
"zoom": 3,
"pitch": 45,
"bearing": 0,
"keyframes": [
{"at": 0, "center": [108, 34], "zoom": 5, "pitch": 60},
{"at": 8, "center": [65, 39], "zoom": 4, "pitch": 45},
{"at": 15, "center": [28, 41], "zoom": 5, "pitch": 60}
]
},
"entities": [
{
"type": "marker",
"coordinates": [108.94, 34.26],
"label": "Chang'an",
"start_at": 0
},
{
"type": "marker",
"coordinates": [28.97, 41.01],
"label": "Constantinople",
"start_at": 12
}
]
}
},
{
"type": "chart",
"estimated_duration": 8,
"narration": "Trade volume grew significantly between the 2nd century BCE and the 14th century CE.",
"chart_type": "line",
"data": {
"labels": ["200 BCE", "0 CE", "200 CE", "600 CE", "1000 CE", "1400 CE"],
"datasets": [
{
"label": "Relative Trade Volume",
"data": [10, 30, 55, 40, 70, 85]
}
]
},
"title": "Silk Road Trade Over Time"
}
]
}Error Codes
All errors return a JSON body with an error object containing a code and message.
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded (5 requests per min). Upgrade tier for higher limits.",
"retry_after": 42
}
}| HTTP | Code | Description |
|---|---|---|
401 | MISSING_API_KEY | No API key provided in headers |
401 | INVALID_API_KEY | API key not recognized or wrong format |
403 | KEY_REVOKED | API key has been revoked |
403 | INSUFFICIENT_SCOPE | API key missing required scope (render or generate) |
404 | NOT_FOUND | Video not found or not owned by your key |
429 | RATE_LIMIT_EXCEEDED | Too many requests. Check Retry-After header |
500 | RENDER_FAILED | Render pipeline error |
500 | GENERATE_FAILED | AI generation pipeline error |
503 | SERVER_BUSY | All render slots in use. Retry after ~60 seconds |
MCP Server
GeoTasker exposes an MCP (Model Context Protocol) server so AI coding tools can generate geospatial videos directly from your IDE.
Any MCP-compatible client works — including Claude Code, Cursor, VS Code Copilot, and Windsurf.
MCP Quick Start
One command to connect. Your browser will open for Google sign-in, and you're ready to go.
Claude Code
claude mcp add --transport http geotasker https://geotasker.ai/mcp/mcpCursor / VS Code Copilot
Add to your .cursor/mcp.json or VS Code MCP settings:
{
"mcpServers": {
"geotasker": {
"url": "https://geotasker.ai/mcp/mcp"
}
}
}Generic MCP Client
Any client that supports Streamable HTTP transport can connect:
{
"mcpServers": {
"geotasker": {
"transport": "http",
"url": "https://geotasker.ai/mcp/mcp"
}
}
}MCP Authentication
MCP uses OAuth 2.1 with PKCE — no API keys needed. Authentication is handled automatically by your MCP client.
Connect
Add the MCP server URL to your client
Browser sign-in
Your browser opens automatically for Google sign-in
Done
Tokens refresh automatically. No keys to manage or rotate
MCP Tools
Four tools are available through the MCP server. Your AI assistant can call these directly.
generate_videoGenerate a video from a text promptDescribe what you want in plain text. AI creates the story, gathers map data, and renders the video.
| Parameter | Type | Description |
|---|---|---|
promptrequired | string | Text description of the video (min 10 chars) |
narration | boolean | Include AI narration Default: true |
background_music | boolean | Include background music Default: true |
music_style | string | Cinematic, Ambient, Classical, Jazz, Rock, Electronic, Pop, Folk, World, Orchestral Default: "Cinematic" |
resolution | string | Video resolution Default: "1080p" |
render_videoRender a video from a story JSONSubmit a complete GeoTasker story JSON. No AI involved — your story is rendered as-is.
| Parameter | Type | Description |
|---|---|---|
storyrequired | object | GeoTasker MultiSegmentStory JSON object |
narration | boolean | Include AI narration Default: true |
background_music | boolean | Include background music Default: true |
music_style | string | Music style Default: "Cinematic" |
resolution | string | Video resolution Default: "1080p" |
get_video_statusCheck video generation statusPoll until status is completed or failed.
| Parameter | Type | Description |
|---|---|---|
video_idrequired | string | The task/video ID returned by generate_video or render_video |
list_videosList your recent videosReturns videos created via the API in the last 7 days.
| Parameter | Type | Description |
|---|---|---|
limit | integer | Max number of videos to return (1-50) Default: 10 |