> ## Documentation Index
> Fetch the complete documentation index at: https://docs.relayapp.im/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Build a Relay agent in 5 minutes with curl.

This transcript creates an agent token, waits for a message, and replies. You need only `curl`.

<Note>
  These examples use `https://api.relayapp.im`. To use a local Relay server, set `RELAY_API_URL=http://localhost:8788` instead.
</Note>

<Steps>
  <Step title="Create an agent">
    In the Relay app, choose **Create your own**, enter the contact details, and create it. Copy the Agent Token before closing the confirmation: Relay shows it once.

    ```bash theme={null}
    export RELAY_API_URL="https://api.relayapp.im"
    export RELAY_AGENT_TOKEN="relay_agt_live_..."
    ```
  </Step>

  <Step title="Verify the token">
    ```bash theme={null}
    curl -sS "$RELAY_API_URL/v1/agents/me" \
      -H "Authorization: Bearer $RELAY_AGENT_TOKEN"
    ```

    ```json theme={null}
    {
      "agent": {
        "id": "agt_01JZRELAY",
        "handle": "scheduler",
        "display_name": "Scheduler",
        "tagline": "Finds a time that works",
        "avatar_url": null,
        "distribution": "store",
        "created_at": "2026-07-12T01:20:00.000Z"
      }
    }
    ```
  </Step>

  <Step title="Poll for a message">
    Send the new contact a message in Relay, then long-poll for up to 25 seconds:

    ```bash theme={null}
    curl -sS "$RELAY_API_URL/v1/events?timeout=25" \
      -H "Authorization: Bearer $RELAY_AGENT_TOKEN"
    ```

    ```json theme={null}
    {
      "events": [
        {
          "event_id": "evt_01JZE9M2XW",
          "event_type": "message.received",
          "agent_id": "agt_01JZRELAY",
          "created_at": "2026-07-12T01:21:03.000Z",
          "data": {
            "message": {
              "id": "msg_01JZM3T8AH",
              "conversation_id": "cnv_01JZC7K4RQ",
              "sequence": 1,
              "sender": { "kind": "user", "id": "usr_01JZU1F0BD" },
              "parts": [
                { "part_index": 0, "type": "text", "text": "What time works tomorrow?" }
              ],
              "reply_to": null,
              "fallback_text": "What time works tomorrow?",
              "status": "sent",
              "created_at": "2026-07-12T01:21:03.000Z"
            }
          }
        }
      ],
      "next_cursor": "djE6MQ=="
    }
    ```

    Save `next_cursor`. Pass it back as `cursor` on the next request; doing so acknowledges everything before that cursor. Treat the cursor as opaque. Because delivery is at least once, also store processed `event_id` values and ignore duplicates.
  </Step>

  <Step title="Reply">
    Use the received message's `conversation_id`. The idempotency key must be 8–255 characters; deriving it from the event ID makes a retry safe.

    ```bash theme={null}
    curl -sS -X POST "$RELAY_API_URL/v1/messages" \
      -H "Authorization: Bearer $RELAY_AGENT_TOKEN" \
      -H "Content-Type: application/json" \
      -H "Idempotency-Key: reply-evt_01JZE9M2XW" \
      -d '{
        "conversation_id": "cnv_01JZC7K4RQ",
        "parts": [
          { "type": "text", "text": "Tomorrow at 2:00 PM works for me." }
        ],
        "reply_to": { "message_id": "msg_01JZM3T8AH", "part_index": 0 }
      }'
    ```

    Relay responds with `202 Accepted`:

    ```json theme={null}
    {
      "message_id": "msg_01JZM4Q9VN",
      "message": {
        "id": "msg_01JZM4Q9VN",
        "conversation_id": "cnv_01JZC7K4RQ",
        "sequence": 2,
        "sender": { "kind": "contact", "id": "agt_01JZRELAY" },
        "parts": [
          { "part_index": 0, "type": "text", "text": "Tomorrow at 2:00 PM works for me." }
        ],
        "reply_to": { "message_id": "msg_01JZM3T8AH", "part_index": 0 },
        "fallback_text": "Tomorrow at 2:00 PM works for me.",
        "status": "sent",
        "created_at": "2026-07-12T01:21:08.000Z"
      }
    }
    ```
  </Step>

  <Step title="Continue from the cursor">
    ```bash theme={null}
    curl -sS "$RELAY_API_URL/v1/events?cursor=djE6MQ%3D%3D&timeout=25" \
      -H "Authorization: Bearer $RELAY_AGENT_TOKEN"
    ```

    If no new message arrives before the timeout, Relay returns an empty page and the same logical cursor:

    ```json theme={null}
    { "events": [], "next_cursor": "djE6MQ==" }
    ```
  </Step>
</Steps>

Next, read [Concepts](/concepts) or switch event delivery to [Webhooks](/webhooks).
