Skip to content
On this site

Custom events

The things that happen in your product — a trial started, a plan upgraded. You declare the name once, fire it against a contact, and an automation triggering on that name enrols them.

Definitions and sends

A definition is a name your team owns, created with POST /events and addressed afterwards by ID or by that name. A send is one occurrence: POST /events/send records it against exactly one contact and enrols them into every enabled automation whose trigger names it.

The two are separately permissioned on purpose. Declaring, listing, changing and deleting a definition needs a full-access key. Sending accepts a key restricted to sending as well, because firing an event is how an integration starts a workflow and is no more powerful than POST /emails — so a key you gave your billing service can report that a trial started without also being able to invent event names or read the ones you have.

Names

Lower-case letters, digits, ., _ and -, starting with a letter, at most 100 characters, and unique among your live definitions. A name can never be shaped like a UUID, which is what lets {identifier} take either without ambiguity.

The rasket: prefix is reserved for the platform's own triggers — rasket:contact.created, rasket:topic.subscribed, the rasket:email.* family and rasket:segment.entered. You can trigger an automation on those; you cannot declare one. A name carrying the prefix is 422 validation_error.

Deleting a definition is soft and frees the name. An automation version still naming it simply never fires again.

Payloads

A send may carry a payload of key/value pairs, at most 16 KB of JSON. When the definition declares a schema, every declared key present in the payload has to be its type; a declared key that is absent or null passes, and undeclared keys pass untouched.

Event schema types
TypeAccepts
stringAny string.
numberA finite JSON number.
booleantrue or false.
dateAn ISO 8601 calendar date (2026-09-11) or a zoned instant (2026-09-11T12:00:00Z) naming a day that exists.

A value that disagrees is 422 validation_error, with one entry in errors[] per key so you can see all of them at once. A PATCH replaces the schema rather than merging into it.

What a send guarantees

  • 202, not 200: the event is durable the moment the call returns, and the runs it enrols start on the next tick.
  • There is no Idempotency-Key here. Two calls are two events and two runs — retry only a call that never answered.
  • One send is exactly one run per matching automation, however many times it is redelivered internally.
  • An unknown event name, or a contact this team does not have, is 404 not_found. Exactly one of contact_id and email must be given; neither or both is 422.

Endpoints

POST /events

Declare a name your integrations can fire and your workflows can trigger on.

Body

Body
FieldTypeDescription
name*stringLower-case letters, digits, ., _ and -, starting with a letter, at most 100 characters. Unique among your live events.
schemaobject | nullA flat map from payload key to type: string, number, boolean or date. At most 50 keys. A payload sent under this event is checked against it.
curl -X POST "https://api.rasket.com/events" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "trial.started",
  "schema": {
    "plan": "string",
    "seats": "number"
  }
}'

Response 201

{
  "object": "event",
  "id": "0199d2f1-4c4e-7a20-9c31-6f2b8a0e5f01"
}
  • Names under the reserved rasket: prefix are the platform's own triggers — rasket:contact.created and its siblings — and are 422 validation_error here.
  • A name already held by one of your live events is 422 validation_error.
  • Declaring a schema is optional. Without one, any payload is accepted.

GET /events

Every event you have declared, newest first.

Query parameters

Query parameters
FieldTypeDescription
limitintegerHow many items to return, 1–100. Defaults to 20.
afterstringReturn the page that follows this item ID. Mutually exclusive with before.
beforestringReturn the page that precedes this item ID. Mutually exclusive with after.
curl -X GET "https://api.rasket.com/events?limit=20" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0"

Response 200

{
  "object": "list",
  "has_more": false,
  "data": [
    {
      "id": "0199d2f1-4c4e-7a20-9c31-6f2b8a0e5f01",
      "name": "trial.started",
      "schema": {
        "plan": "string",
        "seats": "number"
      },
      "created_at": "2026-09-11T12:00:00.000Z",
      "updated_at": "2026-09-11T12:00:00.000Z"
    }
  ]
}
  • Requires a full-access key. A key restricted to sending may fire events, not list them.

POST /events/send

Fire one event for one contact. This is what starts a workflow.

Body

Body
FieldTypeDescription
event*stringThe name of a live event of yours.
contact_idstringThe contact this happened to. Exactly one of contact_id or email.
emailstringThe contact's address, instead of an ID. Exactly one of the two.
payloadobjectKey/value pairs to carry with the event, at most 16 KB of JSON. Checked against the event's schema when it declares one.
curl -X POST "https://api.rasket.com/events/send" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0" \
  -H "Content-Type: application/json" \
  -d '{
  "event": "trial.started",
  "contact_id": "0199d2f1-4c4e-7a20-9c31-6f2b8a0e5f02",
  "payload": {
    "plan": "pro",
    "seats": 12
  }
}'

Response 202

{
  "object": "event",
  "event": "trial.started"
}
  • **202, not 200.** The event is durable the moment this returns; the runs it enrols start on the next tick.
  • This route takes no Idempotency-Key. Two calls are two events and two runs — retry it only when the first call never answered.
  • A key restricted to sending may call this, which is the point: firing an event is no more powerful than sending an email.
  • An unknown event name, or a contact this team does not have, is 404 not_found.

GET /events/{identifier}

By ID or by name.

Path parameters

Path parameters
FieldTypeDescription
identifier*stringThe event's ID, or its name. A name can never be shaped like an ID.
curl -X GET "https://api.rasket.com/events/{identifier}" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0"

Response 200

{
  "object": "event",
  "id": "0199d2f1-4c4e-7a20-9c31-6f2b8a0e5f01",
  "name": "trial.started",
  "schema": {
    "plan": "string",
    "seats": "number"
  },
  "created_at": "2026-09-11T12:00:00.000Z",
  "updated_at": "2026-09-11T12:00:00.000Z"
}
  • schema is null, not absent, when the event declares none.
  • An event that belongs to another team, or that has been deleted, is 404 not_found.

PATCH /events/{identifier}

Replace the payload schema, or clear it.

Path parameters

Path parameters
FieldTypeDescription
identifier*stringThe event's ID, or its name. A name can never be shaped like an ID.

Body

Body
FieldTypeDescription
schema*object | nullA flat map from payload key to type: string, number, boolean or date. At most 50 keys. A payload sent under this event is checked against it.
curl -X PATCH "https://api.rasket.com/events/{identifier}" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0" \
  -H "Content-Type: application/json" \
  -d '{
  "schema": {
    "plan": "string",
    "seats": "number",
    "trial_ends_at": "date"
  }
}'

Response 200

{
  "object": "event",
  "id": "0199d2f1-4c4e-7a20-9c31-6f2b8a0e5f01"
}
  • schema is required, because it is the only field a PATCH can change. Send null to clear it.
  • The schema is replaced, not merged. A key you leave out is no longer declared.
  • An event's name is immutable, so a published workflow never loses the trigger it names.

DELETE /events/{identifier}

Soft-deletes and frees the name.

Path parameters

Path parameters
FieldTypeDescription
identifier*stringThe event's ID, or its name. A name can never be shaped like an ID.
curl -X DELETE "https://api.rasket.com/events/{identifier}" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0"

Response 200

{
  "object": "event",
  "id": "0199d2f1-4c4e-7a20-9c31-6f2b8a0e5f01",
  "deleted": true
}
  • A published workflow version still naming it simply never fires again. Runs already in flight are untouched.
  • The name is free to declare again afterwards.