diff --git a/docs/.gitignore b/docs/.gitignore
new file mode 100644
index 000000000..e43b0f988
--- /dev/null
+++ b/docs/.gitignore
@@ -0,0 +1 @@
+.DS_Store
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 000000000..bb304843c
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,14 @@
+# Development
+
+## Install and initial setup
+
+`npm install`
+
+## Running the app
+
+`npm run dev`
+
+## View the app locally
+
+It runs locally here:
+`http://localhost:3050`
diff --git a/docs/_snippets/delay-example.mdx b/docs/_snippets/delay-example.mdx
new file mode 100644
index 000000000..d9fdfcc2d
--- /dev/null
+++ b/docs/_snippets/delay-example.mdx
@@ -0,0 +1,18 @@
+```typescript Wait example
+new Job(client, {
+ id: "delay-job",
+ name: "Delay Job",
+ version: "0.0.1",
+ trigger: eventTrigger({
+ name: "example.event",
+ }),
+ run: async (payload, io, ctx) => {
+ await io.logger.info("Hi");
+
+ // the second parameter is the number of seconds to wait
+ await io.wait("wait 30 days", 30 * 24 * 60 * 60);
+
+ await io.logger.info("Sorry for the slow reply!");
+ },
+});
+```
diff --git a/docs/_snippets/how-to-pass-integrations.mdx b/docs/_snippets/how-to-pass-integrations.mdx
new file mode 100644
index 000000000..255c16e0e
--- /dev/null
+++ b/docs/_snippets/how-to-pass-integrations.mdx
@@ -0,0 +1,15 @@
+```typescript
+new Job(client, {
+ //... other options
+ integrations: {
+ slack,
+ gh: github,
+ },
+ run: async (payload, io, ctx) => {
+ //slack is available on io.slack
+ io.slack.postMessage(...);
+ //github is available on io.gh
+ io.gh.addIssueLabels(...);
+ }
+});
+```
diff --git a/docs/_snippets/integration-getting-started.mdx b/docs/_snippets/integration-getting-started.mdx
new file mode 100644
index 000000000..3623adff8
--- /dev/null
+++ b/docs/_snippets/integration-getting-started.mdx
@@ -0,0 +1,3 @@
+## Getting started
+
+If you have not yet set up Trigger.dev in your Next.js project, go to the [quick start guide](/documentation/quickstart).
diff --git a/docs/_snippets/integration-list.mdx b/docs/_snippets/integration-list.mdx
new file mode 100644
index 000000000..c47241bf6
--- /dev/null
+++ b/docs/_snippets/integration-list.mdx
@@ -0,0 +1,6 @@
+
+
+The "Integrations" page shows
+
+1. Some of the APIs that you can use with Trigger.dev (you can use any API). Selecting one of these will give you instructions on how to use it.
+2. Your connected integrations. Clicking these will give you more details on that connection.
diff --git a/docs/_snippets/scheduled-dev-warning.mdx b/docs/_snippets/scheduled-dev-warning.mdx
new file mode 100644
index 000000000..ae210e231
--- /dev/null
+++ b/docs/_snippets/scheduled-dev-warning.mdx
@@ -0,0 +1,6 @@
+
+ Scheduled Triggers **do not** trigger Jobs in the DEV
+ [Environment](/documentation/concepts/environments-endpoints). When you're
+ working locally you should use [the Test
+ feature](/documentation/guides/testing-jobs) to trigger any scheduled Jobs.
+
diff --git a/docs/_snippets/send-event-options.mdx b/docs/_snippets/send-event-options.mdx
new file mode 100644
index 000000000..b12678d48
--- /dev/null
+++ b/docs/_snippets/send-event-options.mdx
@@ -0,0 +1,4 @@
+There are two way to send an event that will trigger `eventTrigger()`:
+
+1. Use [client.sendEvent()](/sdk/triggerclient/instancemethods/sendevent) from anywhere in your codebase.
+2. Use [io.sendEvent()](/sdk/io/sendevent) from inside a Job's `run()` function.
diff --git a/docs/_snippets/send-event-params.mdx b/docs/_snippets/send-event-params.mdx
new file mode 100644
index 000000000..1313f72a3
--- /dev/null
+++ b/docs/_snippets/send-event-params.mdx
@@ -0,0 +1,52 @@
+
+
+
+ The `name` property must exactly match any subscriptions you want to
+ trigger.
+
+
+ The `payload` property will be sent to any matching Jobs and will appear
+ as the `payload` param of the `run()` function. You can leave this
+ parameter out if you just want to trigger a Job without any input data.
+
+
+ The optional `context` property will be sent to any matching Jobs and will
+ be passed through as the `context.event.context` param of the `run()`
+ function. This is optional but can be useful if you want to pass through
+ some additional context to the Job.
+
+
+ The `id` property uniquely identify this particular event. If unset it
+ will be set automatically using `ulid`.
+
+
+ This is optional, it defaults to the current timestamp. Usually you would
+ only set this if you have a timestamp that you wish to pass through, e.g.
+ you receive a timestamp from a service and you want the same timestamp to
+ be used in your Job.
+
+
+ This is optional, it defaults to "trigger.dev". It can be useful to set
+ this as you can filter events using this in the `eventTrigger()`.
+
+
+
+
+
+
+
+ An optional Date when you want the event to Trigger Jobs. The event will
+ be sent to the platform immediately but won't be acted upon until the
+ specified time.
+
+
+ An optional number of seconds you want to wait for the event to Trigger
+ any relevant Jobs. The event will be sent to the platform immediately but
+ won't be acted upon until the specified time.
+
+
+ This optional param will be used by the Trigger.dev Connect feature, which
+ is coming soon.
+
+
+
diff --git a/docs/_snippets/send-event-return.mdx b/docs/_snippets/send-event-return.mdx
new file mode 100644
index 000000000..5f3679134
--- /dev/null
+++ b/docs/_snippets/send-event-return.mdx
@@ -0,0 +1,29 @@
+
+
+
+ The `id` of the event that was sent.
+
+
+ The `name` of the event that was sent.
+
+
+ The `payload` of the event that was sent
+
+
+ The `timestamp` of the event that was sent
+
+
+ The `context` of the event that was sent. Is `undefined` if no context was
+ set when sending the event.
+
+
+ The timestamp when the event will be delivered to any matching Jobs. Is
+ `undefined` if `deliverAt` or `deliverAfter` wasn't set when sending the
+ event.
+
+
+ The timestamp when the event was delivered. Is `undefined` if `deliverAt`
+ or `deliverAfter` were set when sending the event.
+
+
+
diff --git a/docs/_snippets/stable-key-param.mdx b/docs/_snippets/stable-key-param.mdx
new file mode 100644
index 000000000..1053571c7
--- /dev/null
+++ b/docs/_snippets/stable-key-param.mdx
@@ -0,0 +1,4 @@
+
+ Should be a stable and unique key inside the `run()`. See
+ [resumability](/documentation/concepts/resumability) for more information.
+
diff --git a/docs/documentation/changelog.mdx b/docs/documentation/changelog.mdx
new file mode 100644
index 000000000..21f8b0d3b
--- /dev/null
+++ b/docs/documentation/changelog.mdx
@@ -0,0 +1,15 @@
+---
+title: "Changelog"
+description: "We release features and fixes weekly! See some of the changes we have made."
+---
+
+## June 28 2023 Release
+
+The first release of Trigger.dev v2, a major overhaul.
+
+- Works well on serverless and long-running servers
+- Adaptors for Next.js
+- Simpler architecture utilizing Postgres
+- Integrations are now just Node.js packages
+- New UI
+- Easy self-hosting
diff --git a/docs/documentation/concepts/client-adaptors.mdx b/docs/documentation/concepts/client-adaptors.mdx
new file mode 100644
index 000000000..ae7bc536a
--- /dev/null
+++ b/docs/documentation/concepts/client-adaptors.mdx
@@ -0,0 +1,31 @@
+---
+title: "Client & Adaptors"
+description: "The Client is how you interact with the API, through an Adaptor."
+---
+
+## Client
+
+A Client is used to connect to a specific [Project](/documentation/concepts/projects) by using an [API Key](/documentation/concepts/environments-apikeys).
+
+Clients are created using the `TriggerClient` class.
+
+```ts
+export const client = new TriggerClient({
+ id: "my-webapp",
+ apiKey: process.env.TRIGGER_API_KEY!,
+});
+```
+
+View the [Client API Reference](//sdk/triggerclient) for more information.
+
+## Adaptors
+
+Adaptors allows Clients to receive data from the Trigger API. They do this by creating an API endpoint that data can be received at and transforming data into the expected format.
+
+Each platform has one or more adaptors, see the guides below:
+
+| Platform | Adaptor |
+| ------------------------------------------------- | -------------------- |
+| [Next.js](/documentation/guides/platforms/nextjs) | `createPagesRoute()` |
+| [Next.js](/documentation/guides/platforms/nextjs) | `createAppRoute()` |
+| Express | Coming soon |
diff --git a/docs/documentation/concepts/connect.mdx b/docs/documentation/concepts/connect.mdx
new file mode 100644
index 000000000..ddc3d4fea
--- /dev/null
+++ b/docs/documentation/concepts/connect.mdx
@@ -0,0 +1,23 @@
+---
+title: Trigger.dev Connect
+description: "Authenticate your users with an Integration using Trigger.dev Connect."
+---
+
+Trigger.dev Connect will be released soon, during the beta period
+
+## What is it?
+
+It allows you to easily add Integrations for your users, such as:
+
+- Add contacts to their Hubspot.
+- Sync data to their Airtable.
+- Post videos to their YouTube.
+- Add issues to their Linear.
+
+## How does it work?
+
+1. Create an [Integration in the Dashboard](/documentation/guides/integrations).
+2. Use our provided React components in your web app to authenticate your users.
+3. Trigger a Job as one of your users.
+4. Inside the Run function the relevant Integrations will be authenticated with your user's credentials.
+5. Profit.
diff --git a/docs/documentation/concepts/delays.mdx b/docs/documentation/concepts/delays.mdx
new file mode 100644
index 000000000..c3c18b50e
--- /dev/null
+++ b/docs/documentation/concepts/delays.mdx
@@ -0,0 +1,12 @@
+---
+title: Delays
+description: "Delays can be used to wait for a certain amount of time before continuing a Run."
+---
+
+[Runs](/documentation/concepts/runs) can be paused using delays. They can be very long.
+
+Delays works even if you're on a serverless platform with timeouts, or if your server goes down. They utilize [resumability](/documentation/concepts/resumability) to ensure that the Run can be resumed after the delay.
+
+## Usage
+
+
diff --git a/docs/documentation/concepts/environments-endpoints.mdx b/docs/documentation/concepts/environments-endpoints.mdx
new file mode 100644
index 000000000..689cf7cdd
--- /dev/null
+++ b/docs/documentation/concepts/environments-endpoints.mdx
@@ -0,0 +1,40 @@
+---
+title: "Environments & Endpoints"
+description: "Environments and Endpoints are used to connect your server to the Trigger.dev platform."
+---
+
+
+When you login to your Project there's a section called "Environments & API Keys".
+
+## Environments
+
+Each environment has an API Key associated with it. This API Key is used to authenticate your Jobs with the Trigger.dev platform.
+
+The API Key you use for your [Client](/documentation/concepts/client-adaptors) is how we know which environment to run your code against:
+
+```ts
+export const client = new TriggerClient({
+ id: "nextjs-example",
+ //this environment variable should be set to your DEV API Key locally,
+ //and your PROD API Key in production
+ apiKey: process.env.TRIGGER_API_KEY!,
+});
+```
+
+### Development
+
+The `DEV` environment should only be used for local development. It's where you can test your Jobs before deploying them to servers.
+
+
+
+### Production
+
+The `PROD` environment is where your Jobs will run in production. It's where you can run your Jobs against real data.
+
+## Endpoints
+
+An Endpoint is a URL on your server that Trigger.dev can connect to. This URL is used to register Jobs, start them and orchestrate runs and retries.
+
+`DEV` has multiple endpoints associated with it – one for each team member. This allows each team member to run their own Jobs, without interfering with each other.
+
+All other environments have just a single endpoint (with a single URL) associated with them.
diff --git a/docs/documentation/concepts/integrations.mdx b/docs/documentation/concepts/integrations.mdx
new file mode 100644
index 000000000..13d1c7371
--- /dev/null
+++ b/docs/documentation/concepts/integrations.mdx
@@ -0,0 +1,112 @@
+---
+title: Integrations
+description: "Integrations make it easy to use APIs in your Jobs"
+---
+
+
+ You can use any API in your Jobs by using existing Node.js SDKs or HTTP
+ requests. Integrations just make it much easier especially when you want to
+ use OAuth. And you get great logging.
+
+
+An Integration is a package you install that makes it easy to work with a specific API. They:
+
+- Create a connection to the API (using OAuth, API keys or tokens)
+- Provide a set of [Tasks](/documentation/concepts/tasks) to work with the API
+- Provide a set of [Triggers](/documentation/concepts/triggers) to listen for events from the API
+- Allow you to use the **full underlying authenticated SDK client** directly
+
+## An example
+
+This job sends Slack messages when a new GitHub issue is opened on the `triggerdotdev/trigger.dev` repo.
+
+```ts
+import { Github } from "@trigger.dev/github";
+import { Slack } from "@trigger.dev/slack";
+
+//1. create GitHub client using a token
+const github = new Github({
+ id: "github",
+ token: process.env.GITHUB_TOKEN!,
+});
+
+//2. create Slack client using OAuth
+const slack = new Slack({
+ id: "slack",
+});
+
+new Job(client, {
+ id: "alert-on-new-github-issues",
+ name: "Alert on new GitHub issues",
+ version: "0.1.1",
+ integrations: {
+ //3. include the slack integration
+ slack,
+ },
+ //4. use the github integration to listen for new issues
+ trigger: github.triggers.repo({
+ event: events.onIssueOpened,
+ owner: "triggerdotdev",
+ repo: "trigger.dev",
+ }),
+ run: async (payload, io, ctx) => {
+ //5. send a message to slack
+ const response = await io.slack.postMessage("Slack alert", {
+ text: `New Issue opened: ${payload.issue.html_url}`,
+ channel: "C04GWBTDQ7W",
+ });
+
+ return response;
+ },
+});
+```
+
+There are some things worth highlighting here:
+
+1. Integration clients can use API keys or tokens.
+2. Integration clients can use OAuth.
+3. Integrations are added to a Job by adding them to the `integrations`.
+4. The Job Trigger can use an Integration to listen for events from the API.
+5. You can use the Integration to make API calls inside the `run` function.
+
+## Authentication
+
+### API Keys and Tokens
+
+You the value in when creating your Integration client. They are never sent from your server by the Trigger.dev service, they are local to your servers. We recommend you use a secure method of storing these values and passing them to your code, like environment variables.
+
+### OAuth
+
+You can use the [Integrations Dashboard](/documentation/guides/using-integrations) to setup OAuth for an Integration. We make it easy to use OAuth by dealing with the OAuth flow, token refreshing and storage for you.
+
+You can use OAuth to authenticate your internal team with an Integration or to allow your users to authenticate with an Integration – we call user authentication [Trigger.dev Connect](/documentation/guides/connect).
+
+## References
+
+
+
+ The Integrations Dashboard allows you to manage your Integrations and setup
+ OAuth.
+
+
+ Authenticate your users with an Integration using Trigger.dev Connect.
+
+
+ Trigger.dev integrates with a wide range of services.
+
+
+ Create an Integration for your own use or as a public package.
+
+
diff --git a/docs/documentation/concepts/jobs.mdx b/docs/documentation/concepts/jobs.mdx
new file mode 100644
index 000000000..c78072e1b
--- /dev/null
+++ b/docs/documentation/concepts/jobs.mdx
@@ -0,0 +1,61 @@
+---
+title: "Jobs"
+description: "When this happens, do this."
+---
+
+> A Job defines what event triggers it and what should happen when it is run.
+
+For example, you can create a Job that will send an email to a user when they sign up for your app.
+
+## Anatomy of a Job
+
+A Job is made up of a few things:
+
+1. Metadata
+2. A Trigger (what event should cause this job to run)
+3. The Run function (what should happen when this job runs)
+
+```ts
+//Job definition – uses the client
+new Job(client, {
+ // 1. Metadata
+ id: "event-1",
+ name: "Run when the foo.bar event happens",
+ version: "0.0.1",
+ // 2. Trigger
+ trigger: eventTrigger({
+ name: "foo.bar",
+ }),
+ // 3. Run function
+ run: async (payload, io, ctx) => {
+ // do something
+ },
+});
+```
+
+## Jobs, Triggers, Runs and Tasks
+
+A more complicated Job
+
+> When a GitHub issue is modified: If the issue has been labelled "critical" send a Slack message and sync the issue to Linear.
+
+This can be visualized like this:
+
+
+
+Events [trigger](/documentation/concepts/triggers) Jobs. Jobs generate a [Run](/documentation/concepts/runs) for every event. A Run is a single execution of a Job. A Run can have multiple [Tasks](/documentation/concepts/tasks) which are the individual steps of a Run.
+
+## References
+
+
+
+ Detailed SDK reference for Jobs.
+
+
+ Viewing and managing your Jobs in the Dashboard.
+
+
diff --git a/docs/documentation/concepts/limitations.mdx b/docs/documentation/concepts/limitations.mdx
new file mode 100644
index 000000000..4f1330d87
--- /dev/null
+++ b/docs/documentation/concepts/limitations.mdx
@@ -0,0 +1,31 @@
+---
+title: "Limitations"
+---
+
+There are a few limitations that are important to understand.
+
+In the current beta:
+
+- Runs on localhost are limited to 5 minutes.
+- On long-running servers (not serverless) Runs can be retried erroneously.
+- Compute intensive jobs are not well supported.
+
+## Runs on localhost are limited to 5 minutes
+
+When developing locally the [CLI dev command](/documentation/guides/cli#dev-command) uses [ngrok](https://ngrok.com/) so messages can be sent to your machine.
+
+Ngrok has a timeout of 5 minutes on a Request/Response cycle. so, if a localhost Run takes longer than 5 minutes to complete, the Run will fail.
+
+This limitation will be removed in the future by adding an alternative run strategy that works well on localhost and long-running servers. This won't use the request/response cycle.
+
+## On long-running servers (not serverless) Runs can be retried erroneously
+
+Currently the only way that Runs are performed is by a Request/Response cycle when `run` is called on a Job. This is optimized for serverless functions (where you have to use a Request/Response cycle), but not for long-running servers.
+
+This limitation will be removed in the future by adding an alternative mode so Jobs works well on localhost and long-running servers. This won't use the request/response cycle.
+
+## Compute intensive jobs are not well supported
+
+Currently the only way that Runs are performed is inside a Request/Response cycle when `run` is called on a Job. This is not a good way to perform compute intensive jobs.
+
+In the future we will add good support for compute intensive jobs.
diff --git a/docs/documentation/concepts/projects.mdx b/docs/documentation/concepts/projects.mdx
new file mode 100644
index 000000000..83f81ac6b
--- /dev/null
+++ b/docs/documentation/concepts/projects.mdx
@@ -0,0 +1,10 @@
+---
+title: "Projects"
+description: "Projects are a group of [Jobs](/documentation/concepts/jobs-runs-tasks) with [Environments](/documentation/concepts/environments-apikeys)"
+---
+
+User's are members of one or more Organizations. Each Organization can have many Projects.
+
+Jobs are scoped to a specific Project. This means they can only be run in the context of a Project. Jobs are associated with a Project by using a Project API key.
+
+Currently all members of an Organization have access to all Projects. More granular access control will be added in the future.
diff --git a/docs/documentation/concepts/resumability.mdx b/docs/documentation/concepts/resumability.mdx
new file mode 100644
index 000000000..e6e9b5c84
--- /dev/null
+++ b/docs/documentation/concepts/resumability.mdx
@@ -0,0 +1,58 @@
+---
+title: Resumability
+description: "Runs are resumable by returning Task stored data"
+---
+
+[Runs](/documentation/concepts/runs) can exceed the maximum timeout on serverless platforms and can survive server restarts.
+
+## How does this work?
+
+1. When a Run is created, it is given a unique ID. This ID is used to identify the Run.
+2. [Tasks](/documentation/concepts/tasks) have a `key` which is a string and is the first parameter. This should be stable and unique inside that `run` function.
+3. When a Task is completed, its output is stored.
+4. If a Run exceeds the timeout, or your server restarts, the Run will be "replayed".
+5. The second+ time it is run, Tasks that have already successfully completed will immediately return their first output. The code inside them won't re-run.
+
+## How to use keys
+
+Like we mentioned above, we use Task keys to determine which Tasks have already been executed. They are defined by you inside your `run` function, for example when you call `io.slack.postMessage`:
+
+```ts
+await io.slack.postMessage("⭐️ New Star", {
+ channel: "C04GWUTDC3W",
+ text: `@${starredBy} just starred ${repoName}!`,
+});
+```
+
+In this example, the key is the string `"⭐️ New Star"`. This means that if the Job is interrupted and then resumed, the `slack.postMessage` Task will be skipped because it has already been executed.
+
+If you make multiple calls to `slack.postMessage`, you should use different keys for each call. For example:
+
+```ts
+await io.slack.postMessage("⭐️ New Star", {
+ channel: "C04GWUTDC3W",
+ text: `@${starredBy} just starred ${repoName}!`,
+});
+
+await io.slack.postMessage("🚨 Critical Issue", {
+ channel: "C04GWUTDC3W",
+ text: `@${assignee} just opened a critical issue in ${repoName}!`,
+});
+```
+
+If you are calling a Task multiple times with the same key, it will only be executed once. For example, if you call `slack.postMessage` with the key `"⭐️ New Star"` twice, it will only be executed once.
+
+## How to use keys with loops
+
+If you are using a loop, you should use the loop index as the key. For example:
+
+```ts
+for (let i = 0; i < 10; i++) {
+ await ctx.waitFor(`Wait ${i}`, { seconds: 30 });
+
+ await slack.postMessage(`⭐️ New Star ${i}`, {
+ channelName: "github-stars",
+ text: `@${starredBy} just starred ${repoName}!`,
+ });
+}
+```
diff --git a/docs/documentation/concepts/runs.mdx b/docs/documentation/concepts/runs.mdx
new file mode 100644
index 000000000..5e40df6dd
--- /dev/null
+++ b/docs/documentation/concepts/runs.mdx
@@ -0,0 +1,80 @@
+---
+title: "Runs"
+description: "When a [Job](/documentation/concepts/jobs) is [Triggered](/documentation/concepts/triggers), the Run function is called."
+---
+
+> Everytime a Job is triggered, a Run is created with a payload of data.
+
+## Anatomy of a Run
+
+A Run is a record of the execution of a Job. It is created from `run()` function of a Job.
+
+```ts
+new Job(client, {
+ 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(),
+ }),
+ }),
+ // 1. Run function with params
+ run: async (payload, io, ctx) => {
+ // 2. Regular code and Tasks
+ },
+});
+```
+
+1. The `run()` function is called with some useful parameters. More on that in a second.
+2. Inside the run function you can write regular code and use [Tasks](/documentation/concepts/tasks).
+
+## Resumability
+
+Runs can exceed the maximum timeout on serverless platforms. If a Run exceeds this limit, it will be re-run. When it is re-run, any completed Tasks return their original output and they aren't re-run. Read more about [Resumability](/documentation/concepts/resumability).
+
+## Run function parameters
+
+### payload
+
+The payload is the data that triggered the Job. It is the same data that was sent to the [Trigger](/documentation/concepts/triggers) that triggered the Job.
+
+- For [Webhooks](/documentation/concepts/triggers/webhooks) the payload is the data from the webhook.
+- For [Events](/documentation/concepts/triggers/events) the payload is the data from the event, in the example above that's `{ url: "https://..." }`.
+- For [Scheduled](/documentation/concepts/triggers/scheduled) the payload is an object with the timestamp and the last timestamp (previous run).
+
+### io
+
+The `io` object gives you access to [Integrations](/documentation/concepts/integrations) and other useful functions. [View the full reference](/sdk/io) for `io`.
+
+A few things you can do with `io`:
+
+- Use [Integrations](/documentation/concepts/integrations).
+- Add [delays](/documentation/concepts/delays) (that can be longer than your server timeout).
+- Log messages to the [Run log](/documentation/guides/viewing-runs).
+- Perform [background fetch requests](/documentation/sdk/io) (that can be longer than your server timeout).
+- [Send events](/documentation/concepts/triggers/events) to Trigger other Jobs.
+- Create a [Task](/documentation/concepts/tasks) manually by wrapping code in `io.runTask`.
+
+### context
+
+The `context` object gives you access to information about the current Run, Job, Environment, Organization and Event. [View the full reference](/sdk/context) for `context`.
+
+## References
+
+
+
+ View all Runs for a Job, all the way down to individual Tasks.
+
+
+ The `io` object gives you access to Integrations and other useful functions.
+
+
+ The `context` object gives you access to the current Run's context.
+
+
diff --git a/docs/documentation/concepts/tasks.mdx b/docs/documentation/concepts/tasks.mdx
new file mode 100644
index 000000000..b69e94d13
--- /dev/null
+++ b/docs/documentation/concepts/tasks.mdx
@@ -0,0 +1,103 @@
+---
+title: "Tasks"
+description: "Tasks are individual building blocks of a Run."
+---
+
+> A Task is a resumable unit of a Run that can be retried, resumed and is logged.
+
+## Tasks vs regular code
+
+In the `run()` function you can use regular code and you can use Tasks.
+
+```ts
+new Job(client, {
+ id: "new-user",
+ name: "Run when a new user signs up",
+ version: "0.0.1",
+ trigger: eventTrigger({
+ name: "new.user",
+ schema: z.object({
+ userId: z.string(),
+ }),
+ }),
+ integrations: {
+ resend,
+ },
+ run: async (payload, io, ctx) => {
+ // regular code, not a Task
+ // the inputs/outputs of this function are not sent to the Trigger.dev platform
+ const user = await prisma.user.findUnique({
+ where: { id: payload.userId },
+ select: { email: true, name: true },
+ });
+ if (!user) throw new Error(`User not found: ${payload.userId}`);
+
+ // Integration functions are Tasks
+ await io.resend.sendEmail("Welcome email", {
+ to: user.email,
+ from: "jane@acme.inc",
+ subject: "Welcome!",
+ html: welcomeEmail(user.name),
+ });
+
+ // built-in io functions are Tasks
+ await io.wait("wait", 60 * 60 * 3); // wait for 3 hours
+
+ // You can wrap your own code in a Task, for retrying, resumability and logging
+ const response = await io.runTask(
+ "my-task",
+ { name: "My Task" },
+ async () => {
+ return await longRunningCode(payload.userId);
+ }
+ );
+
+ return response;
+ },
+});
+```
+
+## The benefits of Tasks
+
+Tasks are a powerful concept that gives you a lot of benefits:
+
+- **Resumability** – Runs can exceed the maximum timeout on serverless platforms. If a Run exceeds this limit, it will be re-run. When it is re-run, any completed Tasks return their original output and they aren't re-run. Read more about [Resumability](/documentation/concepts/resumability).
+- **Retryable** – If a Task fails, it will be retried. You can configure how (or if) a Task is retried. Full details in the [io SDK reference](/sdk/io).
+- **Logging** – Tasks are logged, so you can see what happened in a Run. Find out more about [viewing runs](/documentation/guides/viewing-runs).
+
+## Subtasks
+
+A Task can have multiple subtasks, and so on. This is useful for breaking down a large Task into smaller Tasks. We currently support nesting 5 levels deep.
+
+## Task Keys
+
+The first param of all Tasks is a `key`. This is a unique identifier for the Task inside that Run. It is used for resumability and logging. It is also used to identify the Task in the [Viewing Runs Dashboard](/documentation/guides/viewing-runs).
+
+## References
+
+
+
+ Runs can be very long-running. Learn how we handle this.
+
+
+ Integrations utilize Tasks.
+
+
+ The `io` object allows you to easily run a Task yourself.
+
+
+ View all Runs for a Job, all the way down to individual Tasks.
+
+
diff --git a/docs/documentation/concepts/triggers/dynamic.mdx b/docs/documentation/concepts/triggers/dynamic.mdx
new file mode 100644
index 000000000..79ca560af
--- /dev/null
+++ b/docs/documentation/concepts/triggers/dynamic.mdx
@@ -0,0 +1,130 @@
+---
+title: "DynamicTrigger & DynamicSchedule"
+sidebarTitle: "Dynamic"
+description: "These are advanced features that allows you to attach dynamic triggers to a Job."
+---
+
+Sometimes you don't know when you write the code what the trigger or schedule will be.
+
+[DynamicTrigger](/sdk/dynamictrigger) and [DynamicSchedule](/sdk/dynamicschedule) allow you to configure triggers and schedules at runtime.
+
+## DynamicSchedule
+
+```typescript
+//1. create a DynamicSchedule
+const dynamicSchedule = new DynamicSchedule(client, {
+ id: "dynamicinterval",
+});
+
+//2. create a Job that is attached to the dynamic schedule
+new Job(client, {
+ id: "user-dynamicinterval",
+ name: "User Dynamic Interval",
+ version: "0.1.1",
+ //3. set the DynamicSchedule as the Trigger
+ trigger: dynamicSchedule,
+ run: async (payload, io, ctx) => {
+ await io.logger.info("The userId is ", ctx.source.id);
+ },
+});
+
+//4. Register the DynamicSchedule anywhere in your app
+async function registerUserCronJob(userId: string, userSchedule: string) {
+ //use the userId as the id for the DynamicSchedule
+ //so it comes through to run() in the context source.id
+ await dynamicSchedule.register(userId, {
+ type: "cron",
+ options: {
+ cron: userSchedule,
+ },
+ });
+}
+
+//5. Register inside other Jobs
+new Job(client, {
+ id: "register-dynamicinterval",
+ name: "Register Dynamic Interval",
+ version: "0.1.1",
+ trigger: eventTrigger({
+ name: "dynamic.interval",
+ schema: z.object({
+ userId: z.string(),
+ seconds: z.number().int().positive(),
+ }),
+ }),
+ run: async (payload, io, ctx) => {
+ //6. Register the DynamicSchedule
+ await io.registerInterval("📆", dynamicSchedule, payload.userId, {
+ seconds: payload.seconds,
+ });
+
+ await io.wait("wait", 60);
+
+ //7. Unregister the DynamicSchedule if you want
+ await io.unregisterInterval("❌📆", dynamicSchedule, payload.id);
+ },
+});
+```
+
+## DynamicTrigger
+
+```typescript
+//1. create a DynamicTrigger
+const dynamicOnIssueOpenedTrigger = new DynamicTrigger(client, {
+ id: "github-issue-opened",
+ event: events.onIssueOpened,
+ source: github.sources.repo,
+});
+
+//2. create a Job that is attached to the dynamic trigger
+new Job(client, {
+ id: "listen-for-dynamic-trigger",
+ name: "Listen for dynamic trigger",
+ version: "0.1.1",
+ trigger: dynamicOnIssueOpenedTrigger,
+ integrations: {
+ slack,
+ },
+ run: async (payload, io, ctx) => {
+ await io.slack.postMessage("Slack 📝", {
+ text: `New Issue opened on repo: ${
+ payload.issue.html_url
+ }. \n\n${JSON.stringify(ctx)}`,
+ channel: "C04GWUTDC3W",
+ });
+ },
+});
+
+//3. Register the DynamicTrigger anywhere in your app
+async function registerRepo(owner: string, repo: string) {
+ //the first param (key) should be unique
+ await dynamicOnIssueOpenedTrigger.register(`${owner}/${repo}`, {
+ owner,
+ repo,
+ });
+}
+
+//4. Register inside other Jobs
+new Job(client, {
+ id: "new-repo",
+ name: "New repo",
+ version: "0.1.1",
+ //5. when a new repo is created in your org
+ trigger: github.triggers.org({
+ event: events.onNewRepository,
+ org: "triggerdotdev",
+ }),
+ run: async (payload, io, ctx) => {
+ //6. Register the dynamic trigger so you get notified when an issue is opened
+ return await io.registerTrigger(
+ "register-repo",
+ dynamicOnIssueOpenedTrigger,
+ payload.repository.name,
+ {
+ owner: payload.repository.owner.login,
+ repo: payload.repository.name,
+ }
+ );
+ },
+});
+```
diff --git a/docs/documentation/concepts/triggers/events.mdx b/docs/documentation/concepts/triggers/events.mdx
new file mode 100644
index 000000000..e0b4ca7b4
--- /dev/null
+++ b/docs/documentation/concepts/triggers/events.mdx
@@ -0,0 +1,151 @@
+---
+title: "Event triggers"
+sidebarTitle: "Events"
+description: "Event triggers allow you to run Jobs from your own code (or your other Jobs)"
+---
+
+> 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](https://github.com/colinhacks/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](https://github.com/colinhacks/zod#installation) 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](/guides/zod) for more information.
+
+## Example
+
+```ts
+new Job(client, {
+ 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](/sdk/triggerclient/instancemethods/sendevent).
+
+```ts
+//somewhere in your code, can even be on another server
+await client.sendEvent({
+ name: "user.created",
+ payload: { name: "John Doe", email: "john@doe.com", 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](/sdk/io/sendevent).
+
+```ts
+new Job(client, {
+ 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: "rick.astley@gmail.com" },
+ });
+ },
+});
+```
+
+## Event filters
+
+They are declarative pattern-matching rules, modeled after [AWS EventBridge patterns](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns.html).
+
+Given the following custom event payload:
+
+```json
+{
+ "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": "eric@trigger.dev",
+ "language": { "locale": "en" },
+ "timeZone": "Europe/London"
+ }
+}
+```
+
+The following event filter would match the event:
+
+```json
+{
+ "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"`.
diff --git a/docs/documentation/concepts/triggers/introduction.mdx b/docs/documentation/concepts/triggers/introduction.mdx
new file mode 100644
index 000000000..c626e7852
--- /dev/null
+++ b/docs/documentation/concepts/triggers/introduction.mdx
@@ -0,0 +1,37 @@
+---
+title: Introduction
+description: "A Trigger is what starts a Job Run. It can be a webhook, a schedule, or an event."
+---
+
+We currently support three types of Triggers: Webhooks, Scheduled, and Events. You can use any of these to start a Job Run.
+
+
+
+ Start your Jobs in realtime when events happen in APIs
+
+
+ Run a Job on a repeating schedule
+
+
+ Run your Job when you send events with data
+
+
+ Create Triggers and Schedules with dynamic settings
+
+
diff --git a/docs/documentation/concepts/triggers/scheduled.mdx b/docs/documentation/concepts/triggers/scheduled.mdx
new file mode 100644
index 000000000..f92d60a2c
--- /dev/null
+++ b/docs/documentation/concepts/triggers/scheduled.mdx
@@ -0,0 +1,61 @@
+---
+title: "Scheduled triggers"
+sidebarTitle: "Scheduled"
+description: "Run a Job on a recurring schedule"
+---
+
+A Scheduled Trigger runs a Job on a repeated schedule. You can set the schedule using a CRON expression or an interval.
+
+
+
+## Interval
+
+This job will run every 60 seconds, starting 60 seconds after this Job is first indexed. Note that it does not run at the top of every minute, but rather 60 seconds after the Job is first indexed.
+
+```ts
+import { Job, intervalTrigger } from "@trigger.dev/sdk";
+
+new Job(client, {
+ id: "scheduled-job-1",
+ name: "Scheduled Job 1",
+ version: "0.1.1",
+ trigger: intervalTrigger({
+ seconds: 60,
+ }),
+ run: async (payload, io, ctx) => {
+ await io.logger.info("Received the scheduled event", {
+ payload,
+ });
+
+ return { foo: "bar" };
+ },
+});
+```
+
+## Using CRON syntax
+
+If you want a Job to run at a specific time or on a specific day of the week, you can use a CRON expression.
+
+This job will run at 2:30pm every Monday. You can get help with [CRON syntax](https://crontab.guru/#30_14_*_*_1).
+
+These are not in local time, they are UTC.
+
+```ts
+import { Job, cronTrigger } from "@trigger.dev/sdk";
+
+new Job(client, {
+ id: "scheduled-job-2",
+ name: "Scheduled Job 2",
+ version: "0.1.1",
+ trigger: cronTrigger({
+ cron: "30 14 * * 1",
+ }),
+ run: async (payload, io, ctx) => {
+ await io.logger.info("Received the scheduled event", {
+ payload,
+ });
+
+ return { foo: "bar" };
+ },
+});
+```
diff --git a/docs/documentation/concepts/triggers/webhooks.mdx b/docs/documentation/concepts/triggers/webhooks.mdx
new file mode 100644
index 000000000..f656e56be
--- /dev/null
+++ b/docs/documentation/concepts/triggers/webhooks.mdx
@@ -0,0 +1,54 @@
+---
+title: "Webhooks"
+sidebarTitle: "Webhooks"
+description: "Webhooks allow you to subscribe to events from APIs you use."
+---
+
+Webhooks are a crucial part of API development, allowing for real-time reactions to various events across different systems, such as when a Stripe Payment is made, or when a GitHub issue is created.
+
+## Advantages of using Trigger.dev for webhooks
+
+Webhooks can be difficult to work with, especially when developing locally. We make them far easier to use with our [Integrations](/integrations).
+
+- You don't need to register/unregister for webhooks, we do it for you
+- We receive the webhook, then keep trying to send it to you until you receive it. If your server goes down, no problem.
+
+## Usage
+
+There are two ways to use webhooks with Trigger.dev:
+
+1. Use one of our built-in Integrations, such as [GitHub](/integrations/github). We'll take care of registering the webhook for you.
+2. [Create your own Integration](/integrations/create) that registers for webhooks, this is useful if you want to use a service that we don't have an Integration for.
+
+## Example
+
+```ts Github
+import { Job } from "@trigger.dev/sdk";
+import { Github, events } from "@trigger.dev/github";
+
+//GitHub integration with API Key (it supports OAuth too)
+const github = new Github({
+ id: "github",
+ token: process.env.GITHUB_API_KEY!,
+});
+
+new Job(client, {
+ id: "critical-issue-alert",
+ name: "Critical Issue Alert",
+ version: "0.1.0",
+ //When a GitHub issue is modified on the triggerdotdev/trigger.dev repo
+ trigger: github.triggers.repo({
+ event: events.onIssue,
+ owner: "triggerdotdev",
+ repo: "trigger.dev",
+ }),
+ //include any integrations you want to use
+ integrations: {
+ slack,
+ },
+ //this function gets executed when the webhook is received
+ run: async (payload, io, ctx) => {
+ await io.logger.info(`Action was ${payload.action}`);
+ },
+});
+```
diff --git a/docs/documentation/concepts/what-is-triggerdotdev.mdx b/docs/documentation/concepts/what-is-triggerdotdev.mdx
new file mode 100644
index 000000000..ecf616c67
--- /dev/null
+++ b/docs/documentation/concepts/what-is-triggerdotdev.mdx
@@ -0,0 +1,105 @@
+---
+title: "What is Trigger.dev?"
+sidebarTitle: "What is Trigger.dev?"
+---
+
+Trigger.dev is a platform, SDK and API for building and running Jobs in your codebase, triggered by various sources, but without having to worry about managing any complicated orchestration infrastructure.
+
+It can be used from _any_ Node.js (support versions) or TypeScript backend application (including serverless applications and microservices).
+
+## What we take care of for you:
+
+- We make it possible to run long-running Jobs on serverless platforms that have short timeouts (e.g. 30 seconds).
+- We provide an SDK for building Jobs in your codebase, triggered by various sources such as [events](/triggers/events), [scheduled events](/triggers/scheduled-events), and [webhooks](/triggers/webhooks).
+- We provide an orchestration platform for running Jobs in your codebase.
+- We provide out-of-the-box Integrations with popular services such as [Slack](/integrations/apis/slack), [OpenAI](/integrations/apis/openai), [GitHub](/integrations/apis/github) and [more](/integrations), which vastly simplifies the process interacting with 3rd-party services.
+ - We handle OAuth for you
+- We provide a nice UI for viewing and debugging your Jobs.
+
+## What you take care of:
+
+- You write your Jobs in your codebase.
+- You get a Trigger.dev API Key and add it to your codebase.
+- You deploy your codebase.
+
+## How it works
+
+To get an idea of how Trigger.dev works, let's take a look at a simple Job that sends a Slack message when a GitHub issue is labelled as `critical`:
+
+```ts
+import { Job } from "@trigger.dev/sdk";
+import { Github, events } from "@trigger.dev/github";
+import { Slack } from "@trigger.dev/slack";
+
+//GitHub integration with API Key (it supports OAuth too)
+const github = new Github({
+ id: "github",
+ token: process.env.GITHUB_API_KEY!,
+});
+
+//Slack integration with OAuth
+const slack = new Slack({
+ id: "slack",
+});
+
+new Job(client, {
+ id: "critical-issue-alert",
+ name: "Critical Issue Alert",
+ version: "0.1.0",
+ //When a GitHub issue is modified on the triggerdotdev/trigger.dev repo
+ trigger: github.triggers.repo({
+ event: events.onIssue,
+ owner: "triggerdotdev",
+ repo: "trigger.dev",
+ }),
+ //include any integrations you want to use
+ integrations: {
+ slack,
+ },
+ //this function gets executed when the trigger fires
+ run: async (payload, io, ctx) => {
+ await io.logger.info(`Action was ${payload.action}`);
+
+ if (payload.action === "labeled" && payload.label?.name === "critical") {
+ //use the Slack integration to post a message
+ await io.slack.postMessage("post message", {
+ channel: "C04GWUTDC3W",
+ text: `Issue ${payload.issue.number}: ${payload.issue.title} is critical!`,
+ });
+ }
+ },
+});
+```
+
+This code lives in a file inside your Next.js repo.
+
+It is listening for the [issueEvent](/integrations/apis/github/triggers) GitHub webhook, and when it receives one, we will take care of calling the `run` function supplied to the `Job` constructor with the webhook payload. This gives you the following advantages over traditional webhooks:
+
+- We will automatically register the webhook with GitHub for you, and verify the payload signature.
+- We provide a nicely typed `event` payload to your `run` function, so you don't have to setup webhook payload types.
+- If your server isn't running, we will wait until it's back online before attempting to run the Job.
+- It is very easy to test your Job locally using our [Test Run](/guides/running-tests) feature.
+
+As you can see the above Job also makes a call to our Slack [postMessage](/integrations/apis/slack) function, which provides the following advantages over using the raw Slack API:
+
+- We automatically handle the OAuth flow for you, so you don't have to worry about setting up a Slack app and dealing with credentials in your code (see our [Authentication](/concepts/authentication) guide for more details).
+- We will automatically retry the request if the Slack API returns an error.
+- We provide a nicely typed `response` object from your `postMessage` function, so you don't have to setup Slack API types.
+
+## Why use Trigger.dev?
+
+Apart from the reasons mentioned above, there are a few other reasons why you might want to use Trigger.dev:
+
+- You want to access your database or other internal services from your Jobs, without having to expose them to the internet.
+- You want to colocate your Jobs with your code, so you can deploy them together in one atomic unit.
+- You want to build event-driven architectures without having to manage any complicated orchestration infrastructure.
+- You want to add in delays or retries to your Jobs, without having to worry about managing a queue.
+
+## Architecture
+
+Below is a simplified architecture diagram of how Trigger.dev works:
+
+{/* https://www.tldraw.com/r/v2_KEeyTalIH0NRKdsb01Lqt?viewport=36%2C-165%2C2234%2C1420&page=page%3AOecar06rEOb6Kpu9XzDKo */}
+
+
+As you can see above, we communicate between your code and the Trigger.dev platform. This allows us to send events to your code, and receive tasks from your code.
diff --git a/docs/documentation/faq.mdx b/docs/documentation/faq.mdx
new file mode 100644
index 000000000..e698ed104
--- /dev/null
+++ b/docs/documentation/faq.mdx
@@ -0,0 +1,83 @@
+---
+title: "FAQ"
+description: "This section is aimed at collecting common questions from users to provide documented answers."
+---
+
+
+ Yes, view our [self-hosting guide](/documentation/guides/self-hosting).
+
+
+
+ Only what you choose to send. The main body of your Job code runs on your
+ infrastructure. For example when you do a database query, that never touches
+ us. We receive data that triggers the start of a Job, any data you pass to one
+ of our API Integrations, and any data you choose to log using our logging
+ function. We store this to display on the Runs page of your dashboard.
+
+
+
+ No, you'll be able to use Trigger.dev with a variety of other frameworks,
+ serverless or otherwise, such as Node.js, Remix, and Express, in addition to
+ Next.js.
+
+
+
+ Trigger.dev is a code-first tool that lets you create Jobs directly in your
+ code, rather than using a UI builder like Zapier. This means you can stay in
+ your own IDE and keep your internal data secure.
+
+
+
+ Yes. Jobs are created in your code locally.
+
+
+
+ Yes. There’s no limit to the complexity of Jobs you can create. Jobs are
+ created in code so you can write conditional, looping, branching or time
+ delayed logic.
+
+
+
+ A run is a single execution of a Job. This can be in either development,
+ staging or production. [View full details](/documentation/concepts/runs).
+
+
+
+ Yes. You create Jobs directly in your own code so it’s version controlled with
+ everything else.
+
+
+
+ A simple Job doing a couple of API calls from different services will take
+ about 5 minutes to create.
+
+
+
+ View [our Integrations page](/integrations) to see the Integrations we
+ currently support. If we don't have an Integration you need, you can request
+ it or create it yourself.
+
+
+
+ Yes, Trigger.dev is open source. We are strong supporters of open source
+ software, and our first product, [jsonhero.io](https://jsonhero.io), has a
+ thriving open source community. Trigger.dev follows in that tradition.
+
+
+
+ No. Trigger.dev is designed for developers who want to create Jobs directly in
+ code, without using a UI builder like Zapier. This allows developers to stay
+ in their familiar development environment and customise their Jobs with code.
+
+
+
+ Developers will need to create Jobs. However, anyone on the team can monitor
+ running Jobs in the Trigger.dev dashboard.
+
+
+
+ Hop in our [Discord](https://discord.gg/nkqV9xBYWy) and ask any question you have in there!
+
+You could also open a [GitHub issue](https://github.com/triggerdotdev/trigger.dev/issues/new).
+
+
diff --git a/docs/documentation/get-help.mdx b/docs/documentation/get-help.mdx
new file mode 100644
index 000000000..38789ec04
--- /dev/null
+++ b/docs/documentation/get-help.mdx
@@ -0,0 +1,26 @@
+---
+title: "Get in touch with us!"
+sidebarTitle: "Get help"
+description: "Contact us if you have any questions, or would like help with any issues."
+---
+
+We are active in the community and will respond to all messages.
+
+Please email us at help@trigger.dev or choose one of the options below:
+
+
+
+ The place to meet other users, the team and to get product updates.
+
+
+ A call with someone from our team. We are happy to help.
+
+
diff --git a/docs/documentation/guides/cli.mdx b/docs/documentation/guides/cli.mdx
new file mode 100644
index 000000000..a41087afe
--- /dev/null
+++ b/docs/documentation/guides/cli.mdx
@@ -0,0 +1,109 @@
+---
+title: "Using the CLI"
+description: "How to use the CLI"
+---
+
+## Introduction
+
+If you're setting up your project for the first time, we recommend using the CLI by following the [Quickstart guide](/documentation/quickstart).
+
+## init Command
+
+The `init` command incorporates Trigger.dev into your Next.js project. It performs the following functions:
+
+- Adds Trigger.dev to the project.
+- Creates a new route.
+- Generates an example file.
+
+ During execution, this command requires some configuration parameters. Detailed information on these parameters can be found in the next section.
+
+
+
+Run this `init` command in a terminal window to setup your project with Trigger.dev
+
+
+
+```bash npm
+npx @trigger.dev/cli@latest init
+```
+
+```bash pnpm
+pnpm dlx @trigger.dev/cli@latest init
+```
+
+```bash yarn
+yarn dlx @trigger.dev/cli@latest init
+```
+
+
+
+### CLI steps explained
+
+
+
+
+ Trigger.dev Cloud is a fully hosted service that provides the easiest and quickest way to use Trigger.dev.
+
+
+ Instead of using the Trigger.dev Cloud service which we host for you, you
+ can host the Trigger.dev platform yourself. We provide an official
+ Trigger.dev Docker image you can use to easily self-host on your preferred
+ platform. More information on self-hosting can be found in the
+ self-hosting section of the docs
+ [here](/documentation/guides/self-hosting).
+
+ When following the [self-hosting guide](/documentation/guides/self-hosting) you will deploy your Docker image to a platform of your choice. After completing this step, enter the URL of your self-hosted instance in this CLI step.
+
+
+
+
+
+
+ To locate your development API key, login to the [Trigger.dev
+ dashboard](https://cloud.trigger.dev) and select the Project you want to
+ connect to. Then click on the Environments & API Keys tab in the left menu.
+ You can copy your development API Key from the field at the top of this page.
+ (Your development key will start with `tr_dev_`).
+
+
+
+ Enter a custom ID or use the default by hitting enter. You can learn more
+ about endpoints
+ [here](/documentation/concepts/environments-endpoints#endpoints).
+
+
+
+
+## dev Command
+
+Once you're running your Next.js project locally, you can then execute the `dev` CLI command to run Trigger.dev locally. You should run this command every time you want to use Trigger.dev locally.
+
+
+
+
+ Make sure your Next.js site is running locally before continuing. You must
+ also leave this `dev` terminal command running while you develop.
+
+
+In a **new terminal window or tab** run:
+
+
+
+```bash npm
+npx @trigger.dev/cli@latest dev
+```
+
+```bash pnpm
+pnpm dlx @trigger.dev/cli@latest dev
+```
+
+```bash yarn
+yarn dlx @trigger.dev/cli@latest dev
+```
+
+
+
+
+ You can optionally pass the port if you're not running on 3000 by adding
+ `--port 3001` to the end
+
diff --git a/docs/documentation/guides/contributing.mdx b/docs/documentation/guides/contributing.mdx
new file mode 100644
index 000000000..ae60aeb51
--- /dev/null
+++ b/docs/documentation/guides/contributing.mdx
@@ -0,0 +1,37 @@
+---
+title: "Contributing"
+description: "You can contribute Integrations and core code to the Trigger.dev platform "
+---
+
+Trigger.dev is open source and we welcome contributions from the community.
+
+
+
+ Our Open Source GitHub repo
+
+
+ You can view open issues and create new ones
+
+
+ Create an Integration for your own use or as a public package.
+
+
+ The place to meet other users, the team and to get product updates.
+
+
diff --git a/docs/documentation/guides/create-a-job.mdx b/docs/documentation/guides/create-a-job.mdx
new file mode 100644
index 000000000..773b99d7a
--- /dev/null
+++ b/docs/documentation/guides/create-a-job.mdx
@@ -0,0 +1,272 @@
+---
+title: "Create a Job"
+description: "How to create a Job in your codebase"
+---
+
+> Jobs are the core of the system. They allow you to run code when some event occurs. They are built using a combination of Triggers and Tasks.
+
+### Pre-requisites
+
+Make sure your Project is set up with Trigger.dev. We recommend [using the CLI](/documentation/quickstart) to do this.
+
+## How to write a Job in code
+
+### 1. Create a Job file in your Project
+
+This is where you will write your Job code. E.g. `my-job.ts`.
+
+```ts
+//this path might be different depending on your project
+import { client } from "@/trigger";
+
+client.defineJob({
+ // This is the unique ID for your Job's end-point
+ id: "your-job-id",
+ // This is the name of your Job
+ name: "Your Job name",
+ // This is the version of our SDK you are using
+ version: "0.0.1",
+ ...
+```
+
+The `id` and `name` are important because they are used to create and identify your Job in the app.
+
+
+ This Job must be imported in the `trigger` file in order to be registered when
+ the CLI dev command is run. This can be found in either the
+ `app/api/trigger/route.ts` file if you're using the Next.js App Router, or
+ `pages/api/trigger.ts` if you're using the Next.js Pages Router.
+
+
+### 2. Choose a Trigger
+
+This is what kicks-off a Job. There are a few different types of Triggers you can use:
+
+
+
+ Run a Job on a repeating schedule, using [intervalTrigger](/documentation/concepts/triggers/scheduled#interval)
+ ```ts
+ client.defineJob({
+ ...
+ trigger: intervalTrigger({
+ seconds: 60,
+ }),
+ ...
+ ```
+ Or with CRON syntax, using [cronTrigger](/documentation/concepts/triggers/scheduled#using-cron-syntax):
+ ```ts
+ client.defineJob({
+ ...
+ trigger: cronTrigger({
+ cron: "30 14 * * 1",
+ }),
+ ...
+ ```
+
+
+
+ Start your Jobs when an event happens in another API. You'll need to use [Integrations](/integrations) to do this.
+
+ Here's an example with the GitHub integration.
+
+ ```ts
+ client.defineJob({
+ ...
+ //E.g. When a GitHub issue is modified on the triggerdotdev/trigger.dev repo
+ trigger: github.triggers.repo({
+ event: events.onIssue,
+ owner: "triggerdotdev",
+ repo: "trigger.dev",
+ }),
+ ...
+ ```
+
+
+
+ The [eventTrigger](/documentation/concepts/triggers/events) allows you to define an event that your Job listens for.
+
+ When you [send an event](/documentation/concepts/triggers/events#sending-events) with the same name the Job will run.
+
+ ``` ts
+ client.defineJob({
+ ...
+ //E.g. when a user is created in your app (you send the event)
+ trigger: eventTrigger({
+ name: "user.created",
+ schema: z.object({
+ name: z.string(),
+ email: z.string(),
+ paidPlan: z.boolean(),
+ }),
+ ...
+ ```
+
+
+
+ These are advanced features that allows you to attach dynamic triggers to a Job. Full information [here](/documentation/concepts/triggers/dynamic).
+
+
+
+### 3. Create the Job Tasks
+
+> A Task is a resumable unit of a Run that can be retried, resumed and is logged.
+
+
+ You can use just regular code in your Jobs. But you don't get the benefits of
+ retrying, logging and resumability. More info on [Tasks vs regular
+ code](/documentation/concepts/tasks#tasks-vs-regular-code).
+
+
+You can string together multiple Tasks and regular code in any order you want.
+
+**Useful built-in Tasks:**
+
+| Task | Description | Task code |
+| ------------------------------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
+| [Delay](/documentation/concepts/delays) | Wait for a period of time | `await io.wait("wait", 60);` |
+| [Log](/sdk/io/logger) | Log a message | `await io.logger.log("Hello");` |
+| [Send Event](/sdk/io/sendevent) | Send an event (for eventTrigger) | `await io.sendEvent("my-event", { name: "my.event", payload: { hello: "world" } });` |
+| [Run task](/sdk/io/runtask) | Wrap your own code in this to create a Task | `await io.runTask("My Task", { name: "My Task" }, async () => { console.log("Hello"); });` |
+| [Background fetch](/sdk/io/backgroundfetch) | Fetch data from a URL that can take longer that the serverless timeout. | `await io.backgroundFetch("fetch-some-data", { url: "https://example.com" });` |
+
+For a full list of built-in Tasks, see the [io SDK reference](/sdk/io).
+
+**Integration Task examples:**
+
+
+ To use our integrations you will need to set them up in the app first. Our
+ guide is [here](/documentation/guides/using-integrations).
+
+
+
+
+
+**Task:** [backgroundCreateCompletion](/integrations/apis/openai)
+
+```ts
+await io.openai.backgroundCreateChatCompletion("background-chat-completion", {
+ model: "gpt-3.5-turbo",
+ messages: [
+ {
+ role: "user",
+ content: "Create a good programming joke about background jobs",
+ },
+ ],
+});
+```
+
+View more OpenAI tasks [here](/integrations/apis/openai).
+
+
+
+
+**Task:** [addIssueLabels](/integrations/apis/github-tasks)
+
+```ts
+await io.github.addIssueLabels("add label", {
+ owner: payload.repository.owner.login,
+ repo: payload.repository.name,
+ issueNumber: payload.issue.number,
+ labels: ["bug"],
+});
+```
+
+View more GitHub tasks [here](/integrations/apis/github-tasks).
+
+
+
+
+**Task:** [sendEmail](/integrations/apis/resend)
+
+```ts
+await io.resend.sendEmail("send-email", {
+ to: payload.to,
+ subject: payload.subject,
+ text: payload.text,
+ from: "Trigger.dev ",
+});
+```
+
+
+
+
+**Task:** [postMessage](/integrations/apis/slack)
+
+```ts
+await io.slack.postMessage("post message", {
+ channel: "C04GWUTDC3W",
+ text: "My first Slack message",
+});
+```
+
+View more Slack tasks [here](/integrations/apis/slack).
+
+
+
+
+These are just a few examples of Integration Tasks. For many more, browse our [Integrations section](/integrations/).
+
+### 4. Register your Jobs
+
+While your app is running, open a **new terminal window or tab** and run:
+
+
+
+```bash npm
+npx @trigger.dev/cli@latest dev
+```
+
+```bash pnpm
+pnpm dlx @trigger.dev/cli@latest dev
+```
+
+```bash yarn
+yarn dlx @trigger.dev/cli@latest dev
+```
+
+
+
+This will register all of your Jobs, they should appear in your dashboard.
+
+
+ Not seeing your Job in the web app? It might be because you forgot to import
+ it. This will need to be either in `app/api/trigger/route.ts` file if you're
+ using the Next,js App Router, or `pages/api/trigger.ts` if you're using the
+ Next,js Pages Router.
+
+
+If you are having trouble getting your job running, please reach out to us and we will help you fix any issues:
+
+- [Join our Discord](https://discord.gg/kA47vcd8P6)
+- [Email us](mailto:help@trigger.dev)
+
+---
+
+## Next steps
+
+We recommend exploring all of the below sections to fully understand how to create and run Jobs using Trigger.dev.
+
+
+
+ A guide for how to run your Jobs. Triggering a test Run and Triggering your Job for real
+
+
+
+
+ View example Jobs / the example jobs repo. These are a great starting
+ point for creating your own Jobs.
+
+
+ How to use the SDK. This includes all the available Tasks, triggers and
+ actions you can use.
+
+
+
+ Integrations make it easy to authenticate and use APIs.
+Learn how to use and create integrations.
+
+
diff --git a/docs/documentation/guides/deployment-automatic.mdx b/docs/documentation/guides/deployment-automatic.mdx
new file mode 100644
index 000000000..2853f95cf
--- /dev/null
+++ b/docs/documentation/guides/deployment-automatic.mdx
@@ -0,0 +1,46 @@
+---
+title: "Automatic endpoint refreshing"
+description: "Use our webhook to automatically tell us when you deploy"
+---
+
+## In the dashboard
+
+1. Go to the "Environments & API Keys" page in your Trigger.dev dashboard
+ 
+2. Select your endpoint row in the table of endpoints.
+ 
+3. There is a webhook URL in the "Automatic Refresh" section. Copy this URL.
+ 
+
+## How to use the webhook URL
+
+### Vercel
+
+You can use this webhook URL in your Vercel dashboard, so when a deployment succeeds it automatically refreshes the endpoint.
+
+1. From your Vercel team dashboard, select "Settings"
+ 
+2. Go to the "Webhooks" page
+ 
+3. Select the "Deployment Succeeded" event, your Vercel Project, and paste in our webhook URL. Then "Create Webhook".
+ 
+4. You're done! Whenever a deploy succeeds, Vercel will tell us to refresh your endpoint.
+ 
+
+### GitHub Actions
+
+You can add a step to the GitHub Action that deploys your app.
+
+```yaml .github/workflows/release.yml
+- name: 🚀 Refresh Trigger.dev Jobs
+ env:
+ DEPLOY_TEST_HOOK: ${{ secrets.TRIGGER_ENDPOINT_HOOK }}
+ run: |
+ curl -X POST $TRIGGER_ENDPOINT_HOOK
+```
+
+You will need to [setup the `TRIGGER_ENDPOINT_HOOK` secret in your GitHub repo](https://docs.github.com/en/actions/security-guides/encrypted-secrets#creating-encrypted-secrets-for-a-repository). Set it to the webhook URL from the endpoint panel.
+
+### Do an HTTP request yourself
+
+Any `GET` or `POST` request to the webhook URL will cause a refresh of the Jobs for that endpoint. `POST` requests don't need a body. There is no authentication required.
diff --git a/docs/documentation/guides/deployment-manual.mdx b/docs/documentation/guides/deployment-manual.mdx
new file mode 100644
index 000000000..05d9ceccc
--- /dev/null
+++ b/docs/documentation/guides/deployment-manual.mdx
@@ -0,0 +1,13 @@
+---
+title: "Manual endpoint refreshing"
+description: "You can manually refresh Endpoints in your Trigger.dev dashboard"
+---
+
+1. Go to the "Environments & API Keys" page in your Trigger.dev dashboard
+ 
+2. Select your endpoint row in the table of endpoints.
+ 
+3. Click the "Refresh now" button
+ 
+
+You should see the "Last refreshed" date update to the current time.
diff --git a/docs/documentation/guides/deployment-setup.mdx b/docs/documentation/guides/deployment-setup.mdx
new file mode 100644
index 000000000..f669049b6
--- /dev/null
+++ b/docs/documentation/guides/deployment-setup.mdx
@@ -0,0 +1,55 @@
+---
+title: "First-time setup"
+description: "The first time you deploy to a new environment you will need to setup the endpoint for that environment."
+---
+
+## 1. Make sure your Client is configured correctly
+
+The API Key you use for your `Client` is how we know which environment to run your code against:
+
+```ts
+export const client = new TriggerClient({
+ id: "nextjs-example",
+ //this environment variable should be set to your DEV API Key locally,
+ //and your PROD API Key in production
+ apiKey: process.env.TRIGGER_API_KEY!,
+});
+```
+
+## 2. Set your environment variables on your server
+
+Ensure that your `TRIGGER_API_KEY` (or whatever you've set it to) environment variable is set on your server, to the correct value from the "Environments & API Keys" page in your Trigger.dev dashboard.
+
+
+
+If you've used any other environment variables in your code (like API Keys for other services), make sure they are set on your server too.
+
+The exact instructions will vary depending on where you deploy to. Here are the docs links to some popular services:
+
+- [Vercel](https://vercel.com/docs/concepts/projects/environment-variables#)
+- [Cloudflare Pages](https://developers.cloudflare.com/pages/platform/functions/bindings/#environment-variables)
+- [Cloudflare Workers](https://developers.cloudflare.com/workers/platform/environment-variables/)
+- [Netlify](https://docs.netlify.com/environment-variables/overview/)
+
+## 3. Deploy your code as usual
+
+Your Job code lives in your codebase, so you can deploy it as you normally would.
+
+## 4. Connect the Endpoint for the first time
+
+1. Go to the "Environments & API Keys" page in your Trigger.dev dashboard
+ 
+
+2. Click the "Configure" button on the relevant endpoint
+ 
+
+3. Enter the URL of your Trigger.dev endpoint
+ 
+
+
+ This is the value of the `path` option for the adaptor you're using. For
+ Next.js, this would usually be `https://yourdomain.com/api/trigger`.
+
+
+4. Click "Save". This will automatically connect, test your endpoint, and register all your Jobs.
+ 
diff --git a/docs/documentation/guides/deployment.mdx b/docs/documentation/guides/deployment.mdx
new file mode 100644
index 000000000..833580151
--- /dev/null
+++ b/docs/documentation/guides/deployment.mdx
@@ -0,0 +1,42 @@
+---
+title: "Introduction"
+description: "A guide for how to deploy your Jobs"
+---
+
+Deployment uses [Environments & Endpoints](/documentation/concepts/environments-endpoints) to connect your Jobs to the Trigger.dev platform.
+
+## First time deploying to a new Environment
+
+The first time you deploy to a new environment you will need to setup the
+endpoint for that environment.
+
+
+ This only needs to be done once for each environment
+
+
+## Subsequent deployments (i.e. refreshing your Endpoint)
+
+If you add new Jobs, change the id of a Job, or change the Triggers of a Job then you will need to refresh your Endpoint.
+
+There are two ways to do this:
+
+
+
+ Manually refresh in your Trigger.dev dashboard
+
+
+ Automatically refresh by using our webhook
+
+
diff --git a/docs/documentation/guides/managing-jobs.mdx b/docs/documentation/guides/managing-jobs.mdx
new file mode 100644
index 000000000..217bdb414
--- /dev/null
+++ b/docs/documentation/guides/managing-jobs.mdx
@@ -0,0 +1,49 @@
+---
+title: "Managing Jobs"
+description: "How to view, add, modify, and delete jobs"
+---
+
+[Jobs](/documentation/concepts/jobs) live inside a [Project](/documentation/concepts/projects).
+
+For Jobs to actually run, they need to be connected to the Trigger.dev platform.
+
+## Viewing Jobs
+
+The main page for a Project is the list of connected Jobs. You can see overview details for a each Job here, including details on the Trigger, Integrations and when it was last run.
+
+
+ 
+
+
+## How to add your first Job
+
+We recommend you do the initial setup of a new Project by following our [quick start guide](/documentation/quickstart). Once completed you should have an example Job in your dashboard.
+
+## Adding more Jobs locally
+
+When you add a new Job to your codebase, you'll need to connect it to Trigger.dev. This is achieved by refreshing the endpoint in your local Dev environment.
+
+1. Go to the "Environments & API Keys" page for your Project
+ 
+2. Select the "DEV" row in the table of endpoints.
+ 
+3. Click the "Refresh now" button
+ 
+
+
+ You only need to do this when you add a new Job (a job with an ID that hasn't
+ been connected to Trigger.dev before). If you modify an existing Job, you
+ don't need to refresh the endpoint.
+
+
+## Deploying Jobs
+
+See our [deployment guide](/documentation/guides/deployment).
+
+## Disabling Jobs
+
+Sometimes there's a Job that you no longer want to be Triggered. You can achieve this by Disabling it. This will prevent the `run()` function being called for that Job.
+
+## Archiving Jobs
+
+Being able to archive Jobs is coming soon
diff --git a/docs/documentation/guides/platforms/express.mdx b/docs/documentation/guides/platforms/express.mdx
new file mode 100644
index 000000000..4136ddb62
--- /dev/null
+++ b/docs/documentation/guides/platforms/express.mdx
@@ -0,0 +1,6 @@
+---
+title: "Express"
+description: "How to get setup and deploy your Express project"
+---
+
+Support for Express is coming very soon
diff --git a/docs/documentation/guides/platforms/nextjs.mdx b/docs/documentation/guides/platforms/nextjs.mdx
new file mode 100644
index 000000000..f17e26369
--- /dev/null
+++ b/docs/documentation/guides/platforms/nextjs.mdx
@@ -0,0 +1,94 @@
+---
+title: "Next.js"
+description: "How to get setup and deploy Jobs for your Next.js project"
+---
+
+You can write Jobs in your Next.js codebase and deploy to both serverless platforms and long-running servers.
+
+## Supported platforms
+
+We support all platforms because under-the-hood an API endpoint is used to run your Jobs.
+
+## Initial setup
+
+View our [Quick start guide](/documentation/quickstart) to get setup.
+
+## Writing Jobs
+
+View our [guide for writing Jobs](/documentation/guides/create-a-job).
+
+## Deployment
+
+View our [deployment guide](/documentation/guides/deployment) to learn how to deploy your Jobs.
+
+## Middleware
+
+Next.js Middleware allows you to run code before a request is completed, and if you are using it currently in your Next.js project (or you add it later), you might need to guard against altering requests to the `/api/trigger` endpoint, which needs to be exposed to the Trigger.dev installation (either your self-hosted one or the Trigger.dev Cloud).
+
+To make sure you aren't matching the `/api/trigger` route in your middleware, check your `config.matcher` export:
+
+```ts middleware.ts
+import { NextResponse } from "next/server";
+import type { NextRequest } from "next/server";
+
+// This function can be marked `async` if using `await` inside
+export function middleware(request: NextRequest) {
+ return NextResponse.redirect(new URL("/home", request.url));
+}
+
+// See "Matching Paths" below to learn more
+export const config = {
+ matcher: "/about/:path*",
+};
+```
+
+The above matcher doesn't match `/api/trigger` so there won't be an issue here. But the following middleware.ts file will cause conflicts with Trigger.dev
+
+```ts middleware.ts
+export function middleware(request: NextRequest) {
+ return NextResponse.redirect(new URL("/home", request.url));
+}
+
+export const config = {
+ matcher: ["/((?!.*\\..*|_next).*)", "/", "/(api|trpc)(.*)"],
+};
+```
+
+As you can see, the last matcher `"/(api|trpc)(.*)"` matches anything starting with `api`, which matches `/api/trigger`. You can add a negative-lookahead pattern to the matcher to exclude the `/api/trigger` route:
+
+```ts middleware.ts
+export const config = {
+ matcher: ["/((?!.*\\..*|_next).*)", "/", "/(api((?!/trigger))|trpc)(.*)"],
+};
+```
+
+The above will match anything starting with `/api` except for `/api/trigger`.
+
+If you want to match all routes except for `/api/trigger`, you can use the following matcher:
+
+```ts middleware.ts
+// Match all routes other than /api/trigger
+export const config = {
+ matcher: ["/((?!api/trigger).*)"],
+};
+```
+
+For more information about middleware matchers, head over to the Next.js [middleware documentation](https://nextjs.org/docs/pages/building-your-application/routing/middleware#matcher).
+
+### Clerk.com Auth Middleware
+
+If you are using [Clerk.com](https://clerk.com) for your Next.js authentication, make sure to update your middleware file to add `/api/trigger` to the `publicRoutes`, like so:
+
+```ts middleware.ts
+import { authMiddleware } from "@clerk/nextjs";
+
+// Adding the /api/trigger route to the public routes so clerk doesn't return a 401
+// /api/trigger will handle it's own authentication
+export default authMiddleware({
+ publicRoutes: ["/api/trigger"],
+});
+
+export const config = {
+ matcher: ["/((?!.*\\..*|_next).*)", "/", "/(api|trpc)(.*)"],
+};
+```
diff --git a/docs/documentation/guides/rerunning.mdx b/docs/documentation/guides/rerunning.mdx
new file mode 100644
index 000000000..f60db0ca7
--- /dev/null
+++ b/docs/documentation/guides/rerunning.mdx
@@ -0,0 +1,24 @@
+---
+title: "Rerunning"
+description: "From a Run page, you can rerun"
+---
+
+On the Run page when the Run is in a `success` or `failed` state, you can rerun by clicking the `Rerun` button.
+
+
+
+There are two possible rerun options.
+
+### 1. Run again
+
+This option is always available (when a run has finished).
+
+It creates a brand new run with the same inputs as the original – the same Trigger payload, settings, connections etc.
+
+Stating the obvious: this will run all the code again.
+
+### 2. Retry job run
+
+This option is only available when the run has failed.
+
+It will continue the existing Run by retrying the Task that failed the Job.
diff --git a/docs/documentation/guides/running-jobs.mdx b/docs/documentation/guides/running-jobs.mdx
new file mode 100644
index 000000000..1ac568598
--- /dev/null
+++ b/docs/documentation/guides/running-jobs.mdx
@@ -0,0 +1,37 @@
+---
+title: "Running your Jobs"
+description: "A guide for how to run your Jobs."
+---
+
+There are two ways to run your Jobs:
+
+1. Triggering a test Run
+2. Triggering your Job for real
+
+## 1. Triggering a test Run
+
+You can perform a Run with any payload you want or use one of our examples on the test page in our dashboard.
+
+[How to do a test Run from the dashboard](/documentation/guides/testing-jobs).
+
+## 2. Triggering your Job for real
+
+Triggering your Job for real depends on the [type of trigger](/documentation/concepts/triggers) you have attached to your Job.
+
+There are three types of Trigger:
+
+### Scheduled Trigger
+
+
+
+[Scheduled Triggers](/documentation/concepts/triggers/scheduled) are triggered automatically by our system on the schedule you define. Once you have [deployed](/documentation/guides/deployment) your Job, it will run automatically.
+
+### Event Trigger
+
+[Event Triggers](/documentation/concepts/triggers/event) are triggered by an event that you send from elsewhere in your code.
+
+
+
+### Webhook Trigger
+
+[Webhook Triggers](/documentation/concepts/triggers/webhook) are triggered when you perform the action that the webhook subscribes to. For example, if you have a webhook Trigger that subscribes to the `pull_request` event on GitHub, then it will be triggered whenever a pull request is opened, closed, or updated on the repo you configured.
diff --git a/docs/documentation/guides/self-hosting.mdx b/docs/documentation/guides/self-hosting.mdx
new file mode 100644
index 000000000..2a576009b
--- /dev/null
+++ b/docs/documentation/guides/self-hosting.mdx
@@ -0,0 +1,36 @@
+---
+title: "Self hosting"
+description: "You can self-host the Trigger.dev platform"
+---
+
+## What does this mean?
+
+Instead of using the [Trigger.dev Cloud](https://cloud.trigger.dev) service which we host for you, you can host the Trigger.dev platform yourself.
+
+## Local development
+
+When you're working on your web app, you can run Trigger.dev locally alongside your web app.
+
+- See our [GitHub docker project](https://github.com/triggerdotdev/docker) for instructions.
+- You will need to [setup tunneling](/documentation/guides/tunneling-platform) if you want to receive webhooks from external services.
+
+## Deployment
+
+We provide an official Trigger.dev [docker image](https://github.com/triggerdotdev/trigger.dev/pkgs/container/trigger.dev) you can use to easily self-host on your preferred platform. We also provide guides for some popular platforms:
+
+
+
+ Easily to deploy to Fly.io
+
+
+ Easily to deploy to Render.com
+
+
diff --git a/docs/documentation/guides/self-hosting/flyio.mdx b/docs/documentation/guides/self-hosting/flyio.mdx
new file mode 100644
index 000000000..2c99ccad6
--- /dev/null
+++ b/docs/documentation/guides/self-hosting/flyio.mdx
@@ -0,0 +1,143 @@
+---
+title: "Deploy to Fly.io"
+description: "Deploy self hosted version of [Trigger.dev](https://trigger.dev) to Fly.io"
+---
+
+You can use this [repository](https://github.com/triggerdotdev/fly.io) as a jumping off point for deploying a self-hosted version of Trigger.dev on Fly.io using the Trigger.dev public docker image located at `ghcr.io/triggerdotdev/trigger.dev:latest`
+
+## Fork the repository mentioned above and change the app name
+
+You should fork the repository before starting so you can make changes and commit them. For example, you'll need to change the `app` property in the `fly.toml` file to be something other than `app = "trigger-v2-fly-demo"`.
+
+## Install and configure the fly.io CLI
+
+1. Install the Fly CLI tool:
+
+
+
+```sh Mac
+brew install flyctl
+```
+
+```sh Windows
+pwsh -Command "iwr https://fly.io/install.ps1 -useb | iex"
+```
+
+
+
+2. Authenticate the CLI:
+
+```sh
+fly auth login
+```
+
+## Create the fly.io app and pg db
+
+1. Launch the app:
+
+```sh
+fly launch
+```
+
+2. Follow the prompts by `fly launch` and make sure to answer them in the following way:
+
+```sh
+? Would you like to copy its configuration to the new app? Yes
+? Choose an app name (leaving blank will default to 'trigger-v2-fly-demo')
+? Would you like to set up a Postgresql database now? Yes
+? Select configuration: Development - Single node, 1x shared CPU, 256MB RAM, 1GB disk <- feel free to pick a beefier machine
+? Would you like to set up an Upstash Redis database now? No
+? Would you like to deploy now? No
+```
+
+## Gather your secret environment variables
+
+### Required
+
+`MAGIC_LINK_SECRET`, `SESSION_SECRET` and `ENCRYPTION_KEY`
+
+All of these secrets should be 16-byte random strings, which you can easily generate (and copy into your pasteboard) with the following command:
+
+```sh
+openssl rand -hex 16 | pbcopy
+```
+
+`LOGIN_ORIGIN` and `APP_ORIGIN`
+
+Both of these secrets should be set to the base URL of your fly application. For example `https://trigger-v2-fly-demo.fly.dev`
+
+### Optional
+
+`AUTH_GITHUB_CLIENT_ID` and `AUTH_GITHUB_CLIENT_SECRET`
+
+1. If you plan on logging in with GitHub auth, you'll need to create a GitHub OAuth app with the following configuration:
+
+
+
+2. Once you register the application you'll need to click on the "Generate new client secret" button:
+
+
+
+3. And then you can copy out the AUTH_GITHUB_CLIENT_ID and AUTH_GITHUB_CLIENT_SECRET:
+
+
+
+`RESEND_API_KEY`, `FROM_EMAIL` and `REPLY_TO_EMAIL`
+
+We use [Resend.com](https://resend.com) for email sending (including the magic-link signup/login system). They have a generous free tier of 100 emails a day that should be sufficient. Signup for Resend.com and enter the environment vars below
+
+## Set the secrets
+
+Call the `fly secrets set` command to stage the secrets to be used on first deploy:
+
+```sh
+fly secrets set \
+ ENCRYPTION_KEY= \
+ MAGIC_LINK_SECRET= \
+ SESSION_SECRET= \
+ LOGIN_ORIGIN="https://.fly.dev" \
+ APP_ORIGIN="https://.fly.dev" \
+ FROM_EMAIL="Acme Inc. " \
+ REPLY_TO_EMAIL="Acme Inc. " \
+ RESEND_API_KEY= \
+ AUTH_GITHUB_CLIENT_ID= \
+ AUTH_GITHUB_CLIENT_SECRET=
+
+Secrets are staged for the first deployment
+```
+
+## Deploy
+
+Now you can deploy to fly. Here we are setting the machine VM size to use 1 dedicated CPU core with 2 GB of memory, but you can run `fly platform vm-sizes` to see other options. The below app will cost about $30/month.
+
+```sh
+fly deploy --vm-size performance-1x
+```
+
+## Visit and create an account
+
+Once deployed, you should be able to open `https://.fly.dev/` in your browser and create an account, either using GitHub or a magic email link.
+
+## Initialize your Next.js project
+
+Next you can easily bootstrap your Next.js project to use your self-hosted instance of Trigger.dev.
+
+First, `cd` into your Next.js project, then run the `@trigger.dev/cli init` command to initialize your Next.js project:
+
+```sh
+npx @trigger.dev/cli@latest init -t "https://.fly.dev"
+```
+
+When it asks for your development API key, head over to your self-hosted Trigger.dev dashboard and select the initial project you created when signing up, and head to the `Environments & API Keys` page to copy your `dev` API key:
+
+
+
+## Start your dev server
+
+Run your Next.js project dev server with `npm run dev` and then in a new terminal window you will need to run the `@trigger.dev/cli dev` command to connect to your Trigger.dev instance and allow it to tunnel to your local Next.js server:
+
+```sh
+npx @trigger.dev/cli@latest dev
+```
+
+At this point you should be able to navigate to your Trigger.dev dashboard and view your registered jobs
diff --git a/docs/documentation/guides/self-hosting/render.mdx b/docs/documentation/guides/self-hosting/render.mdx
new file mode 100644
index 000000000..16fddc354
--- /dev/null
+++ b/docs/documentation/guides/self-hosting/render.mdx
@@ -0,0 +1,72 @@
+---
+title: "Deploy to Render"
+description: "Deploy self hosted version of [Trigger.dev](https://trigger.dev) to [Render](https://render.com/)"
+---
+
+You can use this [repository](https://github.com/triggerdotdev/render.com) as a jumping off point for deploying a self-hosted version of Trigger.dev on Render using the Trigger.dev public docker image located at `ghcr.io/triggerdotdev/trigger.dev:latest`
+
+### Fork the repository mentioned above and change the app name
+
+You should fork the repository before starting so you can make changes and commit them. For example, in render.yaml file you'll need to change the name under services to a unique name for your app.
+
+### Create a new web service
+
+1. Go to the Render dashboard.
+
+2. Click on "New" in the top right corner.
+
+3. Choose "Web service"
+
+ 
+
+4. Click on "Connect With GitHub" (if you have not already done so). You will need to authorize Render to access your GitHub repositories.
+
+5. Once connected, you will see a list of your repositories. Choose the repository that contains your project.
+
+6. Render will detect the render.yaml file in your repository and auto fill the fields, add your app name now.
+
+ 
+
+7. Scrolldown, click on advanced. Here you will need to add the environment variables
+
+ 
+
+### Gather your secret environment variables
+
+The process for generating and collecting the required environment variables is identical to the one described in the [Fly.io guide](/documentation/guides/self-hosting/flyio#gather-your-secret-environment-variables). Follow the steps there to generate and collect the required environment variables.
+
+### Set the environment variables
+
+The render.yaml file declares several environment variables that your app needs to run. These include the `ENCRYPTION_KEY`, `MAGIC_LINK_SECRET` and `SESSION_SECRET`, and others. You need to manually set the values of these environment variables in the Render dashboard:
+
+1. Click on "Add Environment Variable" to add a new environment variable.
+2. Enter the key and value for each environment variable declared in your render.yaml file. The key should match the name of the environment variable in the render.yaml file.
+ 
+
+### Deploy
+
+Render automatically deploys your service when you push to the connected GitHub repository. Alternatively, you can manually trigger a deployment from the Render dashboard by clicking "Deploy" in the "Deploys" tab.
+
+### Initialize your Next.js project
+
+Next, you can easily bootstrap your Next.js project to use your self-hosted instance of Trigger.dev.
+
+First, cd into your Next.js project, then run the `@trigger.dev/cli init` command to initialize your Next.js project:
+
+```sh
+npx @trigger.dev/cli@latest init -t "https://.onrender.com"
+```
+
+When it asks for your development API key, head over to your self-hosted Trigger.dev dashboard and select the initial project you created when signing up, and head to the `Environments & API Keys` page to copy your `dev` API key:
+
+
+
+### Start your dev server
+
+Run your Next.js project dev server with `npm run dev` and then in a new terminal window you will need to run the `@trigger.dev/cli dev` command to connect to your Trigger.dev instance and allow it to tunnel to your local Next.js server:
+
+```sh
+npx @trigger.dev/cli@latest dev
+```
+
+At this point you should be able to navigate to your Trigger.dev dashboard and view your registered jobs
diff --git a/docs/documentation/guides/testing-jobs.mdx b/docs/documentation/guides/testing-jobs.mdx
new file mode 100644
index 000000000..04ce3bf51
--- /dev/null
+++ b/docs/documentation/guides/testing-jobs.mdx
@@ -0,0 +1,25 @@
+---
+title: "Testing Jobs"
+description: "You can test Jobs from the dashboard."
+---
+
+
+There's a tab on the Job page called **Test**. Or you can click the "Test" button in the top right of the page.
+
+
+
+
+
+## Your options when Testing
+
+
+
+1. Select the environment you'd like the test to run against.
+2. Some Triggers provide example payloads that you can select from. This will populate the code editor below.
+3. When you're happy with the payload, click **Run test**.
+
+## Identifying test runs
+
+Tests have a label in the top-right of the Run page and a tick in the Test column of the Runs list.
+
+
diff --git a/docs/documentation/guides/tunneling-platform.mdx b/docs/documentation/guides/tunneling-platform.mdx
new file mode 100644
index 000000000..d8f04fa0d
--- /dev/null
+++ b/docs/documentation/guides/tunneling-platform.mdx
@@ -0,0 +1,41 @@
+---
+title: "Local platform"
+description: "Running the Trigger.dev platform locally requires tunneling to the internet."
+---
+
+Note this is only relevant to you if you are [running the platform locally](/documentation/guides/self-hosting).
+
+## How do I do it?
+
+There are a few ways to do this, but we recommend using [ngrok](https://ngrok.com/). It's free and easy to use.
+
+### Start ngrok
+
+1. Install ngrok:
+
+
+```sh Mac
+brew install ngrok/ngrok/ngrok
+```
+
+```sh Windows
+choco install ngrok
+```
+
+
+
+2. Open a new terminal window/tab, you need to leave this running
+
+3. Create an http tunnel at port 3030:
+
+```sh
+ngrok http 3030
+```
+
+4. Grab your forwarding address in the ngrok output:
+
+
+
+### 2. Use the forwarding URL
+
+Use the forwarding URL that ngrok gave you for the `LOGIN_ORIGIN` and `API_ORIGIN` environment variables for the docker container.
diff --git a/docs/documentation/guides/using-integrations-apikeys.mdx b/docs/documentation/guides/using-integrations-apikeys.mdx
new file mode 100644
index 000000000..53a130c85
--- /dev/null
+++ b/docs/documentation/guides/using-integrations-apikeys.mdx
@@ -0,0 +1,96 @@
+---
+title: "API Keys and Personal Access Tokens"
+description: "Lots of APIs use API Keys or Personal Access Tokens to authenticate. This guide will show you how to use them."
+---
+
+## 1. Create an Integration client
+
+```ts
+//1. Import the Integration packages you want to use
+import { Github } from "@trigger.dev/github";
+import { OpenAI } from "@trigger.dev/openai";
+
+//2. Create a new instance of the Integration client
+// GitHub uses personal access tokens so the param is called `token`
+const github = new Github({
+ //this is used to identify the connection
+ id: "github",
+ token: process.env.GITHUB_TOKEN!,
+});
+
+// OpenAI uses API keys so the param is called `apiKey`
+const openai = new OpenAI({
+ //this is used to identify the connection
+ id: "openai",
+ apiKey: process.env.OPENAI_API_KEY!,
+});
+```
+
+Note that we used `process.env.GITHUB_TOKEN` and `process.env.OPENAI_API_KEY`. They're environment variables, which are a way of not putting secret values directly in your code.
+
+For Next.js, local environment variables usually live in a `.env.local` file in the root of the project.
+
+```bash .env.local
+#...other variables above here
+GITHUB_TOKEN="github_pat_1234567890xxxxxxxxxxxxxxxxxxxx"
+OPENAI_API_KEY="sk-12345678xxxxxxxxxxxxxxxxxxxxxxxx"
+```
+
+## 2. Use the Integration client
+
+There are two way to use Integrations in a Job:
+
+- You can perform Tasks in the `run` function, by passing the Integration client into the `integrations` object.
+- You can use webhooks to Trigger a Job.
+
+This example automatically assigns "matt-aitken" to any new issue in the `trigger.dev` repo (lucky him).
+
+```ts
+new Job(client, {
+ id: "assign-on-issue-opened",
+ name: "Assign on Issue Opened",
+ version: "0.1.0",
+ //1. If you want to use the Integration in the run function, add it here
+ integrations: { github },
+ //2. If the Integration supports webhooks, you can use them here
+ trigger: github.triggers.repo({
+ event: events.onIssueOpened,
+ owner: "triggerdotdev",
+ repo: "trigger.dev",
+ }),
+ run: async (payload, io, ctx) => {
+ //3. Because we add `github` to Integrations, it comes through to `io.github` here
+ const assignee = await io.github.addIssueAssignees("add assignee", {
+ owner: payload.repository.owner.login,
+ repo: payload.repository.name,
+ issueNumber: payload.issue.number,
+ assignees: ["matt-aitken"],
+ });
+
+ return assignee;
+ },
+});
+```
+
+## 3. Viewing connections in the dashboard
+
+### The Integrations page
+
+
+
+### Connected API Key Integration detail page
+
+
+
+Some useful things on this page
+
+1. The `id` that you gave the connection when you defined it in your code
+2. The Jobs that are using this connection
+
+## References
+
+
+
+ Trigger.dev integrates with a wide range of services.
+
+
diff --git a/docs/documentation/guides/using-integrations-oauth.mdx b/docs/documentation/guides/using-integrations-oauth.mdx
new file mode 100644
index 000000000..497a283ff
--- /dev/null
+++ b/docs/documentation/guides/using-integrations-oauth.mdx
@@ -0,0 +1,101 @@
+---
+title: "OAuth"
+description: "Use OAuth to authenticate your team or to add Integrations to your product so your users can connect their accounts."
+---
+
+## 1. Create an Integration client (in code)
+
+```ts
+//1. Import the Integration packages you want to use
+import { Slack } from "@trigger.dev/slack";
+import { Github } from "@trigger.dev/github";
+
+//2. Create a new instance of the Integration client
+const slack = new Slack({
+ //this is used to identify the connection
+ id: "slack",
+});
+
+//GitHub supports OAuth (as well as Personal Access Tokens)
+const github = new Github({
+ //this is used to identify the connection
+ id: "github",
+});
+```
+
+When using OAuth, you only need to specify the `id`.
+
+## 2. Use the Integration client
+
+There are two way to use Integrations in a Job:
+
+- You can perform Tasks in the `run` function, by passing the Integration client into the `integrations` object.
+- You can use webhooks to Trigger a Job.
+
+This example send a Slack message when someone stars the `trigger.dev` GitHub repo 🤩.
+
+```ts
+new Job(client, {
+ id: "star-slack-notification",
+ name: "New Star Slack Notification",
+ version: "0.1.0",
+ //1. If you want to use the Integration in the run function, add it here
+ integrations: { slack },
+ //2. If the Integration supports webhooks, you can use them here
+ trigger: github.triggers.repo({
+ event: events.onNewStar,
+ owner: "triggerdotdev",
+ repo: "empty",
+ }),
+ run: async (payload, io, ctx) => {
+ //3. Because we add `slack` to Integrations, it comes through to `io.slack` here
+ const response = await io.slack.postMessage("Slack star", {
+ text: `${payload.sender.login} starred ${payload.repository.full_name}.\nTotal: ${payload.repository.stargazers_count}⭐️`,
+ channel: "C04GWUTDC3W",
+ });
+ },
+});
+```
+
+## 3. Creating the OAuth connection in the dashboard
+
+Now you need to setup the OAuth client in the dashboard. You will use the `id` that you specified in your code to associate them.
+
+1. Go to the "Integrations page" in your dashboard. Click the Integration you want to setup.
+ 
+
+2. Select OAuth as the authentication type.
+ 
+
+3. Select "Developer" as the user type.
+ 
+
+4. Enter the `id` that you specified in your code. Select the scopes that you want and enter a unique title.
+ 
+
+5. Click the Connect button, it will take you through the OAuth flow.
+
+## 4. Viewing your connection clients
+
+### The Integrations page
+
+
+
+### Connected OAuth integration detail page
+
+
+
+Some useful things on this page
+
+1. The `id` that you gave the connection when you defined it in your code
+2. The Jobs that are using this connection
+3. All the connections associated with this Integration client (there will be more than one if you're authenticated your users)
+4. The scopes that this connection has access to
+
+## References
+
+
+
+ Trigger.dev integrates with a wide range of services.
+
+
diff --git a/docs/documentation/guides/using-integrations.mdx b/docs/documentation/guides/using-integrations.mdx
new file mode 100644
index 000000000..b8af49a61
--- /dev/null
+++ b/docs/documentation/guides/using-integrations.mdx
@@ -0,0 +1,167 @@
+---
+title: "Using Integrations"
+description: "How to use Integrations"
+---
+
+
+ You can use any API in your Jobs by using existing Node.js SDKs or HTTP
+ requests. Integrations just make it much easier especially when you want to
+ use OAuth. And you get great logging.
+
+
+[Integrations](/documentation/concepts/integrations) allow you to quickly use APIs, including webhooks and Tasks.
+
+## Authentication
+
+There are two ways to authenticate Integrations, OAuth and API Keys/Access Tokens.
+
+
+
+ Use API Keys or Access Tokens to connect an Integration
+
+
+
+
+ }
+ href="/documentation/guides/using-integrations-oauth"
+ >
+ Use OAuth to connect an Integration for your team or your users
+
+
+
+## Using for Jobs & Tasks
+
+You must pass Integrations into your Job to run integration tasks. Passed in Integrations will be available on the `io` object in the `run()` function with the same name as the key. For example:
+
+
+
+Both the `postMessage` and `addIssueLabels` functions above are implemented as an "Authenticated Task" that is defined inside the Integration, where the first argument is always the task [key](/documentation/concepts/tasks#task-keys) and the second argument is the parameters for the task. For example, here is how you would call the `postMessage` function above:
+
+```ts
+client.defineJob({
+ // ...
+ integrations: {
+ slack,
+ },
+ run: async (payload, io, ctx) => {
+ const response = await io.slack.postMessage("✋", {
+ channel: "C04GWUTDC3W",
+ text: "My first Slack message",
+ });
+ },
+});
+```
+
+The above code will create a [Task](/documentation/concepts/tasks) that will use the authentication configured for the specified Slack integration.
+
+If the integration does not support a specific task function that you want to use, you can use the `runTask` function to get access to the authenticated client.
+
+For example, the Slack integration doesn't expose an Authenticated Task function for deleting a message, but you can use the `chat.delete` function provided by the [@slack/web-api package](https://slack.dev/node-slack-sdk/web-api) directly:
+
+```ts
+client.defineJob({
+ // ...
+ integrations: {
+ slack,
+ },
+ run: async (payload, io, ctx) => {
+ const response = await io.slack.postMessage("✋", {
+ channel: "C04GWUTDC3W",
+ text: "My first Slack message",
+ });
+
+ await io.wait("⏰", 24 * 60 * 60 * 1000); // wait 24 hours
+
+ await io.slack.runTask("delete", async (slack) => {
+ return slack.chat.delete({
+ channel: "C04GWUTDC3W",
+ ts: response.ts!,
+ });
+ });
+ },
+});
+```
+
+You can optionally pass a third parameter to `runTask` to specify the task parameters:
+
+```ts
+await io.slack.runTask(
+ "delete",
+ async (slack) => {
+ return slack.chat.delete({
+ channel: "C04GWUTDC3W",
+ ts: response.ts!,
+ });
+ },
+ {
+ name: "Delete message",
+ properties: [{ label: "Message", text: response.ts }],
+ }
+);
+```
+
+View the [runTask](/sdk/io/runtask#parameters) reference for more information.
+
+## Using outside of Jobs
+
+If you want to use integrations that support "local auth" only (e.g. API keys, like Stripe and Supabase) outside of a Job you can use the `.native` property on the integration to get direct access to the client. For example:
+
+```ts stripe.ts
+import { Stripe } from "@trigger.dev/stripe";
+
+const stripe = new Stripe({
+ id: "stripe",
+ apiKey: process.env.STRIPE_SECRET_KEY!
+});
+
+async function createCustomer() {
+ await stripe.native.customers.create({
+ // ... customer attributes go here
+ });
+}
+```
+
+## Using for Triggers
+
+Some integrations provide triggers that you can use to start a Job. For example, the GitHub integration provides a `push` trigger that will start a Job when a new commit is pushed to a repository:
+
+```ts
+import { Github, events } from "@trigger.dev/github";
+
+const github = new Github({
+ id: "github",
+ token: process.env.GITHUB_TOKEN!,
+});
+
+client.defineJob({
+ id: "github-integration-on-push",
+ name: "GitHub Integration - On Push",
+ version: "0.1.0",
+ trigger: github.triggers.repo({
+ event: events.onPush,
+ owner: "triggerdotdev",
+ repo: "trigger.dev",
+ }),
+ run: async (payload, io, ctx) => {
+ // do something on push
+ },
+});
+```
+
+Behind the scenes, our `@trigger.dev/github` integration will create a webhook on your repository that will call our API when a new push event is received. We will then start your Job with the payload from the push event.
+
+
+ If you are just using an integration to trigger a job but not using
+ authenticated tasks inside the job run, there is no need to pass the
+ integration in the job `integrations` option.
+
diff --git a/docs/documentation/guides/video-walkthrough.mdx b/docs/documentation/guides/video-walkthrough.mdx
new file mode 100644
index 000000000..b9817e123
--- /dev/null
+++ b/docs/documentation/guides/video-walkthrough.mdx
@@ -0,0 +1,28 @@
+---
+title: "Video walkthrough"
+description: "Go from zero to a working Job in your Next.js app in 10 minutes."
+---
+
+The Job subscribes to new GitHub issues and if the issues haven't been dealt with after 24 hours a Slack reminder is sent and they're assigned to someone.
+
+You can view the [source code here](https://github.com/triggerdotdev/examples/tree/main/github-issue-reminder).
+
+
+
+We cover how to:
+
+- get around serverless timeouts using Trigger.dev.
+- use the CLI to get setup.
+- run the Job locally.
+- create a GitHub onIssueOpened Trigger.
+- test the Job.
+- use Integrations inside the Job, including using API Keys (GitHub) and OAuth (Slack).
+- write the main logic of the Job.
+- use rerun to quickly iterate.
diff --git a/docs/documentation/guides/viewing-runs.mdx b/docs/documentation/guides/viewing-runs.mdx
new file mode 100644
index 000000000..3f47675a0
--- /dev/null
+++ b/docs/documentation/guides/viewing-runs.mdx
@@ -0,0 +1,20 @@
+---
+title: "Viewing Runs"
+description: "See every Task in every Run so you can tell exactly what happened."
+---
+
+## The Runs list
+
+The main page for a Job is a paginated table of Runs. The newest Runs are at the top.
+
+
+
+Filtering Runs is coming soon
+
+## Run page
+
+
+
+You can view the details of the Trigger, all the Tasks and the return value of the Run by clicking the elements in the timeline of the left hand side.
+
+Some Tasks have subtasks which are collapsed by default but can be opened by clicking them.
diff --git a/docs/documentation/guides/zod.mdx b/docs/documentation/guides/zod.mdx
new file mode 100644
index 000000000..0fb580879
--- /dev/null
+++ b/docs/documentation/guides/zod.mdx
@@ -0,0 +1,308 @@
+---
+title: "Zod Guide"
+sidebarTitle: "Zod"
+description: "TypeScript-first schema validation with static type inference"
+---
+
+## Intro
+
+Zod is a fantastic utility package by [@colinhacks](https://twitter.com/colinhacks) that allows for defining runtime schema validation and type-safety.
+
+We use it [extensively](https://github.com/search?q=repo%3Atriggerdotdev%2Ftrigger.dev+%22zod%22%3B&type=code) internally at Trigger.dev.
+
+But there are a few places where we ask you to provide us with a Zod schema, for example when defining your own [events](/documentation/concepts/triggers/events):
+
+```ts
+new Job(client, {
+ id: "new-user",
+ name: "New user",
+ version: "0.1.0",
+ //the eventTrigger uses zod to define the schema
+ trigger: eventTrigger({
+ name: "user.created",
+ schema: z.object({
+ name: z.string(),
+ email: z.string(),
+ paidPlan: z.boolean(),
+ }),
+ }),
+ //this function is run when the custom event is received
+ run: async (payload, io, ctx) => {
+ //do stuff
+ },
+});
+```
+
+So it will help to know a little about Zod and how to use it. We definitely recommend the well written [Zod README](https://github.com/colinhacks/zod#readme) but we've included a short primer below.
+
+
+ Wherever we require you to pass in a Zod schema, you can always start with
+ `z.any()` which accepts `any` type and then add more strict validations later.
+
+
+## Basic Usage
+
+There are three main steps to using Zod:
+
+1. Define a schema
+
+```ts
+import { z } from "zod";
+
+const mySchema = z.object({
+ name: z.string(),
+ email: z.string(),
+ paidPlan: z.boolean(),
+});
+```
+
+2. Infer TypeScript types from the schema
+
+```ts
+type MySchema = z.infer;
+```
+
+3. Validate data against the schema
+
+```ts
+const data: unknown = {
+ name: "Eric",
+ email: "eric@trigger.dev",
+ paidPlan: true,
+};
+
+const result = mySchema.parse(data);
+```
+
+When using Zod with Trigger.dev, you'll only really need to do the first step, and by passing it to us (through the `schema` property of the `customEvent` function), we'll do the second and third steps for you.
+
+## Defining Schemas
+
+### Primitives
+
+Zod schemas are a way to define the shape of an object. They can be as simple as a single type, or as complex as a nested object.
+
+```ts
+// Primitives
+z.string();
+z.number();
+z.boolean();
+z.date();
+z.undefined();
+z.null();
+```
+
+Any schema can be marked as optional, which means the schema can be `undefined` or `null`:
+
+```ts
+z.string().optional();
+```
+
+Schemas can also be marked optional by providing a default value:
+
+```ts
+const optionalString = z.string().default("default value");
+
+const value = optionalString.parse(undefined); // value === "default value"
+```
+
+If you need to allow a value to be `null`, you can use `nullable()`:
+
+```ts
+const nullableString = z.string().nullable();
+
+const value = nullableString.parse(null);
+```
+
+You can also use Zod to coerce primites into other types. For example, you can coerce a string into a number:
+
+```ts
+const numberString = z.coerce.number();
+
+const value = numberString.parse("123"); // value === 123
+```
+
+The following primitives are supported:
+
+```ts
+z.coerce.string();
+z.coerce.number();
+z.coerce.boolean();
+z.coerce.bigint();
+z.coerce.date();
+```
+
+Coercing dates are especially useful when you are receiving a `string` from an API and want to convert it to a JavaScript `Date` object:
+
+```ts
+const date = z.coerce.date();
+
+const value = date.parse("2021-01-01T00:00:00.000Z"); // value === Date object
+```
+
+### Objects
+
+Object schemas are the most common type of schema. They allow you to define the shape of an object, and the types of each property.
+
+```ts
+const mySchema = z.object({
+ name: z.string(),
+ email: z.string(),
+ paidPlan: z.boolean(),
+});
+```
+
+All properties are required by default, although you can make them all optional using `partial()`:
+
+```ts
+const mySchema = z
+ .object({
+ name: z.string(),
+ email: z.string(),
+ paidPlan: z.boolean(),
+ })
+ .partial();
+```
+
+You can also make individual properties optional:
+
+```ts
+const mySchema = z.object({
+ name: z.string(),
+ email: z.string(),
+ paidPlan: z.boolean().optional(),
+});
+```
+
+By default an object schema will strip out any extra properties that are not defined in the schema. You can disable this behavior using `passthrough()`:
+
+```ts
+const mySchema = z.object({
+ name: z.string(),
+});
+
+mySchema.parse({ name: "Eric", email: "eric@trigger.dev" }); // { name: "Eric" }
+mySchema.passthrough().parse({ name: "Eric", email: "eric@trigger.dev" }); // { name: "Eric", email: "eric@trigger.dev" }
+```
+
+Or you can use `strict()` to make the schema throw an error if there are any extra properties:
+
+```ts
+const mySchema = z
+ .object({
+ name: z.string(),
+ })
+ .strict();
+
+mySchema.parse({ name: "Eric", email: "eric@trigger.dev" }); // throws error
+```
+
+Zod includes a few useful object schema utilities to help with reusing schemas, `extends()` and `merge()`:
+
+```ts
+const baseSchema = z.object({
+ name: z.string(),
+});
+
+const extendedSchema = baseSchema.extend({
+ email: z.string(),
+});
+
+const mergedSchema = baseSchema.merge(
+ z.object({
+ email: z.string(),
+ })
+);
+```
+
+You can also use `pick()` and `omit()` to create a new schema that only includes or excludes certain properties:
+
+```ts
+const mySchema = z.object({
+ name: z.string(),
+ email: z.string(),
+ paidPlan: z.boolean(),
+});
+
+const pickedSchema = mySchema.pick({ name: true, email: true });
+const omittedSchema = mySchema.omit({ paidPlan: true });
+```
+
+### Arrays
+
+You can specify the schema of an array using `z.array()`:
+
+```ts
+z.array(z.string()); // string[]
+z.array(z.number()); // number[]
+z.array(z.object({ name: z.string() })); // Array<{ name: string }>
+```
+
+You can also specify the type of array that has a fixed number of elements using `z.tuple()`:
+
+```ts
+z.tuple([z.string(), z.number(), z.boolean()]); // [string, number, boolean]
+```
+
+### Unions
+
+You can specify a union of schemas using `z.union()`:
+
+```ts
+z.union([z.string(), z.number(), z.boolean()]); // string | number | boolean
+```
+
+Discriminating unions are also supported, and especially useful when paired with type narrowing:
+
+```ts
+const mySchema = z.discriminatingUnion("type", [
+ z.object({
+ type: z.literal("a"),
+ data: z.string(),
+ }),
+ z.object({
+ type: z.literal("b"),
+ data: z.number(),
+ }),
+]);
+
+const value = mySchema.parse({ type: "a", data: "hello" });
+
+if (type.a) {
+ // value is { type: "a", data: string }
+} else if (type.b) {
+ // value is { type: "b", data: number }
+}
+```
+
+### Records
+
+You can specify a record of schemas using `z.record()`, useful for when you have a map of values but don't care about the keys:
+
+```ts
+z.record(z.string()); // Record
+z.record(z.number()); // Record
+```
+
+### JSON type
+
+If you want to accept any valid JSON value, you can use the following schema:
+
+```ts
+const literalSchema = z.union([z.string(), z.number(), z.boolean(), z.null()]);
+type Literal = z.infer;
+type Json = Literal | { [key: string]: Json } | Json[];
+const jsonSchema: z.ZodType = z.lazy(() =>
+ z.union([literalSchema, z.array(jsonSchema), z.record(jsonSchema)])
+);
+
+jsonSchema.parse(data);
+```
+
+Hat tip to [ggoodman](https://github.com/ggoodman) for this one.
+
+## Resources
+
+Matt Pocock [@mattpocock](https://twitter.com/mattpocockuk) has a great free Zod Tutorial up on [Total Typescript](https://www.totaltypescript.com/tutorials/zod) that covers the basics of Zod.
+
+Easily generate Zod schemas from [JSON](https://transform.tools/json-to-zod), [JSON Schemas](https://transform.tools/json-schema-to-zod), or [TypeScript](https://transform.tools/typescript-to-zod) types.
diff --git a/docs/documentation/introduction.mdx b/docs/documentation/introduction.mdx
new file mode 100644
index 000000000..ba6b20581
--- /dev/null
+++ b/docs/documentation/introduction.mdx
@@ -0,0 +1,81 @@
+---
+title: Introduction
+description: "Welcome to the Trigger.dev documentation."
+---
+
+Trigger.dev is an open source framework for creating long-running Jobs directly in your Next.js app with API Integrations, webhooks, scheduling and delays. You can reliably run Jobs that wouldn't normally work in serverless environments (like Vercel) because of timeouts.
+
+You can use [Trigger.dev Cloud](https://cloud.trigger.dev) or [Self-host Trigger.dev](/documentation/guides/self-hosting) on your own infrastructure.
+
+
+ Trigger.dev v2 currently only supports serverless. During our beta we will add
+ [support for long-running
+ servers](https://github.com/triggerdotdev/trigger.dev/issues/244).
+
+
+
+
+ Get started in 5 minutes.
+
+
+ Go from zero to a working Job in your Next.js app in 10 minutes.
+
+
+ Learn more about how Trigger.dev works and how it can help you.
+
+
+ Trigger.dev integrates with a wide range of services.
+
+
+ One of the quickest ways to learn how Trigger.dev works is to view some
+ example Jobs.
+
+
+
+## Getting help
+
+We'd love to hear from you or give you a hand getting started. Here are some ways to get in touch with us. We'd also ❤️ your support.
+
+
+
+ The #help-and-questions channel is a great place to get help with any
+ questions about Trigger.dev.
+
+
+ Follow us on Twitter to get the latest updates and news.
+
+
+ Arrange a call with one of the founders. We can help answer questions, build
+ API Integrations for you and give 1-on-1 help building your first Job.
+
+
+ Check us out at triggerdotdev/trigger.dev
+
+
diff --git a/docs/documentation/quickstart.mdx b/docs/documentation/quickstart.mdx
new file mode 100644
index 000000000..bd583c97b
--- /dev/null
+++ b/docs/documentation/quickstart.mdx
@@ -0,0 +1,236 @@
+---
+title: "Quick Start"
+description: "Start creating Jobs in 5 minutes"
+---
+
+This quick start guide will get you up and running with Trigger.dev.
+
+
+Create a blank project by running the `create-next-app` command in your terminal:
+
+```bash
+npx create-next-app@latest
+```
+
+Trigger.dev works with either the Pages or App Router configuration.
+
+
+
+## Create a Trigger.dev account
+
+You can either
+
+- Use the [Trigger.dev Cloud](https://cloud.trigger.dev) (we're currently in private beta).
+- Or [self-host](/documentation/guides/self-hosting) the service.
+
+### Create your first project
+
+Once you've created an account, follow the steps to:
+
+1. Complete your account details.
+2. Create your first Organization and Project.
+
+### Getting an API key
+
+1. Go to the "Environments & API Keys" page in your project.
+ 
+
+2. Copy the `DEV` API key.
+ 
+
+## Run the CLI `init` command
+
+The easiest way to get started it to use the CLI. It will add Trigger.dev to your existing Next.js project, setup a route and give you an example file.
+
+In a terminal window run:
+
+
+
+```bash npm
+npx @trigger.dev/cli@latest init
+```
+
+```bash pnpm
+pnpm dlx @trigger.dev/cli@latest init
+```
+
+```bash yarn
+yarn dlx @trigger.dev/cli@latest init
+```
+
+
+
+It will ask you a few questions
+
+1. Are you using the [Trigger.dev Cloud](https://trigger.dev) or [self-hosting](/documentation/guides/self-hosting)? You're probably using the cloud.
+2. Enter your development API key. Enter the key you copied earlier.
+3. Enter a unique ID for your endpoint (you can just use the default by hitting enter)
+
+## Run your Next.js site
+
+Make sure your Next.js site is running locally, we will connect to it to register your Jobs.
+
+You must leave this running for the rest of the steps.
+
+
+
+```bash npm
+npm run dev
+```
+
+```bash pnpm
+pnpm run dev
+```
+
+```bash yarn
+yarn run dev
+```
+
+
+
+## Run the CLI `dev` command
+
+The CLI `dev` command allows the Trigger.dev service to send messages to your Next.js site. This is required for registering Jobs, triggering them and running tasks. To achieve this it creates a tunnel (using [ngrok](https://ngrok.com/)) so Trigger.dev can send messages to your machine.
+
+You should leave the `dev` command running when you're developing.
+
+In a **new terminal window or tab** run:
+
+
+
+```bash npm
+npx @trigger.dev/cli@latest dev
+```
+
+```bash pnpm
+pnpm dlx @trigger.dev/cli@latest dev
+```
+
+```bash yarn
+yarn dlx @trigger.dev/cli@latest dev
+```
+
+
+
+
+ You can optionally pass the port if you're not running on 3000 by adding
+ `--port 3001` to the end
+
+
+
+
+Instructions of how to resolve any issues due to middleware [here](https://trigger.dev/docs/documentation/guides/platforms/nextjs#middleware)
+
+
+
+You can modify your `package.json` to run both the Next.js server and the CLI `dev` command together.
+
+1. Install the `concurrently` package:
+
+
+
+```bash npm
+npm install concurrently --save-dev
+```
+
+```bash pnpm
+pnpm install concurrently --save-dev
+```
+
+```bash yarn
+yarn add concurrently --dev
+```
+
+
+
+2. Modify your `package.json` file's `dev` script.
+
+```json package.json
+...
+"scripts": {
+ "dev": "concurrently --kill-others npm:dev:*",
+ "dev:next": "next dev",
+ "dev:trigger": "npx @trigger.dev/cli dev",
+ ...
+}
+...
+```
+
+
+
+
+## Your first job
+
+The CLI init command created a simple Job for you. There will be a new file either `api/trigger/route.ts` or `pages/api/trigger.ts`.
+
+In there is this Job:
+
+```typescript
+//Job definition – uses the client
+new Job(client, {
+ // 1. Metadata
+ id: "example-job",
+ name: "Example Job",
+ version: "0.0.1",
+ // 2. Trigger
+ trigger: eventTrigger({
+ name: "example.event",
+ }),
+ // 3. Run function
+ run: async (payload, io, ctx) => {
+ // do something
+ await io.logger.info("Hello world!", { payload });
+
+ return {
+ message: "Hello world!",
+ };
+ },
+});
+```
+
+If you navigate to your Trigger.dev project you will see this Job in the "Jobs" section:
+
+
+
+## Triggering the Job
+
+There are two way to trigger this Job.
+
+1. Use the "Test" functionality in the dashboard.
+2. Use the Trigger.dev API (either via our SDK or a web request)
+
+### "Testing" from the dashboard
+
+Click into the Job and then open the "Test" tab. You should see this page:
+
+
+
+This Job doesn't have a payload schema (meaning it takes an empty object), so you can simple click the "Run test" button.
+
+Congratulations, you should get redirected so you can see your first Run!
+
+## What's next?
+
+
+
+ A Guide for how to create your first real Job
+
+
+ Learn more about how Trigger.dev works and how it can help you.
+
+
+ One of the quickest ways to learn how Trigger.dev works is to view some
+ example Jobs.
+
+
+ Struggling getting setup or have a question? We're here to help.
+
+
diff --git a/docs/documentation/roadmap.mdx b/docs/documentation/roadmap.mdx
new file mode 100644
index 000000000..b9ea1a8b6
--- /dev/null
+++ b/docs/documentation/roadmap.mdx
@@ -0,0 +1,15 @@
+---
+title: "Roadmap"
+description: "Coming changes to Trigger.dev"
+---
+
+## Next up
+
+Features and Integrations we'll be working on next.
+
+#### Features
+
+- Trigger.dev Connect: authenticate your users so you can quickly add Integrations to your app.
+- Vercel Integration
+- Error alerts: get notified when your Jobs fail or don't start.
+- Filtering Runs (e.g. by status)
diff --git a/docs/examples/examples-repository.mdx b/docs/examples/examples-repository.mdx
new file mode 100644
index 000000000..4f3d03721
--- /dev/null
+++ b/docs/examples/examples-repository.mdx
@@ -0,0 +1,17 @@
+---
+title: Examples Repository
+description: "Pre-built Next.js projects with Jobs."
+---
+
+We have an [examples GitHub repo](https://github.com/triggerdotdev/examples) that we add to all the time. It's a great place to start if you're looking for inspiration.
+
+Instructions on how to run each of the below projects are included in their respective READMEs (linked below).
+
+| Name | Description | Integrations |
+| -------------------------------------------------------------------------- | ------------------------------------------------------------- | ----------------------------------- |
+| [Delays](https://github.com/triggerdotdev/examples/tree/main/delays) | A Next.js project containing Jobs using delays | N/A |
+| [Scheduled](https://github.com/triggerdotdev/examples/tree/main/scheduled) | A Next.js project containing interval and cron scheduled Jobs | N/A |
+| [GitHub](https://github.com/triggerdotdev/examples/tree/main/github) | A Next.js project containing GitHub Jobs | [GitHub](/integrations/apis/github) |
+| [OpenAI](https://github.com/triggerdotdev/examples/tree/main/openai) | A Next.js project containing OpenAI Jobs | [OpenAI](/integrations/apis/openai) |
+| [Resend](https://github.com/triggerdotdev/examples/tree/main/resend) | A Next.js project containing Resend Jobs | [Resend](/integrations/apis/resend) |
+| [Slack](https://github.com/triggerdotdev/examples/tree/main/slack) | A Next.js project containing Slack Jobs | [Slack](integrations/apis/slack) |
diff --git a/docs/examples/introduction.mdx b/docs/examples/introduction.mdx
new file mode 100644
index 000000000..5659faaff
--- /dev/null
+++ b/docs/examples/introduction.mdx
@@ -0,0 +1,25 @@
+---
+title: Example Jobs
+description: "An ever-growing list of example Jobs which you can use to get started with Trigger.dev."
+---
+
+
+ If you are using integrations, you'll need set up authentication either using
+ OAuth or API keys / access tokens. You can find out how to do that in the
+ [integrations section](/integrations).
+
+
+| Job (code in link) | Description | Integrations used |
+| ----------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
+| [Basic delay](https://github.com/triggerdotdev/examples/blob/main/delays/src/jobs/delayJob.ts) | Logs a message to the console, waits for 5 minutes, and then logs another message. | N/A |
+| [Basic interval](https://github.com/triggerdotdev/examples/blob/main/scheduled/src/jobs/interval.ts) | This Job will run every 60 seconds, starting 60 seconds after this Job is first indexed. | N/A |
+| [Cron scheduled interval](https://github.com/triggerdotdev/examples/blob/main/scheduled/src/jobs/cronScheduled.ts) | A scheduled Job which runs at 2:30pm every Monday. | N/A |
+| [Tell me a joke using OpenAI](https://github.com/triggerdotdev/examples/blob/main/openai/src/jobs/tellMeAJoke.ts) | Generates a random joke using OpenAI GPT 3.5. | [OpenAI](/integrations/apis/openai) |
+| [Generate an image using OpenAI](https://github.com/triggerdotdev/examples/blob/main/openai/src/jobs/generateHedgehogImages.ts) | Generates a random image of a hedgehog using OpenAI DALL-E. | [OpenAI](/integrations/apis/openai) |
+| [Add a custom label to a GitHub issue when it is created](https://github.com/triggerdotdev/examples/blob/main/github/src/jobs/onIssueOpened.ts) | When a new GitHub issue is opened it adds a "Bug" label to it. | [GitHub](/integrations/apis/github) |
+| [GitHub new star alert](https://github.com/triggerdotdev/examples/blob/main/github/src/jobs/newStarAlert.ts) | When a repo is starred a message is logged with the new Stargazers count. | [GitHub](/integrations/apis/github) |
+| [Github new star alert in Slack](https://github.com/triggerdotdev/examples/blob/main/github/src/jobs/newStarToSlack.ts) | When a repo is starred, a message is sent to a Slack channel with the name and URL of the GitHub user who starred the repo, and the updated Stargazers count. | [GitHub](/integrations/apis/github), [Slack](/integrations/apis/slack) |
+| [Send a Slack message when an event is received](https://github.com/triggerdotdev/examples/blob/main/slack/src/jobs/sendSlackMessage.ts) | Sends a Slack message to a specific channel when an event is received. | [Slack](/integrations/apis/slack) |
+| [Send an email using Resend](https://github.com/triggerdotdev/examples/blob/main/resend/src/jobs/resendBasicEmail.ts) | Send a basic email using Resend | [Resend](/integrations/apis/resend) |
+
+If you have any ideas for Jobs you would like to build, you can fill in the [Job request form](https://bcymafitv0e.typeform.com/to/YLUKy9my#source=example-jobs-docs).
diff --git a/docs/images/add-app-name-render.png b/docs/images/add-app-name-render.png
new file mode 100644
index 000000000..b282afd09
Binary files /dev/null and b/docs/images/add-app-name-render.png differ
diff --git a/docs/images/add-env-variables-render.png b/docs/images/add-env-variables-render.png
new file mode 100644
index 000000000..ad16319f1
Binary files /dev/null and b/docs/images/add-env-variables-render.png differ
diff --git a/docs/images/advanced-render.png b/docs/images/advanced-render.png
new file mode 100644
index 000000000..b95f76776
Binary files /dev/null and b/docs/images/advanced-render.png differ
diff --git a/docs/images/api-key.png b/docs/images/api-key.png
new file mode 100644
index 000000000..954c6819c
Binary files /dev/null and b/docs/images/api-key.png differ
diff --git a/docs/images/api-keys-prod.png b/docs/images/api-keys-prod.png
new file mode 100644
index 000000000..c5a99019b
Binary files /dev/null and b/docs/images/api-keys-prod.png differ
diff --git a/docs/images/api-keys.png b/docs/images/api-keys.png
new file mode 100644
index 000000000..3ea95a45f
Binary files /dev/null and b/docs/images/api-keys.png differ
diff --git a/docs/images/architecture.png b/docs/images/architecture.png
new file mode 100644
index 000000000..371f19d64
Binary files /dev/null and b/docs/images/architecture.png differ
diff --git a/docs/images/cli-dev.gif b/docs/images/cli-dev.gif
new file mode 100644
index 000000000..4fc2d7517
Binary files /dev/null and b/docs/images/cli-dev.gif differ
diff --git a/docs/images/cli-init.gif b/docs/images/cli-init.gif
new file mode 100644
index 000000000..e4c67b495
Binary files /dev/null and b/docs/images/cli-init.gif differ
diff --git a/docs/images/deploy-vercel-1.png b/docs/images/deploy-vercel-1.png
new file mode 100644
index 000000000..5497d4951
Binary files /dev/null and b/docs/images/deploy-vercel-1.png differ
diff --git a/docs/images/deploy-vercel-2.png b/docs/images/deploy-vercel-2.png
new file mode 100644
index 000000000..6ba0dafe7
Binary files /dev/null and b/docs/images/deploy-vercel-2.png differ
diff --git a/docs/images/deploy-vercel-3.png b/docs/images/deploy-vercel-3.png
new file mode 100644
index 000000000..6ca85cdb2
Binary files /dev/null and b/docs/images/deploy-vercel-3.png differ
diff --git a/docs/images/deploy-vercel-4.png b/docs/images/deploy-vercel-4.png
new file mode 100644
index 000000000..4b7dfa112
Binary files /dev/null and b/docs/images/deploy-vercel-4.png differ
diff --git a/docs/images/docs-background.png b/docs/images/docs-background.png
new file mode 100644
index 000000000..495c0e249
Binary files /dev/null and b/docs/images/docs-background.png differ
diff --git a/docs/images/endpoint-automatic-refresh.png b/docs/images/endpoint-automatic-refresh.png
new file mode 100644
index 000000000..afe12c84d
Binary files /dev/null and b/docs/images/endpoint-automatic-refresh.png differ
diff --git a/docs/images/endpoint-manual-refresh-1.png b/docs/images/endpoint-manual-refresh-1.png
new file mode 100644
index 000000000..c6da15a7e
Binary files /dev/null and b/docs/images/endpoint-manual-refresh-1.png differ
diff --git a/docs/images/endpoint-manual-refresh-2.png b/docs/images/endpoint-manual-refresh-2.png
new file mode 100644
index 000000000..bb0a211dd
Binary files /dev/null and b/docs/images/endpoint-manual-refresh-2.png differ
diff --git a/docs/images/endpoint-refresh.png b/docs/images/endpoint-refresh.png
new file mode 100644
index 000000000..e26df131d
Binary files /dev/null and b/docs/images/endpoint-refresh.png differ
diff --git a/docs/images/endpoint-setup-1.png b/docs/images/endpoint-setup-1.png
new file mode 100644
index 000000000..4d513a818
Binary files /dev/null and b/docs/images/endpoint-setup-1.png differ
diff --git a/docs/images/endpoint-setup-2.png b/docs/images/endpoint-setup-2.png
new file mode 100644
index 000000000..53cd28aa6
Binary files /dev/null and b/docs/images/endpoint-setup-2.png differ
diff --git a/docs/images/endpoint-setup-3.png b/docs/images/endpoint-setup-3.png
new file mode 100644
index 000000000..8a140798c
Binary files /dev/null and b/docs/images/endpoint-setup-3.png differ
diff --git a/docs/images/environments-click-dev.png b/docs/images/environments-click-dev.png
new file mode 100644
index 000000000..31c593029
Binary files /dev/null and b/docs/images/environments-click-dev.png differ
diff --git a/docs/images/environments-link.png b/docs/images/environments-link.png
new file mode 100644
index 000000000..0621b702d
Binary files /dev/null and b/docs/images/environments-link.png differ
diff --git a/docs/images/environments.png b/docs/images/environments.png
new file mode 100644
index 000000000..878155a65
Binary files /dev/null and b/docs/images/environments.png differ
diff --git a/docs/images/favicon.png b/docs/images/favicon.png
new file mode 100644
index 000000000..7540b1ea4
Binary files /dev/null and b/docs/images/favicon.png differ
diff --git a/docs/images/first-job.png b/docs/images/first-job.png
new file mode 100644
index 000000000..c42464e25
Binary files /dev/null and b/docs/images/first-job.png differ
diff --git a/docs/images/github-generate-new-secret.png b/docs/images/github-generate-new-secret.png
new file mode 100644
index 000000000..24c290727
Binary files /dev/null and b/docs/images/github-generate-new-secret.png differ
diff --git a/docs/images/github-oauth.png b/docs/images/github-oauth.png
new file mode 100644
index 000000000..d29421bd0
Binary files /dev/null and b/docs/images/github-oauth.png differ
diff --git a/docs/images/github-secrets.png b/docs/images/github-secrets.png
new file mode 100644
index 000000000..e7287ba2a
Binary files /dev/null and b/docs/images/github-secrets.png differ
diff --git a/docs/images/integration-api-key.png b/docs/images/integration-api-key.png
new file mode 100644
index 000000000..7b7cf8fbd
Binary files /dev/null and b/docs/images/integration-api-key.png differ
diff --git a/docs/images/integration-oauth.png b/docs/images/integration-oauth.png
new file mode 100644
index 000000000..5aebd4103
Binary files /dev/null and b/docs/images/integration-oauth.png differ
diff --git a/docs/images/integrations-click-github.png b/docs/images/integrations-click-github.png
new file mode 100644
index 000000000..eae60e8a4
Binary files /dev/null and b/docs/images/integrations-click-github.png differ
diff --git a/docs/images/integrations-list.png b/docs/images/integrations-list.png
new file mode 100644
index 000000000..164a71a64
Binary files /dev/null and b/docs/images/integrations-list.png differ
diff --git a/docs/images/job-concept.png b/docs/images/job-concept.png
new file mode 100644
index 000000000..2075d2684
Binary files /dev/null and b/docs/images/job-concept.png differ
diff --git a/docs/images/new-web-service-render.png b/docs/images/new-web-service-render.png
new file mode 100644
index 000000000..25cdd399a
Binary files /dev/null and b/docs/images/new-web-service-render.png differ
diff --git a/docs/images/ngrok.png b/docs/images/ngrok.png
new file mode 100644
index 000000000..61da8255b
Binary files /dev/null and b/docs/images/ngrok.png differ
diff --git a/docs/images/oauth-setup-1.png b/docs/images/oauth-setup-1.png
new file mode 100644
index 000000000..3106cf8a8
Binary files /dev/null and b/docs/images/oauth-setup-1.png differ
diff --git a/docs/images/oauth-setup-2.png b/docs/images/oauth-setup-2.png
new file mode 100644
index 000000000..1ca65eafd
Binary files /dev/null and b/docs/images/oauth-setup-2.png differ
diff --git a/docs/images/oauth-setup-3.png b/docs/images/oauth-setup-3.png
new file mode 100644
index 000000000..f113736ca
Binary files /dev/null and b/docs/images/oauth-setup-3.png differ
diff --git a/docs/images/project-blank.png b/docs/images/project-blank.png
new file mode 100644
index 000000000..bd5142a54
Binary files /dev/null and b/docs/images/project-blank.png differ
diff --git a/docs/images/project-jobs.png b/docs/images/project-jobs.png
new file mode 100644
index 000000000..ae6e5e577
Binary files /dev/null and b/docs/images/project-jobs.png differ
diff --git a/docs/images/rerun.png b/docs/images/rerun.png
new file mode 100644
index 000000000..9233796b0
Binary files /dev/null and b/docs/images/rerun.png differ
diff --git a/docs/images/run-page.png b/docs/images/run-page.png
new file mode 100644
index 000000000..80548e9de
Binary files /dev/null and b/docs/images/run-page.png differ
diff --git a/docs/images/runs-list.png b/docs/images/runs-list.png
new file mode 100644
index 000000000..dd36c445e
Binary files /dev/null and b/docs/images/runs-list.png differ
diff --git a/docs/images/test-annotated.png b/docs/images/test-annotated.png
new file mode 100644
index 000000000..a224e3fe4
Binary files /dev/null and b/docs/images/test-annotated.png differ
diff --git a/docs/images/test-click.png b/docs/images/test-click.png
new file mode 100644
index 000000000..ecea06e61
Binary files /dev/null and b/docs/images/test-click.png differ
diff --git a/docs/images/test-indicator.png b/docs/images/test-indicator.png
new file mode 100644
index 000000000..a87db42bf
Binary files /dev/null and b/docs/images/test-indicator.png differ
diff --git a/docs/images/test-job.png b/docs/images/test-job.png
new file mode 100644
index 000000000..c0785bd9d
Binary files /dev/null and b/docs/images/test-job.png differ
diff --git a/docs/images/typeform-form-id.png b/docs/images/typeform-form-id.png
new file mode 100644
index 000000000..f9aa4b949
Binary files /dev/null and b/docs/images/typeform-form-id.png differ
diff --git a/docs/integrations/apis/github-tasks.mdx b/docs/integrations/apis/github-tasks.mdx
new file mode 100644
index 000000000..b5850c591
--- /dev/null
+++ b/docs/integrations/apis/github-tasks.mdx
@@ -0,0 +1,54 @@
+---
+title: Tasks
+---
+
+## All tasks
+
+| Function Name | Description |
+| -------------------------------- | ----------------------------------------------------------- |
+| `createIssue` | Creates a new issue in a repository. |
+| `addIssueAssignees` | Adds assignees to an existing issue. |
+| `addIssueLabels` | Adds labels to an existing issue. |
+| `createIssueComment` | Creates a new comment on an existing issue. |
+| `getRepo` | Retrieves information about a repository. |
+| `createIssueCommentWithReaction` | Creates a new comment on an existing issue with a reaction. |
+| `addIssueCommentReaction` | Adds a reaction to an existing issue comment. |
+| `updateWebhook` | Updates an existing webhook. |
+| `createWebhook` | Creates a new webhook. |
+| `listWebhooks` | Lists the webhooks for a repository. |
+| `updateOrgWebhook` | Updates an existing webhook for an organization. |
+| `createOrgWebhook` | Creates a new webhook for an organization. |
+| `listOrgWebhooks` | Lists the webhooks for an organization. |
+
+## Usage
+
+```ts
+new Job(client, {
+ id: "github-integration-on-issue-opened",
+ name: "GitHub Integration - On Issue Opened",
+ version: "0.1.0",
+ integrations: { github },
+ trigger: github.triggers.repo({
+ event: events.onIssueOpened,
+ owner: "triggerdotdev",
+ repo: "empty",
+ }),
+ run: async (payload, io, ctx) => {
+ await io.github.addIssueAssignees("add assignee", {
+ owner: payload.repository.owner.login,
+ repo: payload.repository.name,
+ issueNumber: payload.issue.number,
+ assignees: ["matt-aitken"],
+ });
+
+ await io.github.addIssueLabels("add label", {
+ owner: payload.repository.owner.login,
+ repo: payload.repository.name,
+ issueNumber: payload.issue.number,
+ labels: ["bug"],
+ });
+
+ return { payload, ctx };
+ },
+});
+```
diff --git a/docs/integrations/apis/github-triggers.mdx b/docs/integrations/apis/github-triggers.mdx
new file mode 100644
index 000000000..84e78bab9
--- /dev/null
+++ b/docs/integrations/apis/github-triggers.mdx
@@ -0,0 +1,46 @@
+---
+title: Triggers
+---
+
+## All triggers
+
+| Function Name | Description |
+| --------------------- | -------------------------------------------------------------------------------- |
+| `onIssue` | When any action is performed on an issue. |
+| `onIssueOpened` | When an issue is opened. |
+| `onIssueAssigned` | When an issue is assigned. |
+| `onIssueComment` | When an issue is commented on. |
+| `onStar` | When a repo is starred or unstarred. |
+| `onNewStar` | When a repo is starred. |
+| `onNewRepository` | When a new repo is created. |
+| `onNewBranchOrTag` | When a new branch or tag is created. |
+| `onNewBranch` | When a new branch is created. |
+| `onPush` | When a push is made to a repo. |
+| `onPullRequest` | When activity occurs on a pull request (excluding reviews, issues, or comments). |
+| `onPullRequestReview` | When a pull request review has activity. |
+
+## Usage
+
+```ts
+import { Github, events } from "@trigger.dev/github";
+
+const github = new Github({
+ id: "github",
+ token: process.env.GITHUB_TOKEN!,
+});
+
+new Job(client, {
+ id: "github-integration-on-issue",
+ name: "GitHub Integration - On Issue",
+ version: "0.1.0",
+ trigger: github.triggers.repo({
+ event: events.onIssue,
+ owner: "triggerdotdev",
+ repo: "empty",
+ }),
+ run: async (payload, io, ctx) => {
+ await io.logger.info("This is a simple log info message");
+ //do stuff
+ },
+});
+```
diff --git a/docs/integrations/apis/github.mdx b/docs/integrations/apis/github.mdx
new file mode 100644
index 000000000..a8288dff4
--- /dev/null
+++ b/docs/integrations/apis/github.mdx
@@ -0,0 +1,103 @@
+---
+title: Introduction
+---
+
+
+
+## Installation
+
+
+
+```bash npm
+npm install @trigger.dev/github@latest
+```
+
+```bash pnpm
+pnpm install @trigger.dev/github@latest
+```
+
+```bash yarn
+yarn add @trigger.dev/github@latest
+```
+
+
+
+## Authentication
+
+GitHub supports Personal Access Tokens and OAuth.
+
+```ts
+import { Github } from "@trigger.dev/github";
+
+//create GitHub client using a token
+const github = new Github({
+ id: "github",
+ token: process.env.GITHUB_TOKEN!,
+});
+
+//create GitHub client using OAuth
+const github2 = new Github({
+ id: "github2",
+});
+```
+
+## Triggers and Tasks
+
+
+
+ Trigger Jobs when events happen in GitHub, such as a new commit or a new
+ issue.
+
+
+ Perform tasks such as creating a new issue or a new comment.
+
+
+
+## Using the underlying client
+
+You can use the underlying client to do anything Octokit supports. In this example we create a project card when a new issue is opened..
+
+
+ View [the official GitHub docs](https://docs.github.com/en/rest) for
+ everything that is supported{" "}
+
+
+```ts
+import { Github, events } from "@trigger.dev/github";
+
+const github = new Github({
+ id: "github",
+ token: process.env.GITHUB_TOKEN!,
+});
+
+new Job(client, {
+ id: "alert-on-new-github-issues",
+ name: "Alert on new GitHub issues",
+ version: "0.1.1",
+ trigger: github.triggers.repo({
+ event: events.onIssueOpened,
+ owner: "triggerdotdev",
+ repo: "trigger.dev",
+ }),
+ integrations: {
+ github,
+ },
+ run: async (payload, io, ctx) => {
+ //wrap the SDK call in runTask
+ const { data } = await io.runTask(
+ "create-card",
+ { name: "Create card" },
+ async () => {
+ //create a project card using the underlying client
+ return io.github.client.rest.projects.createCard({
+ column_id: 123,
+ note: "test",
+ });
+ }
+ );
+
+ //log the url of the created card
+ await io.logger.info(data.url);
+ },
+});
+```
diff --git a/docs/integrations/apis/openai.mdx b/docs/integrations/apis/openai.mdx
new file mode 100644
index 000000000..9d6827fd6
--- /dev/null
+++ b/docs/integrations/apis/openai.mdx
@@ -0,0 +1,94 @@
+---
+title: Introduction
+---
+
+
+
+## Installation
+
+
+
+```bash npm
+npm install @trigger.dev/openai@latest
+```
+
+```bash pnpm
+pnpm install @trigger.dev/openai@latest
+```
+
+```bash yarn
+yarn add @trigger.dev/openai@latest
+```
+
+
+
+## Authentication
+
+OpenAI supports API Keys
+
+```ts
+import { OpenAI } from "@trigger.dev/openai";
+
+const openai = new OpenAI({
+ id: "openai",
+ apiKey: process.env.OPENAI_API_KEY!,
+});
+```
+
+## Example
+
+```ts
+new Job(client, {
+ id: "openai-tasks",
+ name: "OpenAI Tasks",
+ version: "0.0.1",
+ trigger: eventTrigger({
+ name: "openai.tasks",
+ schema: z.object({}),
+ }),
+ integrations: {
+ openai,
+ },
+ run: async (payload, io, ctx) => {
+ const response = await io.openai.backgroundCreateChatCompletion(
+ "background-chat-completion",
+ {
+ model: "gpt-3.5-turbo",
+ messages: [
+ {
+ role: "user",
+ content: "Create a good programming joke about background jobs",
+ },
+ ],
+ }
+ );
+
+ await io.logger.info("choices", response.choices);
+ },
+});
+```
+
+## Tasks
+
+Tasks that are marked as "long-running" can last longer than your serverless timeout – they are performed on one of our background workers.
+
+| Function Name | Description | Long-running? |
+| -------------------------------- | ------------------------------------------------------------------------- | ------------- |
+| `createCompletion` | Generates text completions given a prompt. |
+| `backgroundCreateCompletion` | Generates text completions in the background. | ✔ |
+| `createChatCompletion` | Generates text completions in a conversational context. |
+| `backgroundCreateChatCompletion` | Generates text completions in a conversational context in the background. | ✔ |
+| `retrieveModel` | Retrieves a specific model by ID. |
+| `listModels` | Lists the available models. |
+| `createEdit` | Edits a given text prompt. |
+| `createImage` | Generates images from textual descriptions. |
+| `createEmbedding` | Generates embeddings for a given text. |
+| `createFile` | Uploads a file to the OpenAI API. |
+| `listFiles` | Lists the uploaded files. |
+| `createFineTuneFile` | Uploads a file for fine-tuning a model. |
+| `createFineTune` | Fine-tunes a model on a given task. |
+| `listFineTunes` | Lists the available fine-tunes. |
+| `retrieveFineTune` | Retrieves a specific fine-tune by ID. |
+| `cancelFineTune` | Cancels a specific fine-tune by ID. |
+| `listFineTuneEvents` | Lists the events for a specific fine-tune by ID. |
+| `deleteFineTune` | Deletes a specific fine-tune by ID. |
diff --git a/docs/integrations/apis/plain.mdx b/docs/integrations/apis/plain.mdx
new file mode 100644
index 000000000..10a042bbe
--- /dev/null
+++ b/docs/integrations/apis/plain.mdx
@@ -0,0 +1,175 @@
+---
+title: Plain
+description: Plain is customer support for developer tools
+---
+
+
+
+## Installation
+
+
+
+```bash npm
+npm install @trigger.dev/plain@latest
+```
+
+```bash pnpm
+pnpm install @trigger.dev/plain@latest
+```
+
+```bash yarn
+yarn add @trigger.dev/plain@latest
+```
+
+
+
+## Authentication
+
+Plain supports API Keys, to create yours read the [Plain authentication guide](https://www.plain.com/docs/graphql-api/authentication).
+
+```ts
+import { Plain } from "@trigger.dev/plain";
+
+export const plain = new Plain({
+ id: "plain",
+ apiKey: process.env.PLAIN_API_KEY!,
+});
+```
+
+## Create customers and timeline entries
+
+The Plain Integration allows you to create/update customers and add timeline entries.
+
+```ts
+import { client } from "@/trigger";
+import { Job } from "@trigger.dev/sdk";
+import { Plain } from "@trigger.dev/plain";
+
+export const plain = new Plain({
+ id: "plain",
+ apiKey: process.env.PLAIN_API_KEY!,
+});
+
+new Job(client, {
+ id: "plain-playground",
+ name: "Plain Playground",
+ version: "0.1.1",
+ integrations: {
+ plain,
+ },
+ trigger: eventTrigger({
+ name: "plain.playground",
+ }),
+ run: async (payload, io, ctx) => {
+ const { customer } = await io.plain.upsertCustomer("upsert-customer", {
+ identifier: {
+ emailAddress: "rick.astley@gmail.com",
+ },
+ onCreate: {
+ email: {
+ email: "rick.astley@gmail.com",
+ isVerified: true,
+ },
+ fullName: "Rick Astley",
+ externalId: "u_123",
+ },
+ onUpdate: {
+ fullName: {
+ value: "Rick Astley",
+ },
+ externalId: {
+ value: "u_123",
+ },
+ },
+ });
+
+ const foundCustomer = await io.plain.getCustomerById("get-customer", {
+ customerId: customer.id,
+ });
+
+ const timelineEntry = await io.plain.upsertCustomTimelineEntry(
+ "upsert-timeline-entry",
+ {
+ customerId: customer.id,
+ title: "My timeline entry",
+ components: [
+ {
+ componentText: {
+ text: `This is a nice title`,
+ },
+ },
+ {
+ componentDivider: {
+ dividerSpacingSize: ComponentDividerSpacingSize.M,
+ },
+ },
+ {
+ componentText: {
+ textSize: ComponentTextSize.S,
+ textColor: ComponentTextColor.Muted,
+ text: "External id",
+ },
+ },
+ {
+ componentText: {
+ text: foundCustomer?.externalId ?? "",
+ },
+ },
+ ],
+ }
+ );
+ },
+});
+```
+
+## Tasks
+
+## All tasks
+
+| Function Name | Description |
+| --------------------------- | ----------------------------------- |
+| `getCustomerById` | Gets a customer using their id |
+| `upsertCustomer` | Creates or updates a customer |
+| `upsertCustomTimelineEntry` | Creates or updates a timeline entry |
+
+## Using the underlying client
+
+You can use the underlying client to do anything [@team-plain/typescript-sdk](https://github.com/team-plain/typescript-sdk) supports, but make sure to wrap it in a task:
+
+```ts
+import { Plain } from "@trigger.dev/plain";
+
+//create client
+export const plain = new Plain({
+ id: "plain",
+ apiKey: process.env.PLAIN_API_KEY!,
+});
+
+new Job(client, {
+ id: "plain-client",
+ name: "Plain Client",
+ version: "0.1.0",
+ integrations: { plain },
+ trigger: eventTrigger({
+ name: "plain.client",
+ }),
+ run: async (payload, io, ctx) => {
+ const issue = await io.runTask(
+ "create-issue",
+ { name: "Create issue", icon: "plain" },
+ async () => {
+ const result = await io.plain.client.createIssue({
+ customerId: "abcdefghij",
+ issueTypeId: "123456",
+ });
+
+ if (result.error) {
+ throw result.error;
+ }
+
+ return result.data;
+ }
+ );
+ },
+});
+```
diff --git a/docs/integrations/apis/resend.mdx b/docs/integrations/apis/resend.mdx
new file mode 100644
index 000000000..6925daa5e
--- /dev/null
+++ b/docs/integrations/apis/resend.mdx
@@ -0,0 +1,84 @@
+---
+title: Introduction
+---
+
+
+
+## Installation
+
+
+
+```bash npm
+npm install @trigger.dev/resend@latest
+```
+
+```bash pnpm
+pnpm install @trigger.dev/resend@latest
+```
+
+```bash yarn
+yarn add @trigger.dev/resend@latest
+```
+
+
+
+## Authentication
+
+Resend supports API Keys
+
+```ts
+import { Resend } from "@trigger.dev/resend";
+
+const resend = new Resend({
+ id: "resend",
+ apiKey: process.env.RESEND_API_KEY!,
+});
+```
+
+## Example
+
+In this example we use [Zod](/documentation/guides/zod), a TypeScript-first schema declaration and validation library.
+
+```ts
+import { Resend } from "@trigger.dev/resend";
+import { Job, eventTrigger } from "@trigger.dev/sdk";
+import { z } from "zod";
+
+...
+
+const resend = new Resend({
+ id: "resend",
+ apiKey: process.env.RESEND_API_KEY!,
+});
+
+new Job(client, {
+ id: "send-resend-email",
+ name: "Send Resend Email",
+ version: "0.1.0",
+ trigger: eventTrigger({
+ name: "send.email",
+ schema: z.object({
+ to: z.union([z.string(), z.array(z.string())]),
+ subject: z.string(),
+ text: z.string(),
+ }),
+ }),
+ integrations: {
+ resend,
+ },
+ run: async (payload, io, ctx) => {
+ await io.resend.sendEmail("send-email", {
+ to: payload.to,
+ subject: payload.subject,
+ text: payload.text,
+ from: "Trigger.dev ",
+ });
+ },
+});
+```
+
+## Tasks
+
+| Function Name | Description |
+| ------------- | ------------- |
+| `sendEmail` | Send an email |
diff --git a/docs/integrations/apis/slack.mdx b/docs/integrations/apis/slack.mdx
new file mode 100644
index 000000000..d62b2ffc1
--- /dev/null
+++ b/docs/integrations/apis/slack.mdx
@@ -0,0 +1,64 @@
+---
+title: Introduction
+---
+
+
+
+## Installation
+
+
+
+```bash npm
+npm install @trigger.dev/slack@latest
+```
+
+```bash pnpm
+pnpm install @trigger.dev/slack@latest
+```
+
+```bash yarn
+yarn add @trigger.dev/slack@latest
+```
+
+
+
+## Authentication
+
+Slack supports OAuth
+
+```ts
+import { Slack } from "@trigger.dev/slack";
+
+const slack = new Slack({
+ id: "slack",
+});
+```
+
+## Example
+
+```ts
+new Job(client, {
+ id: "slack-test",
+ name: "Slack test",
+ version: "0.0.1",
+ trigger: eventTrigger({
+ name: "slack.test",
+ schema: z.object({}),
+ }),
+ integrations: {
+ slack,
+ },
+ run: async (payload, io, ctx) => {
+ const response = await io.slack.postMessage("post message", {
+ channel: "C04GWUTDC3W",
+ text: "My first Slack message",
+ });
+ },
+});
+```
+
+## Tasks
+
+| Function Name | Description |
+| ------------- | --------------------------- |
+| `postMessage` | Post a message to a channel |
diff --git a/docs/integrations/apis/supabase/client.mdx b/docs/integrations/apis/supabase/client.mdx
new file mode 100644
index 000000000..7b0f4e731
--- /dev/null
+++ b/docs/integrations/apis/supabase/client.mdx
@@ -0,0 +1,124 @@
+---
+title: "Supabase Client"
+sidebarTitle: "JS Client"
+description: "Interact with your Supabase project using the Supabase JS Client."
+---
+
+Our `@trigger.dev/supabase` package provides an integration that wraps the [@supabase/supabase-js](https://github.com/supabase/supabase-js) package, allowing you to run tasks to interact with your Supabase project.
+
+
+ If you want to trigger jobs based on changes in your Supabase database, you'll
+ need to use the [Supabase Management API](../management) integration
+
+
+## Usage
+
+Our Supabase integration currently only supports [service_role](https://supabase.com/docs/guides/api/api-keys#the-servicerole-key) keys:
+
+```ts
+import { Supabase } from "@trigger.dev/supabase";
+
+const supabase = new Supabase({
+ id: "supabase",
+ supabaseUrl: `https://.supabase.co`,
+ supabaseKey: process.env.SUPABASE_SERVICE_ROLE_KEY!,
+});
+```
+
+
+ Never expose the `service_role` key in a browser or anywhere where a user can
+ see it.
+
+
+You can then use the `supabase` integration to run tasks in your jobs:
+
+```ts
+client.defineJob({
+ // ...
+ integrations: {
+ supabase,
+ },
+ run: async (payload, io, ctx) => {
+ const { data: users, error } = await io.supabase.runTask(
+ "find-users",
+ async (db) => {
+ return db.from("users").select("*");
+ }
+ );
+ },
+});
+```
+
+
+ By using `runTask` instead of the `@supabase/supabase-js` client directly
+ inside your job run, you'll be able to create tasks that can be run
+ idempotently and also retried. For more, see our guide on
+ [Resumability](http://localhost:3050/documentation/concepts/resumability)
+
+
+You can also choose to throw an error if the query fails and abort the job run:
+
+```ts
+client.defineJob({
+ // ...
+ integrations: {
+ supabase,
+ },
+ run: async (payload, io, ctx) => {
+ const users = await io.supabase.runTask("find-users", async (db) => {
+ const { data, error } = await db.from("users").select("*");
+
+ if (error) throw error;
+
+ return data;
+ });
+ },
+});
+```
+
+The `db` object passed to the callback is an instance of the [@supabase/supabase-js](https://github.com/supabase/supabase-js) client, so you can use it to run any of the queries or other operations that the client supports:
+
+- [Databases](https://supabase.com/docs/reference/javascript/select)
+- [Auth](https://supabase.com/docs/reference/javascript/auth-signup)
+- [Invoking Functions](https://supabase.com/docs/reference/javascript/functions-invoke)
+- [Storage](https://supabase.com/docs/reference/javascript/storage-createbucket)
+
+
+ Currently we do not support Supabase Realtime (such as subscribing to a
+ channel)
+
+
+## Typescript Support
+
+If you have [generated types](https://supabase.com/docs/reference/javascript/typescript-support) for your Supabase database, you can use them to get type safety for interaction with your database:
+
+```ts
+import { Supabase } from "@trigger.dev/supabase";
+import { Database } from "./supabase.types"; // generated types
+
+const supabase = new Supabase({
+ id: "supabase",
+ supabaseUrl: `https://.supabase.co`,
+ supabaseKey: process.env.SUPABASE_SERVICE_ROLE_KEY!,
+});
+
+client.defineJob({
+ // ...
+ integrations: {
+ supabase,
+ },
+ run: async (payload, io, ctx) => {
+ const users = await io.supabase.runTask("find-users", async (db) => {
+ const { data, error } = await db.from("users").select("*");
+
+ if (error) throw error;
+
+ return data;
+ });
+
+ // users is now typed as User[] instead of any[]
+ },
+});
+```
+
+For more about generating types, see the [Supabase guide](https://supabase.com/docs/reference/javascript/typescript-support)
diff --git a/docs/integrations/apis/supabase/introduction.mdx b/docs/integrations/apis/supabase/introduction.mdx
new file mode 100644
index 000000000..6ce873a93
--- /dev/null
+++ b/docs/integrations/apis/supabase/introduction.mdx
@@ -0,0 +1,52 @@
+---
+title: Introduction
+---
+
+
+
+## Installation
+
+
+
+```bash npm
+npm install @trigger.dev/supabase
+```
+
+```bash pnpm
+pnpm add @trigger.dev/supabase
+```
+
+```bash yarn
+yarn add @trigger.dev/supabase
+```
+
+
+
+## Usage
+
+Our Supabase package supports two different integrations: One for the Supabase Management API and one that wraps the `@supabase/supabase-js` client.
+
+
+
+ The [Management API](https://supabase.com/docs/reference/api/introduction)
+ is used to manage your Supabase organization, projects, and databases. It
+ can also be used to trigger jobs based on changes in your Supabase database.
+ Works with OAuth or Personal Access Tokens.
+
+
+ Wraps the [@supabase/supabase-js](https://github.com/supabase/supabase-js)
+ client to make it easy to use Supabase in your jobs to run queries against
+ your database and access other functionality, like auth, storage, and
+ functions. Works with your Supabase
+ [service_role](https://supabase.com/docs/guides/api/api-keys#the-servicerole-key)
+ key.
+
+
diff --git a/docs/integrations/apis/supabase/management.mdx b/docs/integrations/apis/supabase/management.mdx
new file mode 100644
index 000000000..1981f6006
--- /dev/null
+++ b/docs/integrations/apis/supabase/management.mdx
@@ -0,0 +1,184 @@
+---
+title: "Supabase Management API"
+sidebarTitle: "Management API"
+description: "Manage your Supabase organization, projects, and databases"
+---
+
+Our `@trigger.dev/supabase` package provides an integration that wraps the [Supabase Management API](https://supabase.com/docs/reference/api/introduction), allow you to run tasks that can manage your Supabase Orgs, Projects, and Databases.
+
+It also provides the ability to trigger jobs based on changes in your Supabase database through the use of [Supabase Database Webhooks](https://supabase.com/docs/guides/database/webhooks).
+
+## Usage
+
+There are two different ways to authenticate with the Supabase Management API, either using a [Personal Access Token](https://supabase.com/dashboard/account/tokens) or through OAuth provided by Trigger.dev.
+
+### Personal Access Token
+
+To use the Management API integration with a Personal Access Token, head over to your account [tokens](https://supabase.com/dashboard/account/tokens) page and click the "Generate New Token" button. Once you've copied the token you should save it to an environment variable in your project, for example `SUPABASE_TOKEN` and then use it in the `SupabaseManagementAPI` constructor:
+
+```ts
+import { SupabaseManagement } from "@trigger.dev/supabase";
+
+const supabaseManagement = new SupabaseManagement({
+ id: "supabase-management",
+ apiKey: process.env.SUPABASE_TOKEN!,
+});
+```
+
+Make sure you have the `SUPABASE_TOKEN` environment variable set in your project and keep it secret, as it provides full access to your Supabase account.
+
+### OAuth
+
+To use the Management API integration with Supabase OAuth, you'll need to create a new integration in the Trigger.dev dashboard and authorize it with your Supabase account. Once you've done that, you can use the `SupabaseManagementAPI` constructor with the matching `id` of the integration:
+
+```ts
+import { SupabaseManagement } from "@trigger.dev/supabase";
+
+const supabaseManagement = new SupabaseManagement({
+ id: "supabase-oauth",
+});
+```
+
+The access token will automatically be refreshed when it expires, so you don't need to worry about it, and any job that runs using the integration will have access to your Supabase account.
+
+## Jobs & Tasks
+
+Using the `SupabaseManagement` integration, you can run any of the [Management API](https://supabase.com/docs/reference/api/introduction) endpoints as a task inside a job. For example, to create a new Supabase project:
+
+```ts
+import { TriggerClient, eventTrigger } from "@trigger.dev/sdk"; // this is the Trigger.dev client
+import { SupabaseManagement } from "@trigger.dev/supabase";
+
+const client = new TriggerClient({
+ apiKey: process.env.TRIGGER_API_KEY!,
+});
+
+const supabaseManagement = new SupabaseManagement({
+ id: "supabase-management",
+});
+
+client.defineJob({
+ id: "create-supabase-project",
+ name: "Create Supabase Project",
+ version: "1.0.0",
+ integrations: {
+ supabaseManagement,
+ },
+ trigger: eventTrigger({
+ name: "create.project"
+ })
+ run: async (payload, io, ctx) => {
+ await io.supabaseManagement.createProject("🚀", {
+ name: payload.name,
+ organization_id: payload.organization_id,
+ plan: "free",
+ region: "us-east-1",
+ db_pass: "secret1234"
+ })
+ }
+})
+```
+
+For a full list of available tasks, see the [Supabase Management API](https://supabase.com/docs/reference/api/introduction) documentation.
+
+## Triggers
+
+The `SupabaseManagement` integration also provides the ability to trigger jobs based on changes in your Supabase database through the use of [Supabase Database Webhooks](https://supabase.com/docs/guides/database/webhooks).
+
+To use this feature, you'll first initialize a `db` instance, passing in your Supabase project [ID](https://supabase.com/dashboard/project/_/settings/api) (or URL):
+
+```ts
+import { SupabaseManagement } from "@trigger.dev/supabase";
+
+const supabaseManagement = new SupabaseManagement({
+ id: "supabase-management",
+});
+
+const db = supabase.db("https://.supabase.co");
+```
+
+Now, you can use the `db` instance to add a trigger to run a job when a row is inserted, updated, or deleted from a table:
+
+```ts
+client.defineJob({
+ id: "supabase-trigger",
+ name: "Supabase Trigger",
+ trigger: db.onInserted({
+ table: "users",
+ }),
+ run: async (payload, io, ctx) => {
+ // payload is the database webhook body (see https://supabase.com/docs/guides/database/webhooks#payload)
+ },
+});
+```
+
+You can add additional filters to the trigger by passing a `filter` object:
+
+```ts
+client.defineJob({
+ id: "supabase-trigger",
+ name: "Supabase Trigger",
+ trigger: db.onUpdated({
+ table: "users",
+ filter: {
+ country: ["USA", "Canada"], // This will only trigger the job if the user.country is USA or Canada
+ },
+ }),
+ run: async (payload, io, ctx) => {
+ // payload is the database webhook body (see https://supabase.com/docs/guides/database/webhooks#payload)
+ },
+});
+
+client.defineJob({
+ id: "supabase-trigger",
+ name: "Supabase Trigger",
+ trigger: db.onUpdated({
+ table: "todos",
+ // Only trigger if the todo is marked as completed
+ filter: {
+ old_record: {
+ is_completed: [false],
+ },
+ record: {
+ is_completed: [true],
+ },
+ },
+ }),
+ run: async (payload, io, ctx) => {
+ // payload is the database webhook body (see https://supabase.com/docs/guides/database/webhooks#payload)
+ },
+});
+```
+
+
+ We will only create at most 1 database webhook per table, to limit resource
+ usage when writing to your database. This means we cannot support scoping
+ updated triggers to specific columns.
+
+
+### Typescript Support
+
+If you have [generated types](https://supabase.com/docs/reference/javascript/typescript-support) for your Supabase database, you can use them to get type safety for your database triggers:
+
+```ts
+import { Database } from "./supabase.types"; // Generated types
+import { SupabaseManagement } from "@trigger.dev/supabase";
+
+const supabaseManagement = new SupabaseManagement({
+ id: "supabase-management",
+});
+
+// Pass the generated types to the db instance
+const db = supabase.db("https://.supabase.co");
+
+client.defineJob({
+ id: "supabase-trigger",
+ name: "Supabase Trigger",
+ trigger: db.onUpdated({
+ table: "users",
+ }),
+ run: async (payload, io, ctx) => {
+ // payload.record and payload.old_record are now correctly typed to match the users table
+ },
+});
+```
diff --git a/docs/integrations/apis/typeform.mdx b/docs/integrations/apis/typeform.mdx
new file mode 100644
index 000000000..7ee2e7d70
--- /dev/null
+++ b/docs/integrations/apis/typeform.mdx
@@ -0,0 +1,156 @@
+---
+title: Typeform
+---
+
+
+
+## Installation
+
+
+
+```bash npm
+npm install @trigger.dev/typeform@latest
+```
+
+```bash pnpm
+pnpm install @trigger.dev/typeform@latest
+```
+
+```bash yarn
+yarn add @trigger.dev/typeform@latest
+```
+
+
+
+## Authentication
+
+Typeform supports Personal Access Tokens, to create yours read the [Typeform Personal Access Token guide](https://www.typeform.com/developers/get-started/personal-access-token/).
+
+```ts
+import { Typeform } from "@trigger.dev/typeform";
+
+//create Typeform client using a person access token
+const typeform = new Typeform({
+ id: "typeform-1",
+ token: process.env.TYPEFORM_PAT!,
+});
+```
+
+## Get notified of new form responses
+
+The Typeform Integration allows you to trigger a job run when a new form response is submitted using the `onFormResponse` trigger:
+
+```ts
+import { client } from "@/trigger";
+import { Typeform } from "@trigger.dev/typeform";
+import { Job } from "@trigger.dev/sdk";
+
+export const typeform = new Typeform({
+ id: "typeform-1",
+ token: process.env.TYPEFORM_API_KEY!,
+});
+
+new Job(client, {
+ id: "do-something-on-new-responses",
+ name: "Send a message to slack on new responses",
+ version: "0.1.1",
+ trigger: typeform.onFormResponse({
+ uid: "