---
updatedAt: 2026-11-04T00:13:54.000Z
agentTools:
  projectIndex: https://developer.serverobotics.com/llms.txt
---

# Getting Started

Go from an API key to a robot en route in about five minutes.

Everything below runs against the sandbox, `https://api.sandbox.serverobotics.com`. Sandbox deliveries are served by simulated robots, so you can run the full lifecycle end to end without a real courier moving.

Every v2 endpoint lives under your partner, so the base URL for all calls is `https://api.sandbox.serverobotics.com/v2/partners/$PARTNER_ID`. Endpoint paths in this guide and the API Reference, such as `POST /quotes`, are relative to that base URL. In Try It, set `partner_id` once in the base URL and it applies to every endpoint.

## 1. Make an authenticated call

Every request carries your API key in the `X-API-Key` header. Start with something harmless. How many robots are on duty near a location:

```sh
curl "https://api.sandbox.serverobotics.com/v2/partners/$PARTNER_ID/robots/nearby_count?lat=34.0227&lng=-118.2798" \
  -H "X-API-Key: $API_KEY"
```

```json
{ "count": 3, "lat": 34.0227, "lng": -118.2798, "radius_m": 1000 }
```

A `401` means the key or partner id is wrong. See [Authentication](https://developer.serverobotics.com/reference/authentication) for where keys come from.

## 2. Spin up a simulated fleet

A sandbox partner with no robots gets `couriers_busy` on every quote. Give yourself a fleet first, **inside the sandbox service area** (the examples here use Los Angeles, near USC):

```sh
curl -X POST "https://api.sandbox.serverobotics.com/v2/partners/$PARTNER_ID/simulated_fleet/power_up" \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{ "fleets": [{
        "fleet_size": 3,
        "robot_naming_prefix": "cor_test-",
        "start_gps": { "lat": 34.0227, "lng": -118.2798 },
        "randomized_starting_offset_meters": 5,
        "gps_telemetry_frequency": 1000,
        "job_assignment_poll_frequency": 5000,
        "auto_job_event_frequency": 20000,
        "max_robot_speed_mph": 5,
        "auto_advance_jobs": true
      }] }'
```

`auto_advance_jobs: true` makes robots walk the delivery lifecycle on their own. Set it to `false` when you want to drive each stage yourself, as in step 5.

Fleets are capped at **10 robots across all of a partner's sandbox fleets combined**. Poll `GET /simulated_fleet/status` until every robot reports `is_ready: true`.

> 🚧 Ready is not the same as dispatchable
>
> Robots report ready within a second or two, but the dispatcher takes about **30 seconds** longer to start offering them. Quotes in that window return `503 couriers_busy`. Retry the quote every few seconds until it succeeds rather than treating the first `couriers_busy` as a failure.
>
> Outside the sandbox service area, quotes return `couriers_busy` no matter how long you wait, so a fleet that never becomes quotable usually means the pickup is out of area.

## 3. Quote a delivery

A quote prices a potential delivery and reserves nothing. It is valid for **5 minutes and can only be used once**.

```sh
curl -X POST "https://api.sandbox.serverobotics.com/v2/partners/$PARTNER_ID/quotes" \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{
    "pickup": {
      "address": {
        "street_address_1": "3201 S Figueroa St",
        "city": "Los Angeles",
        "state": "CA",
        "zip_code": "90007",
        "country": "US"
      },
      "location": {
        "lat": 34.0227,
        "lng": -118.2798
      }
    },
    "dropoff": {
      "address": {
        "street_address_1": "3375 S Hoover St",
        "city": "Los Angeles",
        "state": "CA",
        "zip_code": "90007",
        "country": "US"
      },
      "location": {
        "lat": 34.0226,
        "lng": -118.2835
      }
    }
  }'
```

You get back a `quote_id`, a `fee` in cents, and ETAs. If the delivery isn't possible you get a `422` explaining why: untraversable pickup, unreachable deadline, or distance over the limit.

If Serve recognises the merchant at the pickup, the response also lists `suggested_spots`, which are nearby Serve parking Spots. Add the optional `id` and `name` fields to the pickup to help Serve recognise the merchant.

## 4. Turn the quote into a job

```sh
curl -X POST "https://api.sandbox.serverobotics.com/v2/partners/$PARTNER_ID/jobs" \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{
    "quote_id": "dqt_qUdje83jhdk",
    "external_order_id": "SP 937-215",
    "delivery_items": [
      {
        "name": "Burrito",
        "quantity": 1
      }
    ],
    "pickup": {
      "address": {
        "street_address_1": "3201 S Figueroa St",
        "city": "Los Angeles",
        "state": "CA",
        "zip_code": "90007",
        "country": "US"
      },
      "location": {
        "lat": 34.0227,
        "lng": -118.2798
      }
    },
    "dropoff": {
      "address": {
        "street_address_1": "3375 S Hoover St",
        "city": "Los Angeles",
        "state": "CA",
        "zip_code": "90007",
        "country": "US"
      },
      "location": {
        "lat": 34.0226,
        "lng": -118.2835
      }
    }
  }'
```

Reusing a spent quote returns `409 used_quote`.

To send the robot to one of the quote's `suggested_spots`, add `"selected_spot_id": "<spot_id>"` to the matching waypoint. Serve ignores an unrecognised Spot and still creates the job. Without a selection, Serve may route the robot to the nearest known Spot.

> 📘 Skip the two-step
>
> If you always commit to whatever quote you receive, `POST /jobs/instant` quotes and creates in one call. Send an `Idempotency-Key` header and retries are safe, because the same key replays the original response rather than creating a second job.
>
> One wrinkle worth designing for: **rejections replay too.** Retrying a transient `couriers_busy` under the same key returns that same rejection. Send a new key when you genuinely want another attempt.

## 5. Watch it happen

Poll `GET /jobs/{job_id}` and read `status` as it moves through `pending_courier_assignment` → `pickup_en_route` → `pickup_arrived` → `dropoff_en_route` → `dropoff_arrived` → `dropoff_complete`.

To skip polling, receive the same updates as they happen. Connect to the partner WebSocket at `wss://api.sandbox.serverobotics.com/v2/ws/partners/$PARTNER_ID`, or set a `webhook_url` on your partner account. The WebSocket authenticates with `X-API-Key`, or an `api_key` query parameter where headers aren't available. Both channels deliver the same `EventEnvelope`, carrying `event.delivery_status` and `event.courier_status` events.

With `auto_advance_jobs: false`, you drive it instead:

```sh
curl -X POST "https://api.sandbox.serverobotics.com/v2/partners/$PARTNER_ID/simulated_fleet/jobs/$JOB_ID/advance" \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{ "target_stage": "dropoff_arrived" }'
```

That's the whole loop. To draw the planned route on a map, call `GET /jobs/{job_id}/route`. Each leg's `route` is a GeoJSON `FeatureCollection` of sidewalk segments, in order. Each feature is a `LineString` with routing properties such as `time_estimate` and `next_maneuvers`. Join the features' coordinates to get one path. The route is only available while the job is active. Once the job completes, the endpoint returns `404 route_not_found`.

## Testing the unhappy paths

Sandbox lets you force failures rather than waiting to stumble into them. Pass `simulate_rejection` on a quote or instant job:

`pickup_untraversable` · `dropoff_untraversable` · `delivery_distance_exceeds_limit` · `outside_operating_hours` · `pickup_deadline_unreachable` · `dropoff_deadline_unreachable` · `couriers_busy` · `internal_error`

Build against these early. `couriers_busy` in particular is a normal transient condition in production, not an exceptional one.

## Limits and conventions

The rate limit is 600 requests per minute, and a `429` carries a `retry-after` header in seconds. Dates are UTC in ISO 8601, `2020-05-15T15:50:38Z`. Coordinates are decimal degrees in WGS84. Fees are integer cents.

# Sibling pages

* [Authentication](https://developer.serverobotics.com/reference/authentication.md)
* [Real-time events](https://developer.serverobotics.com/reference/events.md)