Amazon S3
Each outbound message is written as one object. Use it for an archive, a data-lake landing zone, or for payloads too large for a queue. It works with Amazon S3 and with S3-compatible stores such as Cloudflare R2 or MinIO. Requires the Starter plan or above.
Settings
| Field | Required | Notes |
|---|---|---|
bucket | Yes | The bucket name |
region | No | e.g. eu-central-1 (default us-east-1). Use auto for R2. |
keyPrefix | No | e.g. hookbase/orders/. Letters, digits and / ! _ . * ' ( ) = -, with no empty, . or .. segments. |
endpoint | No | An S3-compatible endpoint (https://<account>.r2.cloudflarestorage.com). It must be public https. Leave it blank for AWS. |
accessKeyId / secretAccessKey | Yes | A key with the policy below (an R2 API token's S3 credentials for R2) |
Object layout
<keyPrefix>YYYY/MM/DD/<message id>.jsonThe date is the UTC date of the attempt. The extension follows the payload's content type (.json, .xml, .txt, or .bin). A retry of the same message overwrites the same key, so each message is written once.
The object's Content-Type is the payload's, and the signature attributes are user metadata: x-amz-meta-webhook-id, x-amz-meta-webhook-timestamp, x-amz-meta-webhook-signature, x-amz-meta-hookbase-event-type.
IAM policy
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::acme-webhooks/hookbase/orders/*"
}
]
}If the bucket uses SSE-KMS with a customer-managed key, also allow kms:GenerateDataKey on that key.
Verifying
import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';
const obj = await s3.send(new GetObjectCommand({ Bucket: 'acme-webhooks', Key: key }));
const body = await obj.Body.transformToString();
const m = obj.Metadata; // keys without the x-amz-meta- prefix
wh.verify(body, {
'webhook-id': m['webhook-id'],
'webhook-timestamp': m['webhook-timestamp'],
'webhook-signature': m['webhook-signature'],
});AccessDenied, NoSuchBucket and other 4xx errors are permanent and the message is dead-lettered. SlowDown, 5xx and network errors are retried.