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

# Create a governed short link

> Requires a token with the `links:write` permission.



## OpenAPI

````yaml /openapi.json post /api/v1/links
openapi: 3.0.0
info:
  description: >-
    Every request carries `Authorization: Bearer utmk_…`. The token fixes the
    workspace; no request names one. Every operation declares `x-permission`,
    the token permission it requires.
  title: UTM Builder API
  version: '1'
servers:
  - url: https://app.utmkit.co
    variables: {}
security:
  - bearer: []
tags: []
paths:
  /api/v1/links:
    post:
      tags:
        - links
      summary: Create a governed short link
      description: Requires a token with the `links:write` permission.
      operationId: UtmBuilderWeb.API.V1.LinkController.create
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LinkInput'
        description: Link input
        required: true
      responses:
        '201':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LinkWithWarning'
          description: Link
        '409':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: Error
        '422':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: Error
        '429':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: Error
      callbacks: {}
components:
  schemas:
    LinkInput:
      properties:
        android_url:
          description: >-
            optional Android destination (spec 047): an app link or a Play page,
            https only; phones on Android are routed here, blank clears it
          nullable: true
          type: string
        campaign_id:
          nullable: true
          type: integer
        destination:
          format: uri
          nullable: true
          type: string
        domain:
          description: optional; a verified custom domain name, else the shared domain
          type: string
        expires_at:
          format: date-time
          nullable: true
          type: string
        ios_url:
          description: >-
            optional iOS destination (spec 047): an app link or an App Store
            page, https only; phones on iOS are routed here, blank clears it
          nullable: true
          type: string
        note:
          description: free text kept on the link; blank clears it
          nullable: true
          type: string
        short_code:
          description: optional; random when omitted
          type: string
        tags:
          description: >-
            tag names (spec 039): an existing tag of the workspace by name,
            case-insensitive, else a new one; on update the list replaces the
            link's tags and [] clears them
          items:
            type: string
          type: array
        utm_campaign:
          type: string
        utm_content:
          type: string
        utm_medium:
          type: string
        utm_source:
          type: string
        utm_term:
          type: string
        whatsapp_message:
          description: the prefilled message, plain text, never URL-encoded
          nullable: true
          type: string
        whatsapp_number:
          description: >-
            a WhatsApp click-to-chat link (issue #202): the phone in
            international format (+, spaces and dashes are stripped). Given
            INSTEAD of destination — the wa.me URL is composed and the message
            encoded once, server-side
          nullable: true
          type: string
      title: LinkInput
      type: object
    LinkWithWarning:
      allOf:
        - $ref: '#/components/schemas/Link'
        - properties:
            warning:
              description: governance warning when the convention warns rather than blocks
              nullable: true
              type: string
          type: object
      title: LinkWithWarning
    Error:
      description: Every refusal. `code` is the closed set of FR-019.
      properties:
        error:
          properties:
            code:
              enum:
                - unauthenticated
                - subscription_required
                - subscription_ended
                - missing_permission
                - role_forbids
                - plan_forbids
                - rate_limited
                - governance_refused
                - scanner_refused
                - limit_reached
                - duplicate_link
                - not_found
                - invalid_input
              type: string
            details:
              additionalProperties: true
              description: field → messages, on invalid_input
              nullable: true
              type: object
            message:
              type: string
            permission:
              nullable: true
              type: string
            retry_after_seconds:
              nullable: true
              type: integer
          required:
            - code
            - message
          type: object
      required:
        - error
      title: Error
      type: object
    Link:
      properties:
        android_url:
          nullable: true
          type: string
        campaign_id:
          nullable: true
          type: integer
        created_at:
          format: date-time
          type: string
        created_by:
          properties:
            api_token_id:
              nullable: true
              type: integer
            user_id:
              type: integer
          type: object
        destination:
          type: string
        expires_at:
          format: date-time
          nullable: true
          type: string
        id:
          type: integer
        ios_url:
          nullable: true
          type: string
        note:
          nullable: true
          type: string
        qr_url:
          description: the short URL with the scan marker
          format: uri
          type: string
        short_code:
          type: string
        short_url:
          format: uri
          type: string
        state:
          enum:
            - live
            - pending
            - blocked
            - expired
          type: string
        tags:
          description: the link's tags, by name without regard to case
          items:
            properties:
              color:
                enum:
                  - gray
                  - red
                  - orange
                  - amber
                  - green
                  - teal
                  - blue
                  - purple
                type: string
              name:
                type: string
            type: object
          type: array
        utm_campaign:
          nullable: true
          type: string
        utm_content:
          nullable: true
          type: string
        utm_medium:
          nullable: true
          type: string
        utm_source:
          nullable: true
          type: string
        utm_term:
          nullable: true
          type: string
      title: Link
      type: object
  securitySchemes:
    bearer:
      description: utmk_<lookup><secret>, minted on /tokens
      scheme: bearer
      type: http

````