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

# Create join link

> Mint a reusable, co-branded signup link for one of your storefronts

`POST /api/v2/storefront/join-links`

Mints a join link for a storefront your organization owns. Advertisers who sign up through the link become [sponsored buyers](/v2/storefront/sponsored-buyers/overview) scoped to that storefront. The `approvalPolicy` you choose here decides whether those signups are admitted automatically or held for your review.

## Request

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.interchange.io/api/v2/storefront/join-links \
    -H "Authorization: Bearer $SCOPE3_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "storefrontId": 4012,
      "approvalPolicy": "manual_approve",
      "slug": "northwind-advertisers",
      "maxUses": 250,
      "expiresAt": "2026-12-31T23:59:59Z"
    }'
  ```

  ```json minimal theme={null}
  {
    "storefrontId": 4012
  }
  ```
</CodeGroup>

## Parameters

| Field            | Type    | Required | Notes                                                                                                           |
| ---------------- | ------- | -------- | --------------------------------------------------------------------------------------------------------------- |
| `storefrontId`   | integer | Yes      | The `storefront_config.id` the joining buyer is scoped to. Must belong to your organization.                    |
| `approvalPolicy` | enum    | No       | `auto_approve`, `manual_approve`, `invite_only`, or `closed`. Default `manual_approve`.                         |
| `slug`           | string  | No       | Custom handle (2–64 chars, lowercase letters, numbers, hyphens). Derived from the storefront name when omitted. |
| `expiresAt`      | string  | No       | ISO-8601 expiry. Omit for a link that never expires.                                                            |
| `maxUses`        | integer | No       | Cap on total successful signups (positive). Omit for unlimited.                                                 |

## Response

`201 Created` with the new `JoinLink`:

```json theme={null}
{
  "id": "5571",
  "slug": "northwind-advertisers",
  "joinPath": "/join/northwind-advertisers",
  "sellerCustomerId": 318,
  "storefrontId": 4012,
  "role": "BUYER",
  "posture": "prepay",
  "approvalPolicy": "manual_approve",
  "active": true,
  "uses": 0,
  "maxUses": 250,
  "expiresAt": "2026-12-31T23:59:59.000Z",
  "revokedAt": null,
  "createdAt": "2026-06-14T18:22:10.441Z",
  "updatedAt": "2026-06-14T18:22:10.441Z"
}
```

The buyer visits `joinPath` (`/join/{slug}`); your UI or agent prepends its own origin to form the full URL.

## Errors

* `400 VALIDATION_ERROR` — missing `storefrontId`, or an invalid `slug`, `approvalPolicy`, `expiresAt`, or `maxUses`.
* `401 UNAUTHORIZED` — missing or invalid API key.
* `403 CUSTOMER_ROLE_DENIED` — the API key is not a seller account; only sellers manage join links.
* `403 ACCESS_DENIED` — the `storefrontId` belongs to another organization.
* `404 NOT_FOUND` — no storefront with this `id` exists.
* `409 CONFLICT` — an active link with that `slug` already exists. Choose a different slug or disable the existing one.

See [Errors](/v2/reference/errors) for the full error contract.

## Related

<CardGroup cols={2}>
  <Card title="Join-link tasks" href="/v2/storefront/join-links/tasks" icon="list-check">
    All operations
  </Card>

  <Card title="List join links" href="/v2/storefront/join-links/tasks/list-join-links" icon="list">
    Every active link
  </Card>

  <Card title="Sponsored buyers" href="/v2/storefront/sponsored-buyers/overview" icon="handshake">
    Manage the buyers who joined
  </Card>

  <Card title="Errors" href="/v2/reference/errors" icon="triangle-exclamation">
    Shared error contract
  </Card>
</CardGroup>
