---
title: Quickstart
description: Send your first event to Retidal in under five minutes.
---

Get a project API key, send an event, and confirm it was accepted.

## Prerequisites

- A Retidal project. Create one in the console at `https://retidal.com`.
- A project API key. Ingestion has no scope gate — any valid project key works, legacy or scoped — see [Authentication](/docs/authentication).

<Steps>
<Step title="Get your API key">

In the console, open your project's **API Keys** settings and copy an existing key, or issue a new one. The raw key is shown once at creation time — store it somewhere you can retrieve it, such as an environment variable.

```bash
export RETIDAL_API_KEY="tk_live_xxxxxxxxxxxxxxxxxxxxxxxx"
```

</Step>
<Step title="Send an event">

`POST` to `https://api.retidal.com/api/v1/t` with your key in the `X-API-Key` header. Add `?sync=1` so the response proves the event reached storage — drop it once you move to production traffic.

```bash
curl -X POST "https://api.retidal.com/api/v1/t?sync=1" \
  -H "X-API-Key: $RETIDAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "eventName": "page_view",
    "visitorId": "vid_abc123"
  }'
```

</Step>
<Step title="Confirm it was accepted">

With `?sync=1`, `POST /api/v1/t` returns `200` with `processed: true` on success — proof the event reached D1 and Analytics Engine, not just that it was queued:

```json
{
  "accepted": 1,
  "failed": 0,
  "queued": 0,
  "processed": true
}
```

Drop `?sync=1` for production traffic: `POST /api/v1/t`'s default response is `202` with `processed: false` — the event was validated and dispatched to background processing, but persistence is not yet proven. Reserve `?sync=1` for integration checks and health checks.

</Step>
<Step title="Send a purchase event with attribution">

Real events carry more than a name. `properties.amount` is in minor units (cents), and `clickIds` captures ad-platform attribution:

```bash
curl -X POST https://api.retidal.com/api/v1/t \
  -H "X-API-Key: $RETIDAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "eventName": "user_paid",
    "visitorId": "vid_abc123",
    "userId": "uid_456",
    "sessionId": "sess_789",
    "properties": { "amount": 9900, "currency": "CNY" },
    "clickIds": { "gclid": "xyz" }
  }'
```

</Step>
</Steps>

## What this unlocks

Sending your first event unlocks attaching richer identity and properties ([Send data](/docs/sending-data/events)), reading the full response contract so you can tell a queued event from a persisted one ([Errors & status codes](/docs/errors)), and wiring ad-platform and cross-device attribution via short links ([Attribution](/docs/attribution/short-links)).

## Verify it worked

Re-run the sync request from step 2 (or step 4) and confirm the response is literally `"processed": true`:

```bash
curl -s "https://api.retidal.com/api/v1/t?sync=1" \
  -H "X-API-Key: $RETIDAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"eventName": "page_view", "visitorId": "vid_abc123"}' | jq .processed
# expect: true
```

## If it doesn't work

If the request is rejected, times out, or `processed` never becomes `true`, work through [Events not arriving](/docs/troubleshooting/events-not-arriving).

## Next steps

<CardGroup cols={2}>
  <Card title="Send data" href="/docs/sending-data/events">
    Full event fields, identity association, and Click ID capture.
  </Card>
  <Card title="Authentication" href="/docs/authentication">
    Capability scopes and how to issue and rotate keys.
  </Card>
  <Card title="Errors & status codes" href="/docs/errors">
    The full ingestion response contract, including validation modes.
  </Card>
  <Card title="Attribution" href="/docs/attribution/short-links">
    Short links, cross-device stitching, and ad-platform callbacks.
  </Card>
</CardGroup>
