# Get a presigned upload URL for an opt-in proof screenshot (/docs/api/routing/toll-free-verification/presignTfvOptInImage)

> For the complete documentation index, see [llms.txt](https://docs.tandemcx.ai/llms.txt). Any page on this site can be fetched as Markdown by appending `.md` to its URL.

`POST /v1/sms-registration/opt-in-images`

Get a presigned upload URL for an opt-in proof screenshot

Mint a short-lived (5 minute) presigned S3 PUT URL for one opt-in proof image. Accepts image/png, image/jpeg, or image/webp, up to 5 MB.
The image is served only through signed CloudFront URLs, never a public one — store the returned key (in TfvBusinessProfile.optIn.images, as `{ kind: "upload", key }`), not a URL. previewUrl is a 1-hour signed URL for showing the just-uploaded image as a thumbnail; submission itself signs its own 90-day URL from the key at submit/resubmit time. See the PR that added this endpoint for why: Bandwidth's review can run for weeks, longer than any URL signed with the service's own short-lived credentials should stay valid, so a fixed key plus signing on demand is what keeps both the security posture and the review window intact.

## Request

**Base URL:** `https://api.tandemcx.ai`

**Authentication:** `Authorization: Bearer <token>` — A Tandem bearer token. Requests are scoped to the organization the token belongs to; no organization header is required.

### Body (`application/json`) — required

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `contentType` | enum: `image/png` \| `image/jpeg` \| `image/webp` | Yes | — |
| `contentLength` | integer | Yes | Size in bytes; rejected above 5 MB. |

## Responses

### 200 — The presigned upload URL, the object key, and a 1-hour preview URL.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `url` | string | Yes | PUT the image bytes here directly (not through this API). |
| `key` | string | Yes | The object key — store this in optIn.images, not a URL. |
| `previewUrl` | string | Yes | 1-hour signed URL for an immediate UI thumbnail. |

### 400 — The request was malformed.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `error` | object | No | — |
| `error.code` | string | No | — |
| `error.message` | string | No | — |

### 401 — Missing, malformed, or expired bearer token.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `error` | object | No | — |
| `error.code` | string | No | — |
| `error.message` | string | No | — |
