Skip to main content
Routal

Build with AI

Wire Routal into your AI coding assistant — Cursor, Claude Code, ChatGPT, Gemini, Copilot — so it generates correct Routal code on the first try.

In 2026 most developers write API code with an AI assistant open in the next tab. Routal ships three machine-readable assets that drop into any assistant and prime it for correct code generation. This page is the setup guide.

The three assets

AssetWhat it is
/llms.txtConcise index for LLM crawlers — title + summary + URL for every doc page and every endpoint.
/llms-full.txtFull Markdown dump of every doc page + every endpoint, one file (~150 KB) — sized for an LLM context window.
/openapi.jsonOpenAPI 3.0 spec — for codegen tools (openapi-typescript, openapi-python-client, oapi-codegen, etc.).

Most readers want /llms-full.txt. It is the authoritative dump and stays in sync with the docs automatically.


Two ways to give your assistant the context

Zero setup — use the "Open in AI" button

Every recipe page has an Open in AI assistant button. Click → pick ChatGPT, Claude, Copilot, or Gemini → the assistant opens with the recipe context, the llms.txt URL, and a parameterised prompt already loaded. No config files, no rules, no setup.

Use this path when you are exploring scenarios or writing Routal code occasionally.

Project rules — wire it into your IDE once

For an active integration project, drop the Routal context into your assistant's rules file. The model picks it up automatically on every session.

Cursor

Create .cursor/rules/routal.mdc in your repo root:

---
description: Routal API context
alwaysApply: true
---

When writing code that calls api.routal.com, treat
https://developers.routal.com/llms-full.txt as the authoritative reference for
endpoints, payload shapes, error codes, and gotchas. Do not invent endpoints —
if it is not in that file or in https://developers.routal.com/openapi.json, it
does not exist.

Hard rules:
- Auth is `?private_key=...` query parameter — NOT `Authorization: Bearer`.
- Branch error handling on `message_id`, not `message` text.
- Use bulk endpoints (POST /v2/stops, POST /v3/vehicles) instead of looping single creates.
- React to webhooks instead of polling.

Claude Code

Add to CLAUDE.md in your project root:

## Routal API integration

Authoritative API reference: https://developers.routal.com/llms-full.txt

When writing code that calls api.routal.com:
- Auth is `?private_key=...` query parameter, never an `Authorization` header.
- Branch on `error.message_id`, not `error.message`.
- Prefer bulk endpoints (POST /v2/stops, POST /v3/vehicles) over loops.
- Subscribe to webhooks rather than polling.

Do not invent endpoints. If it is not in `/llms-full.txt` or `/openapi.json`,
it does not exist.

Windsurf, GitHub Copilot, or other assistants

Most assistants accept a URL as a knowledge source via their rules / instructions file. Point them at https://developers.routal.com/llms-full.txt. If your tool doesn't accept URLs, copy the file contents in directly.


Verify the assistant has the context

After wiring, ask your assistant a control question. A correctly primed assistant produces something like the snippet below; an unprimed one will try Authorization: Bearer, hallucinate an endpoint, or forget project_id.

Prompt:

Write a curl call that creates a Routal plan for tomorrow.

Expected answer:

curl -X POST 'https://api.routal.com/v2/plan?private_key=YOUR_KEY&project_id=YOUR_PROJECT_ID' \
  -H 'Content-Type: application/json' \
  -d '{ "label": "Tomorrow", "execution_date": "2026-05-22" }'

Three signals the assistant has the context:

  • private_key lives in the query string, not in Authorization.
  • project_id is required as a query parameter.
  • Base URL is api.routal.com, not developers.routal.com.

If the answer looks wrong, paste /llms-full.txt into the conversation as a fallback and ask the assistant to re-read it.


The 10 facts every assistant needs

If you are writing a system prompt manually, these are the load-bearing rules. They are already inside /llms-full.txt — this is just the human-readable summary so you can sanity-check the assistant's output.

  1. Auth is private_key as a query parameter. Never Authorization: Bearer.
  2. external_id is your idempotency lever. No Idempotency-Key header today. Pattern: POST /v2/stops/search on external_id → if found, reuse; else create.
  3. Branch on message_id. Errors are { message, message_id: "highway.<context>.error.<reason>" }. The text may change; the ID is stable.
  4. Use bulk endpoints. POST /v2/stops and POST /v3/vehicles accept arrays. Looping single creates burns the 2,000 req/min budget.
  5. Subscribe to webhooks, don't poll. Webhooks fire on state change. Polling wastes the rate budget and lags real events.
  6. POST /v2/plan/{id}/optimize is not retry-safe. A second call may move stops if the first completed. If one is running you get highway.optimization.error.sync_optimization_already_progress — wait, don't retry.
  7. Dispatch sends an email; it does NOT change route status. Route flips to in_transit when the driver opens the magic link, not when you call POST /v2/route/{id}/dispatch.
  8. Webhooks have no signature today. Auth them with a URL token (/webhooks/routal?token=...). Dedup on (event_id, data.id, data.updated_at). Webhooks auto-disable after 50 consecutive failures.
  9. Pagination is offset-based{ total, limit, offset, pages, page, docs }. Always pin a sort to avoid duplicates under concurrent writes.
  10. Deletes cascade and don't check status. DELETE /v2/plan/{id} succeeds even when in-progress. The one hard guard is is_locked: true on a route.

The Routal mental model

Project (long-lived workspace; vehicles, custom fields, integrations live here)
  └── Plan (one execution window — typically a day or a shift)
        ├── Stops (deliveries / pickups / services)
        ├── Vehicles (assigned to the plan, pulled from the project's fleet)
        └── Routes (ordered list of stops per vehicle, created by the optimizer)

Status enums you will see in responses and webhooks:

  • Plan: draft · planning · in_progress · finished
  • Route: not_started · in_transit · finished
  • Stop: pending · incomplete · completed · canceled

Routal computes transitions automatically. Clients never call an endpoint to advance status. The route flips to in_transit when the driver opens the magic link; the plan flips to finished when every route is finished.


What's NOT on this page

  • The full API context block. Lives at /llms-full.txt — auto-generated from every doc page so it never drifts. Point your assistant at the URL rather than maintaining a separate copy.
  • Code samples in TypeScript / Python / cURL. Every endpoint page in the API Reference has them, and every recipe walks the full integration in three languages.
  • A "how Routal works" overview. Browse planner.routal.com for the product side, or read Resource lifecycle for the API-side state machine.