---
title: "Keep original source columns with recipients"
method: POST
path: "/campaigns/{id}/distribution/imports"
tags: ["Gift links"]
---

# Keep original source columns with recipients

`POST /campaigns/{id}/distribution/imports`

## Request

- Base URL: `https://gtmswag.com/api/v1`
- URL: `https://gtmswag.com/api/v1/campaigns/{id}/distribution/imports`
- Auth: one of:
  - HTTP bearer
  - OAuth 2 (authorization code, authorization URL `https://gtmswag.com/oauth/authorize`, token URL `https://gtmswag.com/oauth/token`, scopes: `gifts:write`)

Keeps only the columns you select (`retainedColumnIndices`) from the original CSV, linked to recipients by `importRowId` (and `recipientId`), so exports can return the customer's own columns. Rows may arrive across several calls; replays with identical rows are no-ops. No gifts, messages or charges. Accepts an MCP OAuth token with `gifts:write`.

## Path parameters

- `id` string, required

## Request body

- object
  - `importId` string, required: Stable customer import ID; reuse with identical retry data.
  - `headers` string[], required: Original source CSV headers in order, including duplicates.
  - `retainedColumnIndices` integer[], required: Original zero-based positions explicitly selected for private retention.
  - `rows` object[], required: Source rows linked by stable importRowId and recipientId; preserve original order and cells.
    - `importRowId` string, required: Stable source row ID within an import.
    - `recipientId` string: Stable workspace recipient ID; never infer from a name.
    - `position` integer, required: Original zero-based row position in the import.
    - `cells` string[], required: Original untrimmed source cell values, aligned with headers.
    - `error` string: Validation error for an unmatched source row; no link will be assigned.
  - `totalRows` integer, required: Total source rows, at most 500; do not truncate.
  - `sourceBytes` integer, required: Original CSV bytes, at most 5 MiB.

## Response `200`

Success: `{"data": SourceImport}`.

- SourceImportResponse: The success body: `{"data": SourceImport}`.
  - `data` SourceImport, required: Original source columns kept with a campaign's recipients for exports.
    - `importId` string, required
    - `headers` string[], required
    - `retainedColumnIndices` integer[], required
    - `totalRows` integer, required
    - `complete` boolean, required

## Other responses

- `400`: Bad request: `VALIDATION_ERROR`, `INVALID_REQUEST`, `INVALID_JSON`. Each example says when.
- `401`: Not authenticated: `AUTH_REQUIRED`. no credentials, or an OAuth token on a route that only takes workspace keys; the key is malformed, unknown or revoked.
- `403`: Forbidden: `INSUFFICIENT_SCOPE`, `DEMO_LIMITED`. Each example says when.
- `404`: Not found: `NOT_FOUND`. Each example says when.
- `409`: Conflict: `IMPORT_CONFLICT`, `IMPORT_RECIPIENT_MISMATCH`. Each example says when.
- `413`: Request too large: `IMPORT_ROW_LIMIT`, `IMPORT_SIZE_LIMIT`, `INVALID_REQUEST`. Each example says when.
- `415`: Unsupported media type: `INVALID_REQUEST`. a write with a body that is not `Content-Type: application/json` (a key request with no body needs no Content-Type).
- `429`: Too many requests: `RATE_LIMIT`. more than 240 requests in the current minute for this workspace (REST and MCP share the limit); wait `retryAfterMs`.
- `default`: Any other refusal or failure, such as 403 CSRF (a cross-origin `Origin` header), 403 HTTPS_REQUIRED or 500 INTERNAL_ERROR, with what to do next.

---

[API](https://skmtc.dev/gtmswag/apis/gtm-swag-api.md) · [All operations](https://skmtc.dev/gtmswag/apis/gtm-swag-api/llms.txt) · [OpenAPI document](https://skmtc.dev/gtmswag/apis/gtm-swag-api/revisions/9ff86fa99afe?raw)
