Appearance
The event object
An event is a named thing that happens to a contact — user.created, order.completed — optionally with a schema describing the payload it carries. Events are what automation triggers listen for.
Fields
The object returned by GET /v1/events/{id}, and by create, update and list.
| Field | Type | Description |
|---|---|---|
object | string | Always "event". |
id | string | Event identifier — an opaque, prefixed string, evt_…. Stable for the life of the event, and the value you pass as a cursor when paginating. |
name | string | The dotted identifier, e.g. user.created. Unique within your team, and usable in place of the id on every event endpoint. Never starts with the reserved sendgrail. namespace. |
schema | object | null | A flat map of field name → type describing the payload — see below. null when the event has no schema and accepts any payload. |
created_at | string | ISO 8601 timestamp of when the event was defined. |
updated_at | string | ISO 8601 timestamp of the last schema change; equal to created_at until the first one. |
A delete returns a stub rather than the object — { object, id, deleted: true }. See Delete an event.
schema is one level deep
schema maps each expected field to a type. There are four types, and the value is always a type name — never a nested object.
| Type | Payload value | Notes |
|---|---|---|
string | a JSON string | |
number | a JSON number | |
boolean | true / false | |
date | a JSON string | ISO 8601, e.g. 2026-07-17T09:30:00Z. |
json
"schema": {
"plan": "string",
"seats": "number",
"trial": "boolean",
"signed_up_at": "date"
}When an event is sent, its payload is validated against this map: a field of the wrong type is a 422. Fields the schema doesn't list are allowed through — the schema is a floor, not a whitelist. An event with "schema": null accepts any payload.
The name is the identity
name is unique within your team, which is what makes it usable as a path parameter: GET /v1/events/user.created works without you looking the id up first, the same way a contact endpoint accepts an email address. The name is fixed once created — to change the shape, update the schema; to change the name, create a new event.
Ids are opaque
evt_… is a prefixed string and nothing more — this API is Resend-inspired but not identical, and its ids are its own. Don't parse the part after the prefix or assume it sorts; treat the whole thing as a token. Automations carry auto_…, runs carry run_…, on the same principle.
Auto-created events
An event doesn't have to be defined before it is sent. Send an event with an unknown name and SendGrail creates the event with "schema": null — after which it is a first-class object here, listed and retrievable like any other.