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

# Triggers

export const FUNCTION_PAYLOAD_LIMIT = '6MB';

export const EMAIL_PAYLOAD_SIZE_LIMIT = '30MB';

export const PAYLOAD_SIZE_LIMIT = '512KB';

export const ENDPOINT_BASE_URL = '*.m.pipedream.net';

<Frame>
  <iframe className="w-full aspect-video rounded-xl" src="https://www.youtube.com/embed/Jjq-ZoYZQoQ" title="Using Triggers" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowFullScreen />
</Frame>

**Triggers** define the type of event that runs your workflow. For example, HTTP triggers expose a URL where you can send any HTTP requests. Pipedream will run your workflow on each request. The Scheduler trigger runs your workflow on a schedule, like a cron job.

Today, we support the following triggers:

* [Triggers for apps like Twitter, GitHub, and more](/workflows/building-workflows/triggers/#app-based-triggers)
* [HTTP / Webhook](/workflows/building-workflows/triggers/#http)
* [Schedule](/workflows/building-workflows/triggers/#schedule)
* [Email](/workflows/building-workflows/triggers/#email)
* [RSS](/workflows/building-workflows/triggers/#rss)

If there’s a specific trigger you’d like supported, please [let us know](https://pipedream.com/support/).

## App-based Triggers

You can trigger a workflow on events from apps like Twitter, Google Calendar, and more using [event sources](/workflows/building-workflows/triggers/). Event sources run as separate resources from your workflow, which allows you to trigger *multiple* workflows using the same source. Here, we’ll refer to event sources and workflow triggers interchangeably.

When you create a workflow, click **Add Trigger** to view the available triggers:

<Frame>
  <img src="https://mintcdn.com/pipedream/xnRKrRxEtt3vxd6I/images/c223818e-image.png?fit=max&auto=format&n=xnRKrRxEtt3vxd6I&q=85&s=888738847789814036d90d70e6e955a9" width="448" height="175" data-path="images/c223818e-image.png" />
</Frame>

This will open a new menu to search and choose a trigger for your workflow:

<Frame>
  <img src="https://mintcdn.com/pipedream/h8oodpUDiyR1Ssvt/images/3b97c96b-image.png?fit=max&auto=format&n=h8oodpUDiyR1Ssvt&q=85&s=dd1d36fc586b2c002803c27450952993" width="1376" height="818" data-path="images/3b97c96b-image.png" />
</Frame>

Search by **app name** to find triggers associated with your app. For Google Calendar, for example, you can run your workflow every time a new event is **added** to your calendar, each time an event **starts**, **ends**, and more:

<Frame>
  <img src="https://mintcdn.com/pipedream/NF77kliJSewMqg65/images/0eb031e4-image.png?fit=max&auto=format&n=NF77kliJSewMqg65&q=85&s=e8fe25920a9060b1a9f5e4f56f83b541" width="1363" height="654" data-path="images/0eb031e4-image.png" />
</Frame>

Once you select your trigger, you’ll be asked to connect any necessary accounts (for example, Google Calendar sources require you authorize Pipedream access to your Google account), and enter the values for any configuration settings.

Some sources are configured to retrieve an initial set of events when they’re created. Others require you to generate events in the app to trigger your workflow. If your source generates an initial set of events, you’ll see them appear in the **Select events** dropdown in the **Select Event** step:

<Frame>
  <img src="https://mintcdn.com/pipedream/NF77kliJSewMqg65/images/0401e401-CleanShot_2022-03-22_at_09.55.57_2x_upj35r.png?fit=max&auto=format&n=NF77kliJSewMqg65&q=85&s=45ced1089dee7989683d226775fac13a" width="2028" height="1032" data-path="images/0401e401-CleanShot_2022-03-22_at_09.55.57_2x_upj35r.png" />
</Frame>

Then you can select a specific test event and manually trigger your workflow with that event data by clicking **Send Test Event**. Now you’re ready to build your workflow with the selected test event.

### What’s the difference between an event source and a trigger?

You’ll notice the docs use the terms **event source** and **trigger** interchangeably above. It’s useful to clarify the distinction in the context of workflows.

[Event sources](/workflows/building-workflows/triggers/) run code that collects events from some app or service and emits events as the source produces them. An event source can be used to **trigger** any number of workflows.

For example, you might create a single source to listen for new Twitter mentions for a keyword, then trigger multiple workflows each time a new tweet is found: one to [send new tweets to Slack](https://pipedream.com/@pravin/twitter-mentions-slack-p_dDCA5e/edit), another to [save those tweets to an Amazon S3 bucket](https://pipedream.com/@dylan/twitter-to-s3-p_KwCZGA/readme), etc.

**This model allows you to separate the data produced by a service (the event source) from the logic to process those events in different contexts (the workflow)**.

Moreover, you can access events emitted by sources using Pipedream’s [SSE](/workflows/data-management/destinations/sse/) and [REST APIs](/rest-api/). This allows you to access these events in your own app, outside Pipedream’s platform.

### Can I add multiple triggers to a workflow?

Yes, you can add any number of triggers to a workflow. Click the top right menu in the trigger step and select **Add trigger**.

<Frame>
  <img src="https://mintcdn.com/pipedream/grEzwYhEB2vZSwGw/images/899a0814-image.png?fit=max&auto=format&n=grEzwYhEB2vZSwGw&q=85&s=aef5f14b7355700d74261032761db207" width="470" height="330" data-path="images/899a0814-image.png" />
</Frame>

### Shape of the `steps.trigger.event` object

In all workflows, you have access to [event data](/workflows/building-workflows/triggers/#event-format) using the variable `steps.trigger.event`.

The shape of the event is specific to the source. For example, RSS sources produce events with a `url` and `title` property representing the data provided by new items from a feed. Google Calendar sources produce events with a meeting title, start date, etc.

## HTTP

When you select the **HTTP** trigger:

<Frame>
  <img src="https://mintcdn.com/pipedream/xnRKrRxEtt3vxd6I/images/d7aa472c-image.png?fit=max&auto=format&n=xnRKrRxEtt3vxd6I&q=85&s=5899d83eab2e4e1f0334cbf53e3d1c0e" width="1362" height="800" data-path="images/d7aa472c-image.png" />
</Frame>

Pipedream creates a URL endpoint specific to your workflow:

<Frame>
  <img src="https://mintcdn.com/pipedream/h8oodpUDiyR1Ssvt/images/300c019f-image.png?fit=max&auto=format&n=h8oodpUDiyR1Ssvt&q=85&s=81385af20a15240c238cf3928ac529eb" width="1057" height="446" data-path="images/300c019f-image.png" />
</Frame>

You can send any HTTP requests to this endpoint, from anywhere on the web. You can configure the endpoint as the destination URL for a webhook or send HTTP traffic from your application - we’ll accept any [valid HTTP request](/workflows/building-workflows/triggers/#valid-requests).

<Note>
  Pipedream also supports [custom domains](/workflows/domains/). This lets you host endpoints on `https://endpoint.yourdomain.com` instead of the default <code>{ENDPOINT_BASE_URL}</code> domain.
</Note>

### Accessing HTTP request data

You can access properties of the HTTP request, like the method, payload, headers, and more, in [the `event` object](/workflows/building-workflows/triggers/#event-format), accessible in any [code](/workflows/building-workflows/code/) or [action](/components/contributing/#actions) step.

### Valid Requests

You can send a request to your endpoint using any valid HTTP method: `GET`, `POST`, `HEAD`, and more.

We default to generating HTTPS URLs in the UI, but will accept HTTP requests against the same endpoint URL.

You can send data to any path on this host, with any query string parameters. You can access the full URL in the `event` object if you’d like to write code that interprets requests with different URLs differently.

You can send data of any [Media Type](https://www.iana.org/assignments/media-types/media-types.xhtml) in the body of your request.

The primary limit we impose is on the size of the request body: we’ll issue a `413 Payload Too Large` status when the body [exceeds our specified limit](/workflows/building-workflows/triggers/#request-entity-too-large).

### Authorizing HTTP requests

By default, HTTP triggers are public and require no authorization to invoke. Anyone with the endpoint URL can trigger your workflow. When possible, we recommend adding authorization.

HTTP triggers support two built-in authorization types in the **Authorization** section of the HTTP trigger configuration: a [static, custom token](/workflows/building-workflows/triggers/#custom-token) and [OAuth](/workflows/building-workflows/triggers/#oauth).

#### Custom token

To configure a static, custom token for HTTP auth:

1. Open the **Configure** section of the HTTP trigger
2. Select **Custom token**.
3. Enter whatever secret you’d like and click **Save and Continue**.

<Frame>
  <img src="https://mintcdn.com/pipedream/grEzwYhEB2vZSwGw/images/915c7c73-Google_Chrome_-_Untitled_Workflow_-_10-24-2024_10-30_AM_-_Build_-_Pipedream_2024-10-24_at_10.31.01_AM_pkh8dk.png?fit=max&auto=format&n=grEzwYhEB2vZSwGw&q=85&s=ee8b8f2d7c05c6e72e017ca0281c3d7e" width="1713" height="1301" data-path="images/915c7c73-Google_Chrome_-_Untitled_Workflow_-_10-24-2024_10-30_AM_-_Build_-_Pipedream_2024-10-24_at_10.31.01_AM_pkh8dk.png" />
</Frame>

When making HTTP requests, pass the custom token as a `Bearer` token in the `Authorization` header:

```bash theme={null}
curl -H 'Authorization: Bearer <your token>' https://myendpoint.m.pipedream.net
```

#### OAuth

You can also authorize requests using [Pipedream OAuth clients](/rest-api/auth/#oauth):

1. Open the **Configure** section of the HTTP trigger.
2. Select **OAuth**.
3. If you don’t have an existing OAuth client, [create one in your workspace’s API settings](/rest-api/auth/#creating-an-oauth-client).

<Frame>
  <img src="https://mintcdn.com/pipedream/Acz4Z1ch6TM7-aI8/images/9c43dae5-Google_Chrome_-_Untitled_Workflow_-_10-24-2024_10-30_AM_-_Build_-_Pipedream_2024-10-24_at_10.36.04_AM_ujx34e.png?fit=max&auto=format&n=Acz4Z1ch6TM7-aI8&q=85&s=a00bb7e6f8efd4494869cba6605f0d7f" width="1570" height="1212" data-path="images/9c43dae5-Google_Chrome_-_Untitled_Workflow_-_10-24-2024_10-30_AM_-_Build_-_Pipedream_2024-10-24_at_10.36.04_AM_ujx34e.png" />
</Frame>

Next, you’ll need to [generate an OAuth access token](/rest-api/auth/#how-to-get-an-access-token).

When making HTTP requests, pass the OAuth access token as a `Bearer` token in the `Authorization` header:

```bash theme={null}
curl -H 'Authorization: Bearer <OAuth access token>' https://myendpoint.m.pipedream.net
```

You can use the Pipedream SDK to automatically refresh access tokens and invoke workflows, or make HTTP requests directly to the workflow’s URL:

<CodeGroup>
  ```javascript JavaScript theme={null}
  import { PipedreamClient } from "@pipedream/sdk";
   
  // These secrets should be saved securely and passed to your environment
  const client = new PipedreamClient({
    clientId: "{oauth_client_id}",
    clientSecret: "{oauth_client_secret}",
    projectId: "{project_id}",
    projectEnvironment: "development" // or "production"
  });
   
  await client.workflows.invokeForExternalUser(
    "enabc123", // pass the endpoint ID or full URL here
    "{external_user_id}", // The end user's ID in your system
    "POST", // HTTP method
    {
      key: "value",
    } // request body
  )
  ```

  ```bash cURL theme={null}
  # First, obtain an OAuth access token
  curl -X POST https://api.pipedream.com/v1/oauth/token \
    -H "Content-Type: application/json" \
    -d '{
      "grant_type": "client_credentials",
      "client_id": "{oauth_client_id}",
      "client_secret": "{oauth_client_secret}"
    }'
   
  # The response will include an access_token. Use it in the Authorization header below.
  curl -X POST https://{your-endpoint-url} \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer {access_token}" \
    -d '{
      "message": "Hello, world"
    }'
  ```
</CodeGroup>

#### Implement your own authorization logic

Since you have access to the entire request object, and can issue any HTTP response from a workflow, you can implement custom logic to validate requests.

For example, you could require JWT tokens and validate those tokens using the [`jsonwebtoken` package](https://www.npmjs.com/package/jsonwebtoken) at the start of your workflow.

### Custom domains

To configure endpoints on your own domain, e.g. `endpoint.yourdomain.com` instead of the default `*.m.pipedream.net` domain, see the [custom domains](/workflows/domains/) docs.

### How Pipedream handles JSON payloads

When you send JSON in the HTTP payload, or when JSON data is sent in the payload from a webhook provider, **Pipedream converts that JSON to its equivalent JavaScript object**. The trigger data can be referenced using [the `steps` object](/workflows/building-workflows/triggers/#shape-of-the-stepstriggerevent-object).

In the [Inspector](/workflows/building-workflows/inspect/), we present `steps.trigger.event` cleanly, indenting nested properties, to make the payload easy to read. Since `steps.trigger.event` is a JavaScript object, it’s easy to reference and manipulate properties of the payload using dot-notation.

### How Pipedream handles `multipart/form-data`

When you send [form data](https://ec.haxx.se/http/http-multipart) to Pipedream using a `Content-Type` of `multipart/form-data`, Pipedream parses the payload and converts it to a JavaScript object with a property per form field. For example, if you send a request with two fields:

```bash theme={null}
curl -F 'name=Leia' -F 'title=General' https://myendpoint.m.pipedream.net
```

Pipedream will convert that to a JavaScript object, `event.body`, with the following shape:

```javascript theme={null}
{
  name: "Leia",
  title: "General",
}
```

### How Pipedream handles HTTP headers

HTTP request headers will be available in the `steps.trigger.event.headers` steps export in your downstream steps.

Pipedream will automatically lowercase header keys for consistency.

### Pipedream-specific request parameters

These params can be set as headers or query string parameters on any request to a Pipedream HTTP endpoint.

#### `x-pd-nostore`

Set to `1` to prevent logging any data for this execution. Pipedream will execute all steps of the workflow, but no data will be logged to Pipedream. No event will show up in the inspector or the Event History UI.

If you need to disable logging for *all* requests, use the workflow’s [Data Retention controls](/workflows/building-workflows/settings/#data-retention-controls), instead.

#### `x-pd-notrigger`

Set to `1` to send an event to the workflow for testing. Pipedream will **not** trigger the production version of the workflow, but will display the event in the [list of test events](/workflows/building-workflows/triggers/#selecting-a-test-event) on the HTTP trigger.

#### Limits

You can send any content, up to the [HTTP payload size limit](/workflows/limits/#http-request-body-size), as a part of the form request. The content of uploaded images or other binary files does not contribute to this limit — the contents of the file will be uploaded at a Pipedream URL you have access to within your source or workflow. See the section on [Large File Support](/workflows/building-workflows/triggers/#large-file-support) for more detail.

### Sending large payloads

*If you’re uploading files, like images or videos, you should use the [large file upload interface](/workflows/building-workflows/triggers/#large-file-support), instead*.

By default, the body of HTTP requests sent to a source or workflow is limited to {PAYLOAD_SIZE_LIMIT}. **But you can send an HTTP payload of any size to a [workflow](/workflows/building-workflows/) or an [event source](/workflows/building-workflows/triggers/) by including the `pipedream_upload_body=1` query string or an `x-pd-upload-body: 1` HTTP header in your request**.

```bash theme={null}
curl -d '{ "name": "Yoda" }' \
  https://endpoint.m.pipedream.net\?pipedream_upload_body\=1
 
curl -d '{ "name": "Yoda" }' \
  -H "x-pd-upload-body: 1" \
  https://endpoint.m.pipedream.net
```

In workflows, Pipedream saves the raw payload data in a file whose URL you can reference in the variable `steps.trigger.event.body.raw_body_url`.

<Frame>
  <img src="https://mintcdn.com/pipedream/xnRKrRxEtt3vxd6I/images/ccaee50d-CleanShot_2022-03-21_at_16.42.01_2x_w6dmqk.png?fit=max&auto=format&n=xnRKrRxEtt3vxd6I&q=85&s=2fad1cff81857bdd4e4ed793212eb302" width="1744" height="638" data-path="images/ccaee50d-CleanShot_2022-03-21_at_16.42.01_2x_w6dmqk.png" />
</Frame>

Within your workflow, you can download the contents of this data using the **Send HTTP Request** action, or [by saving the data as a file to the `/tmp` directory](/workflows/building-workflows/code/nodejs/working-with-files/).

#### Example: Download the HTTP payload using the Send HTTP Request action

*Note: you can only download payloads at most {FUNCTION_PAYLOAD_LIMIT} in size using this method. Otherwise, you may encounter a [Function Payload Limit Exceeded](/troubleshooting/#function-payload-limit-exceeded) error.*

You can download the large HTTP payload using the **Send HTTP Request** action. [Copy this workflow to see how this works](https://pipedream.com/new?h=tch_egfAby).

The payload from the trigger of the workflow is exported to the variable `steps.retrieve_large_payload.$return_value`:

<Frame>
  <img src="https://mintcdn.com/pipedream/NF77kliJSewMqg65/images/07182686-image.png?fit=max&auto=format&n=NF77kliJSewMqg65&q=85&s=3c49406301f10ba0d7efd7063f605be2" width="1144" height="368" data-path="images/07182686-image.png" />
</Frame>

#### Example: Download the HTTP payload to the `/tmp` directory

[This workflow](https://pipedream.com/new?h=tch_5ofXkX) downloads the HTTP payload, saving it as a file to the [`/tmp` directory](/workflows/building-workflows/code/nodejs/working-with-files/#the-tmp-directory).

```javascript theme={null}
import stream from "stream";
import { promisify } from "util";
import fs from "fs";
import got from "got";
 
export default defineComponent({
  async run({ steps, $ }) {
    const pipeline = promisify(stream.pipeline);
    await pipeline(
      got.stream(steps.trigger.event.body.raw_body_url),
      fs.createWriteStream(`/tmp/raw_body`)
    );
  },
})
```

You can [read this file](/workflows/building-workflows/code/nodejs/working-with-files/#reading-a-file-from-tmp) in subsequent steps of your workflow.

#### How the payload data is saved

Your raw payload is saved to a Pipedream-owned [Amazon S3 bucket](https://aws.amazon.com/s3/). Pipedream generates a [signed URL](https://docs.aws.amazon.com/AmazonS3/latest/dev/ShareObjectPreSignedURL.html) that allows you to access to that file for up to 30 minutes. After 30 minutes, the signed URL will be invalidated, and the file will be deleted.

#### Limits

**You can upload payloads up to 5TB in size**. However, payloads that large may trigger [other Pipedream limits](/workflows/limits/). Please [reach out](https://pipedream.com/support/) with any specific questions or issues.

### Large File Support

*This interface is best used for uploading large files, like images or videos. If you’re sending JSON or other data directly in the HTTP payload, and encountering a **Request Entity Too Large** error, review the section above for [sending large payloads](/workflows/building-workflows/triggers/#sending-large-payloads)*.

You can upload any file to a [workflow](/workflows/building-workflows/) or an [event source](/workflows/building-workflows/triggers/) by making a `multipart/form-data` HTTP request with the file as one of the form parts. **Pipedream saves that file to a Pipedream-owned [Amazon S3 bucket](https://aws.amazon.com/s3/), generating a [signed URL](https://docs.aws.amazon.com/AmazonS3/latest/dev/ShareObjectPreSignedURL.html) that allows you to access to that file for up to 30 minutes**. After 30 minutes, the signed URL will be invalidated, and the file will be deleted.

In workflows, these file URLs are provided in the `steps.trigger.event.body` variable, so you can download the file using the URL within your workflow, or pass the URL on to another third-party system for it to process.

<Frame>
  <img src="https://mintcdn.com/pipedream/anb6FA0wpd8jtdUB/images/60d97667-image.png?fit=max&auto=format&n=anb6FA0wpd8jtdUB&q=85&s=1b7f3b1a8a6f942f301c6dce6b96172e" width="1098" height="592" data-path="images/60d97667-image.png" />
</Frame>

Within your workflow, you can download the contents of this data using the **Send HTTP Request** action, or [by saving the data as a file to the `/tmp` directory](/workflows/building-workflows/code/nodejs/working-with-files/).

#### Example: upload a file using `cURL`

For example, you can upload an image to a workflow using `cURL`:

```bash theme={null}
curl -F 'image=@my_image.png' https://myendpoint.m.pipedream.net
```

The `-F` tells `cURL` we’re sending form data, with a single “part”: a field named `image`, with the content of the image as the value (the `@` allows `cURL` to reference a local file).

When you send this image to a workflow, Pipedream [parses the form data](/workflows/building-workflows/triggers/#how-pipedream-handles-multipartform-data) and converts it to a JavaScript object, `event.body`. Select the event from the [inspector](/workflows/building-workflows/inspect/#the-inspector), and you’ll see the `image` property under `event.body`:

<Frame>
  <img src="https://mintcdn.com/pipedream/xnRKrRxEtt3vxd6I/images/c61ae423-image.png?fit=max&auto=format&n=xnRKrRxEtt3vxd6I&q=85&s=728c7fcb6fd6fb41d12a9aeeb44ec63f" width="2188" height="484" data-path="images/c61ae423-image.png" />
</Frame>

When you upload a file as a part of the form request, Pipedream saves it to a Pipedream-owned [Amazon S3 bucket](https://aws.amazon.com/s3/), generating a [signed URL](https://docs.aws.amazon.com/AmazonS3/latest/dev/ShareObjectPreSignedURL.html) that allows you to access to that file for up to 30 minutes. After 30 minutes, the signed URL will be invalidated, and the file will be deleted.

Within the `image` property of `event.body`, you’ll see the value of this URL in the `url` property, along with the `filename` and `mimetype` of the file. Within your workflow, you can download the file, or pass the URL to a third party system to handle, and more.

#### Example: Download this file to the `/tmp` directory

[This workflow](https://pipedream.com/@dylburger/example-download-an-image-to-tmp-p_KwC2Ad/edit) downloads an image passed in the `image` field in the form request, saving it to the [`/tmp` directory](/workflows/building-workflows/code/nodejs/working-with-files/#the-tmp-directory).

```javascript theme={null}
import stream from "stream";
import { promisify } from "util";
import fs from "fs";
import got from "got";
 
const pipeline = promisify(stream.pipeline);
await pipeline(
  got.stream(steps.trigger.event.body.image.url),
  fs.createWriteStream(`/tmp/${steps.trigger.event.body.image.filename}`)
);
```

#### Example: Upload image to your own Amazon S3 bucket

[This workflow](https://pipedream.com/@dylburger/example-save-uploaded-file-to-amazon-s3-p_o7Cm9z/edit) streams the uploaded file to an Amazon S3 bucket you specify, allowing you to save the file to long-term storage.

#### Limits

Since large files are uploaded using a `Content-Type` of `multipart/form-data`, the limits that apply to [form data](/workflows/building-workflows/triggers/#how-pipedream-handles-multipartform-data) also apply here.

The content of the file itself does not contribute to the HTTP payload limit imposed for forms. **You can upload files up to 5TB in size**. However, files that large may trigger [other Pipedream limits](/workflows/limits/). Please [reach out](https://pipedream.com/support/) with any specific questions or issues.

### Cross-Origin HTTP Requests

We return the following headers on HTTP `OPTIONS` requests:

```http theme={null}
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET,HEAD,PUT,PATCH,POST,DELETE
```

Thus, your endpoint will accept [cross-origin HTTP requests](https://developer.mozilla.org/en-US/Web/HTTP/CORS) from any domain, using any standard HTTP method.

### HTTP Responses

#### Default HTTP response

By default, when you send a [valid HTTP request](/workflows/building-workflows/triggers/#valid-requests) to your endpoint URL, you should expect to receive a `200 OK` status code with the following payload:

```html theme={null}
<p><b>Success!</b></p>
<p>To customize this response, check out our docs <a href="https://docs.pipedream.com/workflows/steps/triggers/#http-responses">here</a></p>
```

When you’re processing HTTP requests, you often don’t need to issue any special response to the client. We issue this default response so you don’t have to write any code to do it yourself.

<Note>
  **How can my workflow run faster?**

  See [our guide on running workflows faster](/troubleshooting/#how-can-my-workflow-run-faster).
</Note>

#### Customizing the HTTP response

If you need to issue a custom HTTP response from a workflow, you can either:

* Use the **Return HTTP response** action, available on the **HTTP / Webhook** app, or
* **Use the `$.respond()` function in a Code or Action step**.

#### Using the HTTP Response Action

The HTTP Response action lets you return HTTP responses without the need to write code. You can customize the response status code, and optionally specify response headers and body.

This action uses `$.respond()` and will always [respond immediately](/workflows/building-workflows/triggers/#returning-a-response-immediately) when called in your workflow. A [response error](/workflows/building-workflows/triggers/#errors-with-http-responses) will still occur if your workflow throws an Error before this action runs.

#### Using custom code with `$.respond()`

You can return HTTP responses in Node.js code with the `$.respond()` function.

`$.respond()` takes a single argument: an object with properties that specify the body, headers, and HTTP status code you’d like to respond with:

```javascript theme={null}
defineComponent({
  async run({ steps, $ }) {
    await $.respond({
      status: 200,
      headers: { "my-custom-header": "value" },
      body: { message: "My custom response" }, // This can be any string, object, Buffer, or Readable stream
    });
  },
});
```

The value of the `body` property can be either a string, object, a [Buffer](https://nodejs.org/api/buffer.html#buffer_buffer) (binary data), or a [Readable stream](https://nodejs.org/api/stream.html#stream_readable_streams). Attempting to return any other data may yield an error.

In the case where you return a Readable stream:

* You must `await` the `$.respond` function (`await $.respond({ ... }`)
* The stream must close and be finished reading within your [workflow execution timeout](/workflows/limits/#time-per-execution).
* You cannot return a Readable and use the [`immediate: true`](/workflows/building-workflows/triggers/#returning-a-response-immediately) property of `$.respond`.

#### Timing of `$.respond()` execution

You may notice some response latency calling workflows that use `$.respond()` from your HTTP client. By default, `$.respond()` is called at the end of your workflow, after all other code is done executing, so it may take some time to issue the response back.

If you need to issue an HTTP response in the middle of a workflow, see the section on [returning a response immediately](/workflows/building-workflows/triggers/#returning-a-response-immediately).

#### Returning a response immediately

You can issue an HTTP response within a workflow, and continue the rest of the workflow execution, by setting the `immediate` property to `true`:

```javascript theme={null}
defineComponent({
  async run({ steps, $ }) {
    await $.respond({
      immediate: true,
      status: 200,
      headers: { "my-custom-header": "value" },
      body: { message: "My custom response" },
    });
  },
});
```

Passing `immediate: true` tells `$.respond()` to issue a response back to the client at this point in the workflow. After the HTTP response has been issued, the remaining code in your workflow runs.

This can be helpful, for example, when you’re building a Slack bot. When you send a message to a bot, Slack requires a `200 OK` response be issued immediately, to confirm receipt:

```javascript theme={null}
defineComponent({
  async run({ steps, $ }) {
    await $.respond({
      immediate: true,
      status: 200,
      body: "",
    });
  },
});
```

Once you issue the response, you’ll probably want to process the message from the user and respond back with another message or data requested by the user.

[Here’s an example workflow](https://pipedream.com/@dylburger/issue-http-response-immediately-continue-running-workflow-p_pWCWGJ) that shows how to use `immediate: true` and run code after the HTTP response is issued.

#### Errors with HTTP Responses

If you use `$.respond()` in a workflow, **you must always make sure `$.respond()` is called in your code**. If you make an HTTP request to a workflow, and run code where `$.respond()` is *not* called, your endpoint URL will issue a `400 Bad Request` error with the following body:

```txt theme={null}
No $.respond called in workflow
```

This might happen if:

* You call `$.respond()` conditionally, where it does not run under certain conditions.
* Your workflow throws an Error before you run `$.respond()`.
* You return data in the `body` property that isn’t a string, object, or Buffer.

If you can’t handle the `400 Bad Request` error in the application calling your workflow, you can implement `try` / `finally` logic to ensure `$.respond()` always gets called with some default message. For example:

```javascript theme={null}
defineComponent({
  async run({ steps, $ }) {
    try {
      // Your code here that might throw an exception or not run
      throw new Error("Whoops, something unexpected happened.");
    } finally {
      await $.respond({
        status: 200,
        body: {
          msg: "Default response",
        },
      });
    }
  },
});
```

### Errors

Occasionally, you may encounter errors when sending requests to your endpoint:

#### Request Entity Too Large

The endpoint will issue a `413 Payload Too Large` status code when the body of your request exceeds {PAYLOAD_SIZE_LIMIT}.

In this case, the request will still appear in the inspector, with information on the error.

#### API key does not exist

Your API key is the host part of the endpoint, e.g. the `eniqtww30717` in `eniqtww30717.m.pipedream.net`. If you attempt to send a request to an endpoint that does not exist, we’ll return a `404 Not Found` error.

We’ll also issue a 404 response on workflows with an HTTP trigger that have been disabled.

#### Too Many Requests

If you send too many requests to your HTTP source within a small period of time, we may issue a `429 Too Many Requests` response. [Review our limits](/workflows/limits/) to understand the conditions where you might be throttled.

You can also [reach out](https://pipedream.com/support/) to inquire about raising this rate limit.

If you control the application sending requests, you should implement [a backoff strategy](https://medium.com/clover-platform-blog/conquering-api-rate-limiting-dcac5552714d) to temporarily slow the rate of events.

## Schedule

Pipedream allows you to run hosted scheduled jobs — commonly-referred to as a “cron job” — [for free](/pricing/). You can think of workflows like scripts that run on a schedule.

You can write scheduled job to send an HTTP request, send a scheduled email, run any Node.js or Python code, connect to any API, and much more. Pipedream manages the servers where these jobs run, so you don’t have to worry about setting up a server of your own or operating some service just to run code on a schedule. You write the workflow, we take care of the rest.

### Choosing a Schedule trigger

To create a new scheduled job, create a new workflow and search for the **Schedule** trigger:

<Frame>
  <img src="https://mintcdn.com/pipedream/nKh6d_6A4aXFb6xD/images/e1e437d8-image.png?fit=max&auto=format&n=nKh6d_6A4aXFb6xD&q=85&s=245954109b33c2b7c038d7cf742a7920" width="453" height="361" data-path="images/e1e437d8-image.png" />
</Frame>

By default, your trigger will be turned **Off**. **To enable it, select either of the scheduling options**:

* **Every** : run the job every N days, hours, minutes (e.g. every 1 day, every 3 hours).
* **Cron Expression** : schedule your job using a cron expression. For example, the expression `0 0 * * *` will run the job every day at midnight. Cron expressions can be tied to any timezone.

### Testing a scheduled job

If you’re running a scheduled job once a day, you probably don’t want to wait until the next day’s run to test your new code. You can manually run the workflow associated with a scheduled job at any time by pressing the **Run Now** button.

### Job History

You’ll see the history of job executions under the **Job History** section of the [Inspector](/workflows/building-workflows/inspect/).

Clicking on a specific job shows the execution details for that job — all the logs and observability associated with that run of the workflow.

### Trigger a notification to an external service (email, Slack, etc.)

You can send yourself a notification — for example, an email or a Slack message — at any point in a workflow by using the relevant [Action](/components/contributing/#actions) or [Destination](/workflows/data-management/destinations/).

If you’d like to email yourself when a job finishes successfully, you can use the [Email Destination](/workflows/data-management/destinations/email/). You can send yourself a Slack message using the Slack Action, or trigger an [HTTP request](/workflows/data-management/destinations/http/) to an external service.

You can also [write code](/workflows/building-workflows/code/) to trigger any complex notification logic you’d like.

### Troubleshooting your scheduled jobs

When you run a scheduled job, you may need to troubleshoot errors or other execution issues. Pipedream offers built-in, step-level logs that show you detailed execution information that should aid troubleshooting.

Any time a scheduled job runs, you’ll see a new execution appear in the [Inspector](/workflows/building-workflows/inspect/). This shows you when the job ran, how long it took to run, and any errors that might have occurred. **Click on any of these lines in the Inspector to view the details for a given run**.

Code steps show [logs](/workflows/building-workflows/code/nodejs/#logs) below the step itself. Any time you run `console.log()` or other functions that print output, you should see the logs appear directly below the step where the code ran.

[Actions](/components/contributing/#actions) and [Destinations](/workflows/data-management/destinations/) also show execution details relevant to the specific Action or Destination. For example, when you use the [HTTP Destination](/workflows/data-management/destinations/http/) to make an HTTP request, you’ll see the HTTP request and response details tied to that Destination step:

## Email

When you select the **Email** trigger:

<Frame>
  <img src="https://mintcdn.com/pipedream/grEzwYhEB2vZSwGw/images/9322523d-image.png?fit=max&auto=format&n=grEzwYhEB2vZSwGw&q=85&s=be819c7ed18bcc7010cae3a51a1c82dc" width="1371" height="351" data-path="images/9322523d-image.png" />
</Frame>

Pipedream creates an email address specific to your workflow. Any email sent to this address triggers your workflow:

<Frame>
  <img src="https://mintcdn.com/pipedream/Acz4Z1ch6TM7-aI8/images/9cadf478-image.png?fit=max&auto=format&n=Acz4Z1ch6TM7-aI8&q=85&s=ab2f15dd54dfc26f8f2f4b3f16a7398b" width="741" height="260" data-path="images/9cadf478-image.png" />
</Frame>

As soon as you send an email to the workflow-specific address, Pipedream parses its body, headers, and attachments into a JavaScript object it exposes in the `steps.trigger.event` variable that you can access within your workflow. This transformation can take a few seconds to perform. Once done, Pipedream will immediately trigger your workflow with the transformed payload.

[Read more about the shape of the email trigger event](/workflows/building-workflows/triggers/#email).

### Sending large emails

By default, you can send emails up to {EMAIL_PAYLOAD_SIZE_LIMIT} in total size (content, headers, attachments). Emails over this size will be rejected, and you will not see them appear in your workflow.

**You can send emails up to `{EMAIL_PAYLOAD_SIZE_LIMIT}` in size by sending emails to `[YOUR EMAIL ENDPOINT]@upload.pipedream.net`**. If your workflow-specific email address is `endpoint@pipedream.net`, your “large email address” is `endpoint@upload.pipedream.net`.

Emails delivered to this address are uploaded to a private URL you have access to within your workflow, at the variable `steps.trigger.event.mail.content_url`. You can download and parse the email within your workflow using that URL. This content contains the *raw* email. Unlike the standard email interface, you must parse this email on your own - see the examples below.

#### Example: Download the email using the Send HTTP Request action

*Note: you can only download emails at most {FUNCTION_PAYLOAD_LIMIT} in size using this method. Otherwise, you may encounter a [Function Payload Limit Exceeded](/troubleshooting/#function-payload-limit-exceeded) error.*

You can download the email using the **Send HTTP Request** action. [Copy this workflow to see how this works](https://pipedream.com/new?h=tch_1AfMyl).

This workflow also parses the contents of the email and exposes it as a JavaScript object using the [`mailparser` library](https://nodemailer.com/extras/mailparser/):

```javascript theme={null}
import { simpleParser } from "mailparser";
 
export default defineComponent({
  async run({ steps, $ }) {
    return await simpleParser(steps.get_large_email_content.$return_value);
  },
});
```

#### Example: Download the email to the `/tmp` directory, read it and parse it

[This workflow](https://pipedream.com/new?h=tch_jPfaEJ) downloads the email, saving it as a file to the [`/tmp` directory](/workflows/building-workflows/code/nodejs/working-with-files/#the-tmp-directory). Then it reads the same file (as an example), and parses it using the [`mailparser` library](https://nodemailer.com/extras/mailparser/):

```javascript theme={null}
import stream from "stream";
import { promisify } from "util";
import fs from "fs";
import got from "got";
import { simpleParser } from "mailparser";
 
// To use previous step data, pass the `steps` object to the run() function
export default defineComponent({
  async run({ steps, $ }) {
    const pipeline = promisify(stream.pipeline);
    await pipeline(
      got.stream(steps.trigger.event.mail.content_url),
      fs.createWriteStream(`/tmp/raw_email`)
    );
 
    // Now read the file and parse its contents into the `parsed` variable
    // See https://nodemailer.com/extras/mailparser/ for parsing options
    const f = fs.readFileSync(`/tmp/raw_email`);
    return await simpleParser(f);
  },
});
```

#### How the email is saved

Your email is saved to a Pipedream-owned [Amazon S3 bucket](https://aws.amazon.com/s3/). Pipedream generates a [signed URL](https://docs.aws.amazon.com/AmazonS3/latest/dev/ShareObjectPreSignedURL.html) that allows you to access to that file for up to 30 minutes. After 30 minutes, the signed URL will be invalidated, and the file will be deleted.

### Email attachments

You can attach any files to your email, up to [the total email size limit](/workflows/limits/#email-triggers).

Attachments are stored in `steps.trigger.event.attachments`, which provides an array of attachment objects. Each attachment in that array exposes key properties:

* `contentUrl`: a URL that hosts your attachment. You can [download this file to the `/tmp` directory](/workflows/building-workflows/code/nodejs/http-requests/#download-a-file-to-the-tmp-directory) and process it in your workflow.
* `content`: If the attachment contains text-based content, Pipedream renders the attachment in `content`, up to 10,000 bytes.
* `contentTruncated`: `true` if the attachment contained text-based content larger than 10,000 bytes. If `true`, the data in `content` will be truncated, and you should fetch the full attachment from `contentUrl`.

### Appending metadata to the incoming email address with `+data`

Pipedream provides a way to append metadata to incoming emails by adding a `+` sign to the incoming email key, followed by any arbitrary string:

```txt theme={null}
myemailaddr+test@pipedream.net
```

Any emails sent to your workflow-specific email address will resolve to that address, triggering your workflow, no matter the data you add after the `+` sign. Sending an email to both of these addresses triggers the workflow with the address `myemailaddr@pipedream.net`:

```txt theme={null}
myemailaddr+test@pipedream.net
myemailaddr+unsubscribe@pipedream.net
```

This allows you implement conditional logic in your workflow based on the data in that string.

### Troubleshooting

#### I’m receiving an `Expired Token` error when trying to read an email attachment

Email attachments are saved to S3, and are accessible in your workflows over [pre-signed URLs](https://docs.aws.amazon.com/AmazonS3/latest/userguide/ShareObjectPreSignedURL.html).

If the presigned URL for the attachment has expired, then you’ll need to send another email to create a brand new pre-signed URL.

If you’re using email attachments in combination with [`$.flow.delay`](/workflows/building-workflows/code/nodejs/delay/) or [`$.flow.rerun`](/workflows/building-workflows/code/nodejs/rerun/) which introduces a gap of time between steps in your workflow, then there’s a chance the email attachment’s URL will expire.

To overcome this, we suggest uploading your email attachments to your Project’s [File Store](/workflows/data-management/file-stores/) for persistent storage.

## RSS

Choose the RSS trigger to watch an RSS feed for new items:

<Frame>
  <img src="https://mintcdn.com/pipedream/nKh6d_6A4aXFb6xD/images/f59f9ad8-image.png?fit=max&auto=format&n=nKh6d_6A4aXFb6xD&q=85&s=9b55218ba660b80be893118e1a2da4dd" width="1341" height="344" data-path="images/f59f9ad8-image.png" />
</Frame>

This will create an RSS [event source](/workflows/building-workflows/triggers/) that polls the feed for new items on the schedule you select. Every time a new item is found, your workflow will run.

## Events

Events trigger workflow executions. The event that triggers your workflow depends on the trigger you select for your workflow:

* [HTTP triggers](/workflows/building-workflows/triggers/#http) invoke your workflow on HTTP requests.
* [Cron triggers](/workflows/building-workflows/triggers/#schedule) invoke your workflow on a time schedule (e.g., on an interval).
* [Email triggers](/workflows/building-workflows/triggers/#email) invoke your workflow on inbound emails.
* [Event sources](/workflows/building-workflows/triggers/#app-based-triggers) invoke your workflow on events from apps like Twitter, Google Calendar, and more.

### Selecting a test event

When you test any step in your workflow, Pipedream passes the test event you select in the trigger step:

<Frame>
  <img src="https://mintcdn.com/pipedream/xnRKrRxEtt3vxd6I/images/ddf5c7f5-image.png?fit=max&auto=format&n=xnRKrRxEtt3vxd6I&q=85&s=0f3dcea62057483087ec69a9d7392b4d" width="750" height="468" data-path="images/ddf5c7f5-image.png" />
</Frame>

You can select any event you’ve previously sent to your trigger as your test event, or send a new one.

### Examining event data

When you select an event, you’ll see [the incoming event data](/workflows/building-workflows/triggers/#event-format) and the [event context](/workflows/building-workflows/triggers/#stepstriggercontext) for that event:

<Frame>
  <img src="https://mintcdn.com/pipedream/NF77kliJSewMqg65/images/28fc1516-CleanShot_2022-03-31_at_16.30.37_jwwwdy.png?fit=max&auto=format&n=NF77kliJSewMqg65&q=85&s=2b470b930bf446962cd34a40df0b15e0" width="508" height="295" data-path="images/28fc1516-CleanShot_2022-03-31_at_16.30.37_jwwwdy.png" />
</Frame>

Pipedream parses your incoming data and exposes it in the variable [`steps.trigger.event`](/workflows/building-workflows/triggers/#event-format), which you can access in any [workflow step](/workflows/#steps).

### Copying references to event data

When you’re [examining event data](/workflows/building-workflows/triggers/#examining-event-data), you’ll commonly want to copy the name of the variable that points to the data you need to reference in another step.

Hover over the property whose data you want to reference, and click the **Copy Path** button to its right:

<Frame>
  <img src="https://mintcdn.com/pipedream/nKh6d_6A4aXFb6xD/images/f94a0e4e-CleanShot_2022-03-31_at_16.39.56_lsus2o.gif?s=8376b5edb14407360063577ea95d911c" width="508" height="296" data-path="images/f94a0e4e-CleanShot_2022-03-31_at_16.39.56_lsus2o.gif" />
</Frame>

### Copying the values of event data

You can also copy the value of specific properties of your event data. Hover over the property whose data you want to copy, and click the **Copy Value** button to its right:

<Frame>
  <img src="https://mintcdn.com/pipedream/Acz4Z1ch6TM7-aI8/images/bc1c8e05-CleanShot_2022-03-31_at_16.41.02_xgzcsa.gif?s=32e3dcfb51c84e46a57f5d814f519dce" width="508" height="296" data-path="images/bc1c8e05-CleanShot_2022-03-31_at_16.41.02_xgzcsa.gif" />
</Frame>

### Event format

When you send an event to your workflow, Pipedream takes the trigger data — for example, the HTTP payload, headers, etc. — and adds our own Pipedream metadata to it.

**This data is exposed in the `steps.trigger.event` variable. You can reference this variable in any step of your workflow**.

You can reference your event data in any [code](/workflows/building-workflows/code/) or [action](/components/contributing/#actions) step. See those docs or the general [docs on passing data between steps](/workflows/#steps) for more information.

The specific shape of `steps.trigger.event` depends on the trigger type:

#### HTTP

| Property    | Description                                           |
| ----------- | ----------------------------------------------------- |
| `body`      | A string or object representation of the HTTP payload |
| `client_ip` | IP address of the client that made the request        |
| `headers`   | HTTP headers, represented as an object                |
| `method`    | HTTP method                                           |
| `path`      | HTTP request path                                     |
| `query`     | Query string                                          |
| `url`       | Request host + path                                   |

#### Cron Scheduler

| Property              | Description                                                                                     |
| --------------------- | ----------------------------------------------------------------------------------------------- |
| `interval_seconds`    | The number of seconds between scheduled executions                                              |
| `cron`                | When you’ve configured a custom cron schedule, the cron string                                  |
| `timestamp`           | The epoch timestamp when the workflow ran                                                       |
| `timezone_configured` | An object with formatted datetime data for the given execution, tied to the schedule’s timezone |
| `timezone_utc`        | An object with formatted datetime data for the given execution, tied to the UTC timezone        |

#### Email

We use Amazon SES to receive emails for the email trigger. You can find the shape of the event in the [SES docs](https://docs.aws.amazon.com/ses/latest/DeveloperGuide/receiving-email-notifications-contents.html).

### `steps.trigger.context`

`steps.trigger.event` contain your event’s **data**. `steps.trigger.context` contains *metadata* about the workflow and the execution tied to this event.

You can use the data in `steps.trigger.context` to uniquely identify the Pipedream event ID, the timestamp at which the event invoked the workflow, and more:

| Property           | Description                                                                                                                                                                                 |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `deployment_id`    | A globally-unique string representing the current version of the workflow                                                                                                                   |
| `emitter_id`       | The ID of the workflow trigger that emitted this event, e.g. the [event source](/workflows/building-workflows/triggers/) ID.                                                                |
| `id`               | A unique, Pipedream-provided identifier for the event that triggered this workflow                                                                                                          |
| `owner_id`         | The Pipedream-assigned [workspace ID](/workspaces/#finding-your-workspaces-id) that owns the workflow                                                                                       |
| `platform_version` | The version of the Pipedream execution environment this event ran on                                                                                                                        |
| `replay`           | A boolean, whether the event was replayed via the UI                                                                                                                                        |
| `trace_id`         | Holds the same value for all executions tied to an original event. [See below for more details](/workflows/building-workflows/triggers/#how-do-i-retrieve-the-execution-id-for-a-workflow). |
| `ts`               | The ISO 8601 timestamp at which the event invoked the workflow                                                                                                                              |
| `workflow_id`      | The workflow ID                                                                                                                                                                             |
| `workflow_name`    | The workflow name                                                                                                                                                                           |

#### How do I retrieve the execution ID for a workflow?

Pipedream exposes two identifies for workflow executions: one for the execution, and one for the “trace”.

`steps.trigger.context.id` should be unique for every execution of a workflow.

`steps.trigger.context.trace_id` will hold the same value for all executions tied to the same original event, e.g. if you have auto-retry enabled and it retries a workflow three times, the `id` will change, but the `trace_id` will remain the same. For example, if you call `$.flow.suspend()` on a workflow, we run a new execution after the suspend, so you’d see two total executions: `id` will be unique before and after the suspend, but `trace_id` will be the same.

You may notice other properties in `context`. These are used internally by Pipedream, and are subject to change.

### Event retention

On the Free and Basic plans, each workflow retains at most 100 events or 7 days of history.

* After 100 events have been processed, Pipedream will delete the oldest event data as new events arrive, keeping only the last 100 events.
* Or if an event is older than 7 days, Pipedream will delete the event data.

Other paid plans have longer retention. [See the pricing page](https://pipedream.com/pricing) for details.

Events are also stored in [event history](/workflows/event-history/) for up to 30 days, depending on your plan. [See the pricing page](https://pipedream.com/pricing) for the retention on your plan.

Events that are [delayed](/workflows/building-workflows/control-flow/delay/) or [suspended](/glossary/#suspend) are retained for the duration of the delay. After the delay, the workflow is executed, and the event data is retained according to the rules above.

<Note>
  For an extended history of events across all of your workflows, included processed events, with the ability to filter by status and time range, please see the [Event History](/workflows/event-history/).
</Note>

## Don’t see a trigger you need?

If you don’t see a trigger you’d like us to support, please [let us know](https://pipedream.com/support/).
