Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -1053,6 +1053,7 @@
"qstash/howto/multi-region",
"qstash/howto/local-development",
"qstash/howto/local-tunnel",
"qstash/howto/redact-fields",
"qstash/howto/signature",
"qstash/howto/delete-schedule",
"qstash/howto/reset-token",
Expand Down Expand Up @@ -1286,6 +1287,7 @@
"workflow/howto/configure",
"workflow/howto/cancel",
"workflow/howto/security",
"workflow/howto/redact-fields",
"workflow/howto/changes",
"workflow/howto/schedule",
"workflow/howto/use-webhooks",
Expand Down
Binary file added img/qstash/redact-logs.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/qstash/redact-schedules.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/qstash/redact-workflow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
132 changes: 132 additions & 0 deletions qstash/howto/redact-fields.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
---
title: "Redact Private Data"
description: "How to redact private data in your messages"
---

QStash messages can contain private data that you don't want visible in the Upstash Console, or API responses.

QStash allows you to redact specific fields so they appear as `REDACTED:<SHA256>` in the dashboard and API. The original values are still used when delivering messages to your endpoint. The SHA256 hash lets you verify the two data without revealing the original data.

To redact a field, pass the `redactFields` option when publishing a message.

Available options:
| Option | Description |
|--|--|
| body | Redact the body of the message |
| headers | Redact the headers of the message |
| headers[header_name] | Redact a specific header (e.g., `headers[Authorization]`) |

<Info>
Redaction is one-way. Once a field is redacted, the original value cannot be retrieved from the API or dashboard.
</Info>

<CodeGroup>
```typescript TypeScript
import { Client } from "@upstash/qstash";

const client = new Client({ token: "<QSTASH_TOKEN>" });

const res = await client.publishJSON({
url: "https://my-api...",
body: { hello: "world" },
redactFields: {
body: true,
header: ["Authorization"] // or `header: true` to redact all headers
},
});
```

```python Python
from qstash import QStash

client = QStash("<QSTASH_TOKEN>")
client.message.publish_json(
url="https://my-api...",
body={
"hello": "world",
},
redact_fields={
"body": True,
"header": ["Authorization"] // or `header: True` to redact all headers
},
)
```

```bash cURL
curl -XPOST \
-H 'Authorization: Bearer XXX' \
-H "Content-Type: application/json" \
-H "Upstash-Redact-Fields: body, header[Authorization]" \
-d '{ "hello": "world" }' \
'https://qstash.upstash.io/v2/publish/https://my-api...'
```
</CodeGroup>

<Frame caption="Logs of a message with `body` and header[My-Secret-Header] redacted">
<img src="/img/qstash/redact-logs.png" />
</Frame>

Redaction is configured per message, so you can redact different fields for different messages.

If a message fails and moves to the DLQ, the redacted fields remain redacted in the DLQ.
However, when you retry a DLQ message, QStash delivers the original values to your endpoint.

## Schedules

You can also redact fields in schedules. Pass the `redactFields` option when creating a schedule, and all messages produced by that schedule will have the specified fields redacted.
Schedule get and list endpoints also apply redaction, so private data won't appear in API responses or the dashboard.

<CodeGroup>
```typescript TypeScript
import { Client } from "@upstash/qstash";

const client = new Client({ token: "<QSTASH_TOKEN>" });
const res = await client.schedule.create({
name: "my-schedule",
cron: "0 * * * *",
url: "https://my-api...",
body: { hello: "world" },
redactFields: {
body: true,
header: ["Authorization"]
},
});
```

```python Python
from qstash import QStash

client = QStash("<QSTASH_TOKEN>")
client.schedule.create(
name="my-schedule",
cron="0 * * * *",
url="https://my-api...",
body={"hello": "world"},
redact_fields={
"body": True,
"header": ["Authorization"]
},
)
```

```shell cURL
curl -XPOST \
-H 'Authorization: Bearer XXX' \
-H "Content-type: application/json" \
-H "Upstash-Cron: * * * * *" \
-H "Upstash-Redact-Fields: body, header[Authorization]" \
-d '{ "hello": "world" }' \
'https://qstash.upstash.io/v2/schedules/https://example.com'
```
</CodeGroup>


<Frame caption="Schedule with body and header[My-Secret-Header] redacted">
<img src="/img/qstash/redact-schedules.png" />
</Frame>

<Warning>
When updating a redacted schedule via the dashboard or API, you must provide the original values for the redacted fields.

If you don't provide the original values, the redacted fields will be saved as `REDACTED:<SHA256>` — which is the hash value visible in the dashboard, not the original data.
</Warning>
63 changes: 61 additions & 2 deletions qstash/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -783,7 +783,28 @@ paths:
| Upstash-Failure-Callback-Timeout | Timeout for the callback request. Format is same as Upstash-Timeout header. |
| Upstash-Failure-Callback-Retries | Number of retries for the callback request. Default is same as original message retries. |
| Upstash-Failure-Callback-Retry-Delay | Retry delay for the callback request. Format is same as Upstash-Retry-Delay header. |


- name: Upstash-Redact-Fields
in: header
schema:
type: string
description: |
Comma-separated list of fields to redact from the schedule. Redacted fields appear as `REDACTED:<SHA256>` in the dashboard and API responses. The original values are still used when delivering messages to your endpoint.

All messages produced by this schedule will have the specified fields redacted. Schedule get and list endpoints also apply redaction, so private data won't appear in API responses or the dashboard.

Available options:
| Option | Description |
|--------|-------------|
| `body` | Redact the body of the message |
| `headers` | Redact all headers of the message |
| `header[header_name]` | Redact a specific header (e.g., `header[Authorization]`) |

Examples:
- `body`: Redact only the body
- `body, header[Authorization]`: Redact the body and the Authorization header
- `body, headers`: Redact both body and all headers

requestBody:
description: The raw request message passed to the endpoints as is
content:
Expand Down Expand Up @@ -1068,6 +1089,25 @@ paths:
| Upstash-Failure-Callback-Retries | Number of retries for the callback request. Default is same as original message retries. |
| Upstash-Failure-Callback-Retry-Delay | Retry delay for the callback request. Format is same as Upstash-Retry-Delay header. |

- name: Upstash-Redact-Fields
in: header
schema:
type: string
description: |
Comma-separated list of fields to redact from the message. Redacted fields appear as `REDACTED:<SHA256>` in the dashboard and API responses. The original values are still used when delivering messages to your endpoint.

Available options:
| Option | Description |
|--------|-------------|
| `body` | Redact the body of the message |
| `headers` | Redact all headers of the message |
| `header[header_name]` | Redact a specific header (e.g., `header[Authorization]`) |

Examples:
- `body`: Redact only the body
- `body, header[Authorization]`: Redact the body and the Authorization header
- `body, headers`: Redact both body and all headers

requestBody:
description: The raw request message passed to the endpoints as is
content:
Expand Down Expand Up @@ -1727,7 +1767,26 @@ paths:
| Upstash-Failure-Callback-Timeout | Timeout for the callback request. Format is same as Upstash-Timeout header. |
| Upstash-Failure-Callback-Retries | Number of retries for the callback request. Default is same as original message retries. |
| Upstash-Failure-Callback-Retry-Delay | Retry delay for the callback request. Format is same as Upstash-Retry-Delay header. |


- name: Upstash-Redact-Fields
in: header
schema:
type: string
description: |
Comma-separated list of fields to redact from the message. Redacted fields appear as `REDACTED:<SHA256>` in the dashboard and API responses. The original values are still used when delivering messages to your endpoint.

Available options:
| Option | Description |
|--------|-------------|
| `body` | Redact the body of the message |
| `headers` | Redact all headers of the message |
| `header[header_name]` | Redact a specific header (e.g., `header[Authorization]`) |

Examples:
- `body`: Redact only the body
- `body, header[Authorization]`: Redact the body and the Authorization header
- `body, headers`: Redact both body and all headers

requestBody:
description: The raw request message passed to the endpoints as is
content:
Expand Down
75 changes: 75 additions & 0 deletions workflow/howto/redact-fields.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
---
title: "Redact Private Data"
description: "How to redact private data in your workflow runs"
---

Workflow runs can contain private data that you don't want visible in the Upstash Console or API responses.

Upstash Workflow allows you to redact specific fields so they appear as `REDACTED:<SHA256>` in the dashboard and API. The original values are still used when delivering requests to your workflow endpoint. The SHA256 hash lets you verify the data without revealing the original values.

To redact fields, pass the `redactFields` option when triggering a workflow run.

Available options:
| Option | Description |
|--|--|
| body | Redact the body of the workflow steps |
| headers | Redact the headers of the workflow steps |
| headers[header_name] | Redact a specific header (e.g., `headers[Authorization]`) |

<Info>
Redaction is one-way. Once a field is redacted, the original value cannot be retrieved from the API or dashboard.
</Info>

<CodeGroup>
```typescript TypeScript
import { Client } from "@upstash/workflow";

const client = new Client({ token: "<QSTASH_TOKEN>" });

const { workflowRunId } = await client.trigger({
url: "https://my-app.com/api/workflow",
body: { hello: "world" },
redactFields: {
body: true,
header: ["Authorization"] // or `header: true` to redact all headers
},
});
```

```python Python
from upstash_workflow import Client

client = Client("<QSTASH_TOKEN>")
client.trigger(
url="https://my-app.com/api/workflow",
body={
"hello": "world",
},
redact_fields={
"body": True,
"header": ["Authorization"] // or `header: True` to redact all headers
},
)
```

```bash cURL
curl -XPOST \
-H 'Authorization: Bearer XXX' \
-H "Content-Type: application/json" \
-H "Upstash-Redact-Fields: body, header[Authorization]" \
-d '{ "hello": "world" }' \
'https://qstash.upstash.io/v2/publish/https://my-app.com/api/workflow'
```
</CodeGroup>

<Frame caption="Logs of a workflow run with `body` and header[My-Secret-Header] redacted">
<img src="/img/qstash/redact-workflow.png" />
</Frame>


Redaction is configured per workflow run, so you can redact different fields for different runs.

When `body` is redacted, the step outputs in the dashboard and API will show `REDACTED:<SHA256>` instead of the actual values. The workflow still executes with the original data.

If a workflow run fails and moves to the DLQ, the redacted fields remain redacted in the DLQ.
However, when you retry, resume or restart a workflow run from DLQ, Workflow delivers the original values to your endpoint.