Quick Start
Send addresses, get optimized routes back. Get up and running in under 5 minutes.
Agent skill — fastest start
Working with Claude Code, Codex, Cursor or another coding agent? Install the r4m.ai skill and ask for a route in plain words. The agent learns how to geocode addresses, submit them, wait for the result and present it — and uses the MCP tools below when they are connected.
npx skills add r4m-ai/skillsThen put your API key in the agent's environment as R4M_API_KEY and ask, for example:
Plan the fastest round trip from 350 5th Ave, New York via 11 Wall St, Grand Central Terminal and 200 Eastern Pkwy, Brooklyn.
MCP for AI Agents
r4m.ai exposes a Model Context Protocol (MCP) endpoint so AI agents can call route optimization tools directly. Uses Streamable HTTP transport — serverless-compatible, no websocket required.
Available Tools
| Tool | Description |
|---|---|
create_optimization | Submit addresses for route optimization |
get_optimization | Get optimization status and result |
list_optimizations | List all optimizations with pagination |
check_usage | Check the current prepaid balance and activity |
create_key | Generate a new API key |
list_keys | List all API keys |
forward_geocode | Convert a single address to lat/lng coordinates (status ok / ambiguous / not_found, with precision) |
bulk_geocode | Geocode many addresses in one request (up to your plan limit); one result per distinct address, matched by original |
request_topup | Machine-payment top-up when the balance runs out (Preview) |
Configuration
No key needed: add the URL to your client. The first time it connects, it opens your browser — sign in to r4m.ai with Google and allow it. A new account starts with a $1.00 balance. Where no browser is around (a server, CI), send an acc_ API key as a Bearer header instead. Rate limits and pricing are the same either way.
In a terminal:
claude mcp add --transport http r4m https://r4m.ai/api/mcpAdd --scope user to make it available in every project, or --scope project to share it via a checked-in .mcp.json.
Or from inside Claude Code — ask it, and it runs the command for you:
Add the r4m.ai MCP server: claude mcp add --transport http r4m https://r4m.ai/api/mcpThen run /mcp, pick r4m and choose Authenticate: your browser opens to sign in. If r4m is not in the list yet, restart Claude Code.
No browser (a server, CI)? Add --header "Authorization: Bearer acc_…" to the command instead.
HTTP API
Base URL
https://r4m.ai/api/v11Get your API key
Sign up at r4m.ai and create an API key in the Developer Console. You can also create keys via the API.
2Submit addresses for optimization
curl -X POST https://r4m.ai/api/v1/optimizations \
-H "Authorization: Bearer acc_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"addresses": [
{
"address": "Depot — 25 Kent Ave, Brooklyn, NY",
"lat": 40.7218,
"lng": -73.9615,
"isDepot": true,
"serviceTimeSeconds": 900
},
{
"address": "1155 Manhattan Ave, Brooklyn, NY",
"lat": 40.7304,
"lng": -73.954,
"serviceTimeSeconds": 600,
"timeWindowStart": "09:00",
"timeWindowEnd": "10:30",
"priority": 1
},
{
"address": "238 Bedford Ave, Brooklyn, NY",
"lat": 40.7135,
"lng": -73.967,
"serviceTimeSeconds": 900
},
{
"address": "1 Front St, Brooklyn, NY",
"lat": 40.7033,
"lng": -73.9881,
"serviceTimeSeconds": 600,
"priority": 2
},
{
"address": "445 Albee Square W, Brooklyn, NY",
"lat": 40.6926,
"lng": -73.9873,
"serviceTimeSeconds": 1200
}
],
"parameters": {
"travelMode": "driving",
"optimizeMode": "Time",
"roundTrip": true,
"routeStartAt": "2026-04-14T08:00",
"timezone": "America/New_York"
},
"webhookUrl": "https://your-server.com/webhooks/r4m"
}'
# 202 Accepted — this call returns immediately; the solver keeps working (2-60s)
# { "success": true, "data": { "id": "550e8400-…", "status": "pending" } }
#
# That id is how you collect the finished plan. Either:
# webhook — we POST it to your webhookUrl the moment it is ready, or
# polling — GET /api/v1/optimizations/{id} until status is "completed"3Receive the result
Step 2 returned status: "pending" — the solver runs in the background for roughly 2–60 seconds. When it completes, we'll POST the result to your webhookUrl, signed with HMAC-SHA256 (verify via the X-Webhook-Signature header). Delivery is retried with backoff (how many times depends on your plan).
No public endpoint to receive it? Leave webhookUrl out and poll instead — GET /api/v1/optimizations/{id} with the id from step 2, until status is completed or failed. Either way the payload below is what you get.
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"priceMicros": 10000,
"webhookUrl": "https://your-server.com/webhooks/r4m",
"webhookStatus": "delivered",
"result": {
"routes": [
{
"routeStartAt": "2026-04-14T08:00:00-04:00",
"totalDistanceMeters": 19473,
"totalTimeSeconds": 8285,
"polyline": "ulpwFpplbMl@qA@CLOYYIIIK…",
"waypoints": [
{
"index": 0,
"arrivalAt": "2026-04-14T08:00:00-04:00",
"departureAt": "2026-04-14T08:15:00-04:00",
"waitTimeSeconds": 0,
"cumulativeDistanceMeters": 0,
"cumulativeTimeSeconds": 0,
"polylineToNext": "ulpwFpplbMl@qA@CLOYYIIIK…"
},
{
"index": 1,
"arrivalAt": "2026-04-14T09:00:00-04:00",
"departureAt": "2026-04-14T09:10:00-04:00",
"waitTimeSeconds": 2543,
"cumulativeDistanceMeters": 1416,
"cumulativeTimeSeconds": 3600,
"polylineToNext": "}brwFhckbMI{A?IGkAIqBMkC…"
}
]
}
],
"unroutedStops": []
},
"createdAt": "2026-04-14T11:58:12Z",
"updatedAt": "2026-04-14T11:58:41Z"
}
}Shortened here — a real payload carries one waypoint per stop. waitTimeSeconds is time spent waiting for a delivery window to open, and unroutedStops lists any stop that could not be fitted into the plan at all — always check it.
Client SDKs
Auto-generated from our OpenAPI spec. Type-safe, always up to date.
Install
npm install @r4mai/sdkUsage
import { createClient } from "@r4mai/sdk";
const r4m = createClient({ apiKey: "acc_your_api_key_here" });
// Submits, waits out the solve, and hands back the finished plan
const { data: optimization, error } = await r4m.createOptimizationAndWaitForRoutes({
body: {
addresses: [
{ address: "Depot", lat: 40.7128, lng: -74.006, isDepot: true },
{ address: "Stop 1", lat: 40.758, lng: -73.9855 },
{ address: "Stop 2", lat: 40.7484, lng: -73.9857 },
],
},
});
if (error) throw error;
console.log(optimization.result);Explore the full API
Try requests directly in your browser with the interactive API reference.