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

# Event tokens

> Send an event from your site, like a form submit or a purchase, into Squid ID to trigger a workflow. Outreach that fires on what people actually do, then stops when they convert.

Event tokens let your site tell Squid ID what a person did. Squid ID already knows who is on your site. When something happens (they fill out a form, book a demo, buy), a playbook can act on it in real time: start a sequence, or stop one the moment they convert. It is outreach triggered by what people actually do, not a static list you upload. Tokens are managed under **Settings → Event tokens**.

This works for any website, not just SaaS apps. If your site can fire a webhook or run a bit of backend code, it can send an event.

The model is one primitive: **post an event you name, and that name becomes a trigger.** Send `form_submitted`, `demo_booked`, or `purchase` from your site, then pick it as the trigger when you build a playbook.

## If you're coming from RB2B

RB2B, like our own [integrations](/integrations/overview), sends identified visitors out to your tools. Event tokens add the other direction: your site can send an event back in, and Squid ID acts on it. That inbound step is what lets outreach stop on its own when a person converts, and it's an extra capability rather than a like-for-like feature.

<div className="compare">
  <table>
    <thead>
      <tr><th /><th>RB2B</th><th>Squid ID</th></tr>
    </thead>

    <tbody>
      <tr><td>Send identified visitors out</td><td>Yes</td><td>Yes</td></tr>
      <tr><td>Take events back in from your site</td><td>Not provided</td><td>Post events to a per-site endpoint</td></tr>
      <tr><td>Start a playbook from an event</td><td>Not provided</td><td>A form submit or booked demo can begin a sequence</td></tr>
      <tr><td>Stop a playbook from an event</td><td>Not provided</td><td>A conversion pulls the person out of every campaign</td></tr>
      <tr><td>Tokens</td><td>Not applicable</td><td>Multiple named tokens per site, rotate and revoke like API keys</td></tr>
    </tbody>
  </table>
</div>

<p className="why"><strong>Why this matters.</strong> Squid ID knows who is on your site. Your site is the only thing that knows what they did next. Feeding those events back is what closes the loop: a form submit stops the cold campaign automatically instead of you remembering to, and a booked demo kicks off the right follow-up the moment it happens.</p>

## What you'd use it for

The event is whatever is meaningful on your site. Common ones:

* **`form_submitted`** / **`demo_booked`**: someone converts. Stop the campaigns they're in so you're not still cold-emailing a warm lead, and start the right follow-up.
* **`purchase`** / **`order_placed`**: they bought. Suppress outreach and hand off to your CRM playbooks.
* **`quote_requested`** / **`call_booked`**: a high-intent action. Kick off a priority sequence.
* **`signed_up`** / **`trial_started`**: if you do run an app, the classic SaaS conversions work too.
* Any custom milestone your site tracks: start a re-engagement touch.

You choose the name; the name is the trigger.

## The endpoint

Send events with an HTTP POST to `https://id-api.asksquid.ai/api/events`. The token goes in the `Authorization` header, the event in a small JSON body.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://id-api.asksquid.ai/api/events \
    -H "Authorization: Bearer <your-event-token>" \
    -H "Content-Type: application/json" \
    -d '{"event":"form_submitted","email":"jane@acme.com","properties":{"form":"contact"}}'
  ```

  ```javascript Node.js theme={null}
  await fetch("https://id-api.asksquid.ai/api/events", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.SQUID_EVENT_TOKEN}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      event: "form_submitted",
      email: "jane@acme.com",
      properties: { form: "contact" },
    }),
  });
  ```

  ```python Python theme={null}
  import os, requests

  requests.post(
      "https://id-api.asksquid.ai/api/events",
      headers={"Authorization": f"Bearer {os.environ['SQUID_EVENT_TOKEN']}"},
      json={
          "event": "form_submitted",
          "email": "jane@acme.com",
          "properties": {"form": "contact"},
      },
  )
  ```

  ```php PHP theme={null}
  $ch = curl_init("https://id-api.asksquid.ai/api/events");
  curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
      "Authorization: Bearer " . getenv("SQUID_EVENT_TOKEN"),
      "Content-Type: application/json",
    ],
    CURLOPT_POSTFIELDS => json_encode([
      "event" => "form_submitted",
      "email" => "jane@acme.com",
      "properties" => ["form" => "contact"],
    ]),
  ]);
  curl_exec($ch);
  ```

  ```ruby Ruby theme={null}
  require "net/http"
  require "json"

  uri = URI("https://id-api.asksquid.ai/api/events")
  Net::HTTP.post(uri, {
    event: "form_submitted",
    email: "jane@acme.com",
    properties: { form: "contact" }
  }.to_json, {
    "Authorization" => "Bearer #{ENV['SQUID_EVENT_TOKEN']}",
    "Content-Type" => "application/json"
  })
  ```
</CodeGroup>

A valid event returns `202`. A bad token returns `401`, and a payload that fails validation returns `422` with the reason.

<Info>Run it live with your own token in the <a href="/api-reference/events/send-event">Send an event</a> API playground.</Info>

## The event payload

| Field        | Required | What it is                                                                                             |
| ------------ | -------- | ------------------------------------------------------------------------------------------------------ |
| `event`      | Yes      | The name your site sends, like `form_submitted`. Letters, numbers, and `_ . : -`, up to 64 characters. |
| `email`      | Yes      | The person the event is about. This is the identity key.                                               |
| `properties` | No       | Extra context, one level deep. Values are strings, numbers, or booleans.                               |

### Why email is required

`email` is how Squid ID knows **which person** the event is about. It is the join between an event from your site and a person Squid ID identified on your site. When you send `form_submitted` for `jane@acme.com`, Squid ID acts on that exact person: it stops any playbook she is in that ends on that event, and starts any playbook triggered by it.

<Info>Use the same email your site knows the person by, and the one they match on in Squid ID. If the email on the event differs from the email Squid ID resolved for that visitor, the two will not link. An event with no email has no one to act on, so it is rejected.</Info>

`properties` is only context, like the plan or the amount. It never changes who the event is about. Only `email` does that.

## One event, two jobs

A single event does both sides of the loop at once, and each side is a no-op unless a playbook opts in:

* It **stops** any playbook whose exit is that event name. Send `converted` and anyone in a campaign that ends on `converted` is pulled out and suppressed in the tool.
* It **starts** any playbook triggered by that event name.

That is why one `form_submitted` can both stop your cold campaign and start a warmer follow-up.

## Create a token

Only an Owner or Admin can manage event tokens. Tokens are scoped to one website. Issuing a token requires the Workflows add-on (which starts with a free trial).

<Steps>
  <Step title="Open Event tokens">
    Go to **Settings → Event tokens** and click **New token**.
  </Step>

  <Step title="Name it">
    Give it a short label, up to 20 characters, so you can tell tokens apart later, for example "Production" or "Staging".
  </Step>

  <Step title="Copy it once">
    Click **Create token**. The full token is shown one time only.
  </Step>
</Steps>

<Warning>Copy the token immediately. For security it is never shown again. If you lose it, revoke it and create a new one.</Warning>

You can create as many tokens as you need. They work exactly like [API tokens](/account/api-tokens): use separate tokens for production and staging, rotate without downtime by creating a new one before you retire the old, and revoke one without breaking the others.

## Use an event as a trigger

Once an event has been sent, it becomes available as a trigger when you build a playbook.

<Steps>
  <Step title="Send the event at least once">
    Post it to the endpoint above. Squid ID records the event name the first time it sees it.
  </Step>

  <Step title="Add a playbook">
    In **Settings → Workflows**, pick a scenario, then choose **When I send a custom event** as the trigger.
  </Step>

  <Step title="Choose the event">
    Pick the event from the list of ones you've sent.
  </Step>
</Steps>

<Info>You can only trigger on an event you have already sent. The picker lists the events Squid ID has seen, and choosing one you have never sent is rejected. This stops playbooks that would silently never fire because of a typo in the event name.</Info>

## Validation, limits, and retention

Every event is checked at the edge before it reaches anything, so a malformed or oversized payload is rejected rather than stored.

* `event` must match the safe pattern above, up to 64 characters.
* `email` must be a valid address.
* `properties` is optional and shallow: up to 30 keys, string, number, or boolean values only, no nesting, under 8 KB total.
* Requests are rate limited per token and per IP.
* Events are a trigger buffer, not a log. They are validated on the way in and **purged after 24 hours**. What persists is the effect (a playbook started or stopped) and the catalog of event names you've sent.

Inbound events are included with the Workflows add-on up to a generous monthly allowance. There is no per-event charge.

## Revoke a token

On **Settings → Event tokens**, click **Revoke** on any token and confirm. Any app sending events with that token immediately starts getting `401`, and playbooks that trigger on those events stop receiving them. This cannot be undone, so if you are rotating, create the new token first.

## Related

* [Workflows](/workflows/overview)
* [API tokens](/account/api-tokens)
* [ICP filtering](/finding-visitors/icp-filtering)
* [Identified visitors](/finding-visitors/identified-visitors)
