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

# Create a short link

Use this endpoint to create a Joylink short link from a destination URL.

The API may apply affiliate rewrites before the short link is created, so the final destination is not always identical to the `destination` you send.

## Request body

* `destination` (required): URL to shorten.
* `trackingid` (optional): Explicit affiliate tracking value. For Amazon links, this always overrides any existing `tag` query parameter on the destination.
* `require_choices` (optional): When `true`, the API returns `409 choice_required` instead of using the default override behavior for supported conflicts.
* `choices` (optional): Map of choice ids to selected option ids. Use this when your integration already knows how it wants to resolve a conflict.
* `sub_id2` and `sub_id3` (optional): Impact SubID values. These are applied only when the final destination is an Impact affiliate URL. Omit a field to preserve an existing value, or send an empty string to clear it.

## Default behavior

When you do not send `require_choices: true`, the API resolves supported conflicts automatically:

1. The API starts with the `destination` you send.
2. If that destination is already an Impact affiliate link for a supported retailer, and your Joylink account has synced Impact tracking for that retailer, the API rewrites the link to use your tracking by default.
3. If the final destination is an Impact affiliate URL, `sub_id2` and `sub_id3` are applied after the Impact keep or override decision.
4. For Amazon URLs:
   * `trackingid` always wins and replaces any existing `tag`.
   * If `trackingid` is omitted, Joylink uses the Amazon tag configured in your Joylink user settings.
5. If the product has a Creator Connections campaign available, the API uses that Creator Connections link by default.
6. If there is no Creator Connections campaign, but a JL extra commission link is available, the API uses that extra commission link by default.

Creator Connections takes precedence over JL extra commission when both could apply.

## Choice required

When `require_choices` is `true`, the API returns a `409` response with a reusable `choice_required` envelope instead of taking the default override path.

The endpoint evaluates conflicts one at a time, in this order:

1. `impact_link_override`
2. `amazon_tag_override`
3. `creator_connections_link_override`
4. `jl_extra_commission_link_override`

If more than one conflict applies, re-send the same request with the returned choice populated in `choices`, and the API may return another `409` for the next conflict in the sequence.

Supported conflicts:

* An Impact affiliate link that would otherwise be rewritten to use your synced Impact tracking.
* An Amazon link whose existing `tag` differs from your Joylink user tag when `trackingid` is omitted.
* A product with an available Creator Connections campaign that would otherwise replace the original destination.
* A product with an available JL extra commission link that would otherwise replace the original destination.

`choice_required.options[].url` is included when the API can preview the resulting destination ahead of time. Keep options always include it. Override options for Creator Connections and JL extra commission may omit it.

Example Impact conflict:

```json theme={null}
{
  "choice_required": {
    "id": "impact_link_override",
    "prompt": "This link already uses an Impact affiliate tag. Choose whether to override it with your own affiliate tracking.",
    "documentation_url": "https://docs.joylink.io/create-a-short-link#choice-required",
    "options": [
      {
        "id": "override",
        "label": "Override with my affiliate tracking",
        "url": "https://goto.walmart.com/12345/..."
      },
      {
        "id": "keep",
        "label": "Keep the existing link",
        "url": "https://goto.walmart.com/54321/..."
      }
    ]
  }
}
```

For this Impact conflict:

* `override` replaces the existing Impact affiliate link with the affiliate tracking configured on your Joylink account.
* `keep` preserves the original affiliate destination instead of replacing it.

The `documentation_url` field points to this section so an integration can surface a helpful link when it receives the conflict.

Example Amazon conflict:

```json theme={null}
{
  "choice_required": {
    "id": "amazon_tag_override",
    "prompt": "This Amazon link already uses a different affiliate tag. Choose whether to override it with your own affiliate tracking.",
    "documentation_url": "https://docs.joylink.io/create-a-short-link#choice-required",
    "options": [
      {
        "id": "override",
        "label": "Override with my affiliate tracking",
        "url": "https://www.amazon.com/dp/B0TEST1234?tag=my-tag-20"
      },
      {
        "id": "keep",
        "label": "Keep the existing link",
        "url": "https://www.amazon.com/dp/B0TEST1234?tag=other-tag-20"
      }
    ]
  }
}
```

For this Amazon conflict:

* `override` replaces the existing Amazon `tag` with your Joylink user tag.
* `keep` preserves the original Amazon `tag` already present on the destination URL.

Example Creator Connections conflict:

```json theme={null}
{
  "choice_required": {
    "id": "creator_connections_link_override",
    "prompt": "This product has a Creator Connections campaign available. Choose whether to override the destination with the Creator Connections link.",
    "documentation_url": "https://docs.joylink.io/create-a-short-link#choice-required",
    "options": [
      {
        "id": "override",
        "label": "Override with Creator Connections"
      },
      {
        "id": "keep",
        "label": "Keep the existing link",
        "url": "https://www.amazon.com/dp/B0TEST1234?tag=my-tag-20"
      }
    ]
  }
}
```

For this Creator Connections conflict:

* `override` uses the Creator Connections link that would normally be applied for this product.
* `keep` preserves the original destination and skips the Creator Connections link rewrite.

Example JL extra commission conflict:

```json theme={null}
{
  "choice_required": {
    "id": "jl_extra_commission_link_override",
    "prompt": "This product has a JL extra commission link available. Choose whether to override the destination with the JL extra commission link.",
    "documentation_url": "https://docs.joylink.io/create-a-short-link#choice-required",
    "options": [
      {
        "id": "override",
        "label": "Override with JL extra commission link"
      },
      {
        "id": "keep",
        "label": "Keep the existing link",
        "url": "https://www.amazon.com/dp/B0TEST1234?tag=my-tag-20"
      }
    ]
  }
}
```

For this JL extra commission conflict:

* `override` uses the JL extra commission link that would normally be applied for this product.
* `keep` preserves the original destination and skips the extra commission link rewrite.

## Choose the behavior up front

If your integration already knows how it wants to handle this conflict, send the choice up front in the `choices` object.

Example request that uses the default override behavior:

```json theme={null}
{
  "destination": "https://goto.walmart.com/..."
}
```

Send an explicit override choice when you want to be fully declarative:

```json theme={null}
{
  "destination": "https://goto.walmart.com/...",
  "choices": {
    "impact_link_override": "override"
  }
}
```

To preserve the original affiliate destination instead, send:

```json theme={null}
{
  "destination": "https://goto.walmart.com/...",
  "choices": {
    "impact_link_override": "keep"
  }
}
```

For an Amazon link with no `trackingid`, preserve the existing Amazon tag with:

```json theme={null}
{
  "destination": "https://www.amazon.com/dp/B0TEST1234?tag=other-tag-20",
  "choices": {
    "amazon_tag_override": "keep"
  }
}
```

If a JL extra commission product is available and you want to keep the original destination, send:

```json theme={null}
{
  "destination": "https://www.amazon.com/dp/B0TEST1234?tag=my-tag-20",
  "choices": {
    "jl_extra_commission_link_override": "keep"
  }
}
```

If a Creator Connections campaign is available and you want to keep the original destination, send:

```json theme={null}
{
  "destination": "https://www.amazon.com/dp/B0TEST1234?tag=my-tag-20",
  "choices": {
    "creator_connections_link_override": "keep"
  }
}
```

To opt into the `409` flow, send:

```json theme={null}
{
  "destination": "https://goto.walmart.com/...",
  "require_choices": true
}
```


## OpenAPI

````yaml post /public/createlink
openapi: 3.1.0
info:
  title: Joylink API
  version: 1.0.0
  description: API for managing Joylink short links and tracking
servers:
  - url: https://api.joylink.io
    description: Production server
security: []
paths:
  /public/createlink:
    post:
      summary: Create a short link
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreatePublicLinkRequest'
            examples:
              default_override:
                summary: Default create request
                value:
                  destination: https://goto.walmart.com/...
              require_choices:
                summary: Opt in to `choice_required`
                value:
                  destination: https://www.amazon.com/dp/B0TEST1234?tag=other-tag-20
                  require_choices: true
              keep_existing_impact_destination:
                summary: Preserve an existing Impact affiliate destination
                value:
                  destination: https://goto.walmart.com/...
                  choices:
                    impact_link_override: keep
      responses:
        '200':
          description: Successfully created short link
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreatePublicLinkResponse'
              examples:
                success:
                  value:
                    url: https://joylink.io/abc123
        '400':
          description: >-
            Bad request. Returned for malformed JSON, missing `destination`, or
            invalid choice values such as a choice other than `override` or
            `keep`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: >-
            Choice required. Returned only when `require_choices` is `true` and
            the current request hits a supported conflict. Re-send the same
            request with the returned `choice_required.id` set in `choices` as
            `override` to accept Joylink's default rewrite or `keep` to preserve
            the original value or destination. If multiple conflicts apply, the
            endpoint may return another `409` for the next conflict after you
            resolve the first one.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChoiceRequiredResponse'
              examples:
                impact_conflict:
                  value:
                    choice_required:
                      id: impact_link_override
                      prompt: >-
                        This link already uses an Impact affiliate tag. Choose
                        whether to override it with your own affiliate tracking.
                      documentation_url: >-
                        https://docs.joylink.io/create-a-short-link#choice-required
                      options:
                        - id: override
                          label: Override with my affiliate tracking
                          url: >-
                            https://goto.walmart.com/c/99999/88888/77777?u=https%3A%2F%2Fwww.walmart.com%2Fip%2F123456789
                        - id: keep
                          label: Keep the existing link
                          url: >-
                            https://goto.walmart.com/c/12345/67890/13579?u=https%3A%2F%2Fwww.walmart.com%2Fip%2F123456789
        '429':
          $ref: '#/components/responses/RateLimitExceeded'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - ApiKeyAuth: []
components:
  schemas:
    CreatePublicLinkRequest:
      type: object
      required:
        - destination
      properties:
        destination:
          type: string
          description: >-
            URL to shorten. This is the starting destination before any
            affiliate rewrites are applied.
          example: https://www.amazon.com/dp/B0TEST1234?tag=other-tag-20
        trackingid:
          type: string
          description: >-
            Optional explicit affiliate tracking value. For Amazon links,
            sending this always overrides any existing `tag` query parameter on
            the destination.
          example: my-tag-20
        require_choices:
          type: boolean
          description: >-
            When `true`, the API returns `409 choice_required` instead of using
            the default override behavior for supported conflicts. Conflicts are
            evaluated one at a time in this order: `impact_link_override`,
            `amazon_tag_override`, `creator_connections_link_override`,
            `jl_extra_commission_link_override`.
          example: false
        sub_id2:
          type: string
          description: >-
            Optional Impact SubID2 value. Applied only when the final
            destination is an Impact affiliate URL. Omit to preserve an existing
            value, or send an empty string to clear it.
          example: campaign-42
        sub_id3:
          type: string
          description: >-
            Optional Impact SubID3 value. Applied only when the final
            destination is an Impact affiliate URL. Omit to preserve an existing
            value, or send an empty string to clear it.
          example: post-99
        choices:
          type: object
          description: >-
            Optional map of `choice_required` ids to selected option ids. Use
            `override` to accept Joylink's default rewrite, or `keep` to
            preserve the original value or destination for the returned
            conflict.
          additionalProperties:
            type: string
            enum:
              - override
              - keep
          example:
            impact_link_override: keep
    CreatePublicLinkResponse:
      type: object
      required:
        - url
      properties:
        url:
          type: string
          description: The generated short URL.
          example: https://joylink.io/abc123
    Error:
      type: object
      properties:
        error:
          type: string
        details:
          type: string
    ChoiceRequiredResponse:
      type: object
      required:
        - choice_required
      properties:
        choice_required:
          $ref: '#/components/schemas/ChoiceRequired'
    ChoiceRequired:
      type: object
      required:
        - id
        - prompt
        - documentation_url
        - options
      properties:
        id:
          type: string
          enum:
            - impact_link_override
            - amazon_tag_override
            - creator_connections_link_override
            - jl_extra_commission_link_override
          description: >-
            Stable choice identifier. Use this as the key in the request choices
            map.
          example: impact_link_override
        prompt:
          type: string
          description: Human-readable explanation of the conflict that must be resolved.
          example: >-
            This link already uses an Impact affiliate tag. Choose whether to
            override it with your own affiliate tracking.
        documentation_url:
          type: string
          description: >-
            Documentation page explaining why the conflict happened and how to
            resolve it.
          example: https://docs.joylink.io/create-a-short-link#choice-required
        options:
          type: array
          description: >-
            Supported option ids for this choice, including preview destinations
            when available.
          items:
            $ref: '#/components/schemas/ChoiceOption'
    ChoiceOption:
      type: object
      required:
        - id
        - label
      properties:
        id:
          type: string
          enum:
            - override
            - keep
          description: Stable option identifier to send back in the choices map.
          example: override
        label:
          type: string
          description: Human-readable label describing what this option will do.
          example: Override with my affiliate tracking
        url:
          type: string
          description: >-
            Preview destination URL for this option, when Joylink can determine
            it ahead of time.
          example: >-
            https://goto.walmart.com/c/12345/12345/12345?u=https%3A%2F%2Fwww.walmart.com%2Fip%2Fexample
  responses:
    RateLimitExceeded:
      description: >-
        Rate limit exceeded. Public API keys are limited to 60 requests per
        minute and 1440 requests per day, shared across endpoints.
      headers:
        X-RateLimit-Limit-Minute:
          description: Maximum requests allowed per minute.
          schema:
            type: integer
            example: 60
        X-RateLimit-Remaining-Minute:
          description: Requests remaining in the current minute window.
          schema:
            type: integer
            example: 0
        X-RateLimit-Reset-Minute:
          description: Seconds until the minute window resets.
          schema:
            type: integer
            example: 45
        X-RateLimit-Limit-Day:
          description: Maximum requests allowed per day.
          schema:
            type: integer
            example: 1440
        X-RateLimit-Remaining-Day:
          description: Requests remaining in the current day window.
          schema:
            type: integer
            example: 1200
        X-RateLimit-Reset-Day:
          description: Seconds until the day window resets.
          schema:
            type: integer
            example: 43200
        Retry-After:
          description: >-
            Seconds to wait before retrying. Matches the limit you hit (minute
            or day).
          schema:
            type: integer
            example: 45
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            minute_limit:
              summary: Per-minute limit exceeded
              value:
                error: >-
                  Rate limit exceeded. Maximum 60 requests per minute. Resets in
                  45s.
            day_limit:
              summary: Per-day limit exceeded
              value:
                error: >-
                  Rate limit exceeded. Maximum 1440 requests per day. Resets in
                  5h 20m.
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key

````