Send an event and any Jobs that subscribe to that event will get triggered.

Name and Schemas

Name

Event triggers have a name. They will only get triggered when an event with that name are sent.

Schema

Event triggers take a Zod schema. This is used to validate the data that is sent with the event. If the data does not match the schema, the Job will not run.

It also means that inside your run function the payload will be typed correctly. We use Zod for our schemas – it’s a fantastic library that allows you to define schemas in a very simple way.

You can always start out by using z.any() as your schema, and then later on you can add more strict validation. See our Zod guide for more information.

Example

client.defineJob({
  id: "new-user-slack",
  name: "New user slack message",
  version: "0.1.0",
  trigger: eventTrigger({
    name: "user.created",
    schema: z.object({
      name: z.string(),
      email: z.string(),
      paidPlan: z.boolean(),
    }),
    filter: {
      //only run the Job if the user is paying
      paidPlan: [true],
    },
  }),
  integrations: {
    slack,
  },
  //this function is run when the custom event is received
  run: async (payload, io, ctx) => {
    //send a message to the #new-users Slack channel with user details
    const response = await io.slack.postMessage("send-to-slack", {
      channel: "CUKJXJZ3Z",
      text: `New user: ${payload.name} (${payload.email}) signed up. ${
        payload.paidPlan ? "They are paying" : "They are on the free plan"
      }.`,
    });

    return response.message;
  },
});

You can subscribe to the same event from multiple different Jobs. This is useful if you want to send an event to multiple different services or if you want to keep each Job small and simple.

Sending events

There are two ways of sending an event that will Trigger a Job.

1. From your own code

You can use client.sendEvent() to send an event from your own code. View the SDK reference.

//somewhere in your code, can even be on another server
await client.sendEvent({
  name: "user.created",
  payload: { name: "John Doe", email: "[email protected]", paidPlan: true },
});

2. From another Job

You can use io.sendEvent() to send events from inside a Job run, to trigger another. View the SDK reference.

client.defineJob({
  id: "event-1",
  name: "Run when the foo.bar event happens",
  version: "0.0.1",
  trigger: eventTrigger({
    name: "foo.bar",
    schema: z.object({
      url: z.string(),
    }),
  }),
  run: async (payload, io, ctx) => {
    //send an event using `io`
    await io.sendEvent("send event", {
      name: "user.created",
      payload: { name: "Rick Astley", email: "[email protected]" },
    });
  },
});

Event filters

They are declarative pattern-matching rules, modeled after AWS EventBridge patterns.

Here’s a more detailed explanation of Event filters

Given the following custom event payload:

{
  "uid": "jexAgaeJFJsrGfans1pxqm",
  "type": "15 Min Meeting",
  "price": 0,
  "title": "15 Min Meeting between Eric Allam and John Doe",
  "length": 15,
  "status": "ACCEPTED",
  "endTime": "2023-01-25T16:00:00Z",
  "bookingId": 198052,
  "organizer": {
    "id": 32794,
    "name": "Eric Allam",
    "email": "[email protected]",
    "language": { "locale": "en" },
    "timeZone": "Europe/London"
  }
}

The following event filter would match the event:

{
  "type": ["15 Min Meeting"],
  "status": ["ACCEPTED", "REJECTED"],
  "organizer": {
    "name": ["Eric Allam"]
  }
}

For an event pattern to match an event, the event must contain all the field names listed in the event pattern. The field names must also appear in the event with the same nesting structure.

The value of each field name in the event pattern must be an array of strings, numbers, or booleans. The event pattern matches the event if the value of the field name in the event is equal to any of the values in the array.

Effectively, each array is an OR condition, and the entire event pattern is an AND condition.

So the above event filter will match because status == "ACCEPTED", and it would also match if status == "REJECTED".