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

# Amazon S3 setup

> Deliver mapping result files directly to an S3 bucket or any S3-compatible target (Cloudflare R2, MinIO, Backblaze B2).

An S3 delivery destination writes a result file to your bucket every time a mapping job completes. Files arrive in the format you configured (CSV, JSON, or XLSX) with a deterministic name based on the job's inventory ID and date.

## Prerequisites

* An AWS account with an S3 bucket already created.
* IAM credentials (access key + secret) or a role that grants the [minimum permissions](#iam-policy) below.

## IAM policy

Grant Mapping.Travel the minimum required permissions. The `s3:GetObject` and `s3:DeleteObject` actions are used only during the [connection test](/delivery-destinations/testing) to clean up the probe file — they are not exercised on delivery.

```json theme={null} theme={null}
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:DeleteObject"
      ],
      "Resource": "arn:aws:s3:::your-bucket/incoming/*"
    }
  ]
}
```

Replace `your-bucket` and `incoming/` with your actual bucket name and path prefix. The `Resource` ARN controls exactly which keys Mapping.Travel can write to.

<Note>
  Scope the resource to the prefix you configure as `pathPrefix` on the destination. Avoid granting access to `arn:aws:s3:::your-bucket/*` unless you intend Mapping.Travel to write to any key.
</Note>

## Create via the dashboard

1. Open **Developers → Delivery destinations → New destination**.
2. Choose **Amazon S3** as the type.
3. Fill in the bucket name, region, access key, secret key, and an optional path prefix.
4. Click **Test connection** — Mapping.Travel runs a `HeadBucket`, `PutObject`, and `DeleteObject` probe. Fix any errors before saving.
5. Click **Create**.

## Create via API

```bash theme={null} theme={null}
curl -X POST https://api.mapping.travel/api/v1/delivery-destinations \
  -H "X-API-Key: <your-token>" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "S3",
    "name": "Production S3 bucket",
    "s3": {
      "bucket": "acme-mapping-results",
      "region": "eu-west-1",
      "accessKeyId": "AKIAIOSFODNN7EXAMPLE",
      "secretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
      "pathPrefix": "incoming/"
    },
    "status": "ACTIVE"
  }'
```

<Warning>
  Pass IAM credentials with the minimum policy above. Do not use root account credentials or credentials that grant write access to more than the target prefix.
</Warning>

## Path prefix conventions

The `pathPrefix` field controls the key prefix for every delivered file. Set it to a folder path ending with `/`:

| `pathPrefix`         | Example key written                                         |
| -------------------- | ----------------------------------------------------------- |
| *(empty)*            | `mapping_results_INV-1234_2026-06-07.csv`                   |
| `incoming/`          | `incoming/mapping_results_INV-1234_2026-06-07.csv`          |
| `acme/prod/exports/` | `acme/prod/exports/mapping_results_INV-1234_2026-06-07.csv` |

The full key pattern is `{pathPrefix}mapping_results_{partnerInventoryId}_{yyyy-MM-dd}.{ext}`. See [File format](/delivery-destinations/file-format) for the complete column reference.

## S3-compatible targets

The `endpointUrl` field accepts any S3-compatible API endpoint, letting you use non-AWS targets without changing your workflow:

| Provider      | `endpointUrl` example                          |
| ------------- | ---------------------------------------------- |
| Cloudflare R2 | `https://<accountId>.r2.cloudflarestorage.com` |
| MinIO         | `http://minio.internal:9000`                   |
| Backblaze B2  | `https://s3.us-west-004.backblazeb2.com`       |
| Tigris        | `https://fly.storage.tigris.dev`               |

```bash theme={null} theme={null}
curl -X POST https://api.mapping.travel/api/v1/delivery-destinations \
  -H "X-API-Key: <your-token>" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "S3",
    "name": "R2 bucket",
    "s3": {
      "bucket": "acme-mapping-results",
      "region": "auto",
      "accessKeyId": "<r2-access-key-id>",
      "secretAccessKey": "<r2-secret-access-key>",
      "endpointUrl": "https://abc123.r2.cloudflarestorage.com",
      "pathPrefix": "incoming/"
    },
    "status": "ACTIVE"
  }'
```

<Note>
  For R2, set `region` to `"auto"`. For MinIO, use the region you configured in your MinIO deployment (often `"us-east-1"` for default installs).
</Note>

## Troubleshooting

<AccordionGroup>
  <Accordion title="NoSuchBucket — bucket not found">
    The bucket name in the destination config doesn't match an existing bucket in the configured region. Verify:

    * The bucket name is spelled correctly (S3 bucket names are case-sensitive).
    * The `region` field matches the bucket's actual region.
    * For S3-compatible targets, the `endpointUrl` points to the correct host and the bucket exists on that host.
  </Accordion>

  <Accordion title="AccessDenied — permission error">
    The IAM credentials don't have the required permissions. Steps to debug:

    1. Copy the IAM policy above and attach it to the IAM user or role.
    2. If using a path prefix, confirm the `Resource` ARN in the policy ends with `your-prefix/*` — not just `*`.
    3. Re-run the [connection test](/delivery-destinations/testing) (`POST /api/v1/delivery-destinations/{id}/test`) and check the `error` field in the response for the exact AWS error code.
  </Accordion>

  <Accordion title="SignatureDoesNotMatch — wrong credentials">
    The `accessKeyId` / `secretAccessKey` pair is invalid or has been rotated. Update the destination with fresh credentials using `PUT /api/v1/delivery-destinations/{id}`.
  </Accordion>

  <Accordion title="Files not appearing in expected prefix">
    If files land at the wrong key, check that `pathPrefix` ends with a `/`. A prefix of `incoming` (no trailing slash) produces keys like `incomingmapping_results_…`.
  </Accordion>
</AccordionGroup>
