openapi: 3.1.0
info:
  title: URLinks API
  version: "1.0"
  description: |
    The URLinks REST API. Create and manage shortlinks, generate styled QR codes,
    build link-in-bio profile pages, and track click analytics.

    All endpoints require a Bearer token (API key starting with `urk_`).
    Get your key from the URLinks dashboard Settings page.

    Also available as an MCP server for AI agents: `npx @urlinks/mcp-server`
  contact:
    email: admin@urlinks.me
  license:
    name: MIT

servers:
  - url: https://mkec635keeprfdasocc4st545y0eisjc.lambda-url.us-east-2.on.aws
    description: Production

security:
  - bearerAuth: []

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: API key starting with `urk_`

  schemas:
    Shortlink:
      type: object
      properties:
        shortlink:
          type: string
          example: my/docs
        url:
          type: string
          format: uri
          example: https://docs.google.com/document/d/abc123
        description:
          type: string
          example: Team documentation
        created_at:
          type: string
          format: date-time
        click_count:
          type: integer

    ClickAnalytics:
      type: object
      properties:
        shortlink:
          type: string
        total_clicks:
          type: integer
        unique_visitors:
          type: integer
        daily:
          type: array
          items:
            type: object
            properties:
              date:
                type: string
                format: date
              clicks:
                type: integer
        by_country:
          type: object
          additionalProperties:
            type: integer
        by_city:
          type: object
          additionalProperties:
            type: integer
        by_device:
          type: object
          additionalProperties:
            type: integer
        by_browser:
          type: object
          additionalProperties:
            type: integer
        by_os:
          type: object
          additionalProperties:
            type: integer
        by_referrer:
          type: object
          additionalProperties:
            type: integer

    QrConfig:
      type: object
      description: >-
        QR styling saved per shortlink. Field names match what the dashboard QR
        Studio writes, and /qr/image renders the full styling with the same engine
        the dashboard uses, so an API QR is identical to what QR Studio shows.
      properties:
        dotShape:
          type: string
          enum: [square, circle, rounded, classy, classy-rounded, diamond, star, heart, plus, hexagon, octagon, drop]
          description: Shape of the QR data dots
        cornerStyle:
          type: string
          enum: [square, rounded, circle, classy, classy-rounded, diamond, star, heart, plus, hexagon, octagon, drop]
          description: Shape of the corner finder markers (novelty shapes fill only the inner pip)
        outerShape:
          type: string
          enum: [none, square, circle, rounded]
          description: Frame drawn around the whole QR
        fgColor:
          type: string
          example: "#1A1F2E"
          description: Foreground (module) color as hex
        bgColor:
          type: string
          example: "#FFFDF7"
          description: Background color as hex
        transparent:
          type: boolean
          description: Transparent background (ignores bgColor)
        fgTransparent:
          type: boolean
          description: >-
            Transparent dots (data modules cut out, for overlaying on other
            images). Rendered on white in the dashboard preview; the PNG keeps
            real transparency.
        ecLevel:
          type: string
          enum: [L, M, Q, H]
          description: Error-correction level (default H; recommended with logo or styled shapes)
        useGradient:
          type: boolean
          description: Apply a linear gradient to the dots instead of a solid fgColor
        dotsGradient:
          $ref: "#/components/schemas/QrGradient"
        cornersGradient:
          $ref: "#/components/schemas/QrGradient"
        showLogo:
          type: boolean
          description: Embed a center logo
        useUrlinksLogo:
          type: boolean
          description: When showLogo is true, use the URLinks logo (else customLogo)
        customLogo:
          type: string
          format: uri
          description: Center logo image URL when useUrlinksLogo is false
        logoSize:
          type: integer
          description: Logo size as a percent of the QR (20–30)
        centerIcon:
          type: string
          enum: [square, circle, rounded, classy, classy-rounded, diamond, star, heart, plus, hexagon, octagon, drop, bolt, clover, shield, moon]
          description: >-
            Built-in center glyph rendered in the middle of the QR — a no-upload
            alternative to a logo. Any data shape, or an emblem
            (bolt/clover/shield/moon). Overrides showLogo when set.
        centerIconColor:
          type: string
          example: "#1A1F2E"
          description: Hex color for the center emblem (defaults to fgColor)
        dotImageUrl:
          type: string
          format: uri
          description: >-
            URL of a square PNG. When set, each QR module is colored by sampling
            this image at the module's position (e.g. a flag): white/pale regions
            are pulled to a scannable light grey, finder eyes are forced dark, on
            a white background. Overrides solid color and gradient.
        frame:
          type: string
          enum: [none, banner, badge, minimal]
          description: A "scan me" caption frame around the QR
        frameText:
          type: string
          description: Caption text for the frame (max 30 chars)

    QrTemplate:
      type: object
      description: A saved, reusable QR style the user can apply to any link.
      properties:
        id:
          type: string
        name:
          type: string
        config:
          $ref: "#/components/schemas/QrConfig"
        createdAt:
          type: integer
          description: Unix epoch milliseconds

    QrGradient:
      type: object
      properties:
        stop1:
          type: string
          description: Gradient start color (hex)
        stop2:
          type: string
          description: Gradient end color (hex)
        angle:
          type: integer
          description: Gradient angle in degrees (0–360)

    Profile:
      type: object
      description: Link-in-bio profile. page_style and blocks are stored as JSON; extra keys pass through.
      properties:
        username:
          type: string
        display_name:
          type: string
        bio:
          type: string
        avatar_url:
          type: string
          format: uri
        page_style:
          type: object
          description: Visual theme and layout. Key fields include backgroundColor, backgroundScene, backgroundGradient, backgroundTexture, defaultFontFamily, buttonStyle, headerLayout, profileLayout, socialIconStyle (brand|theme|outline), nameStrokeWidth, etc.
        blocks:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
              type:
                type: string
                enum: [link, header, text, divider, image, embed, spacer, marquee, gallery, social_icons, countdown, product]
              content:
                type: object
              style:
                type: object
                description: Per-block overrides — backgroundColor, backgroundGradient, animation, hoverEffect, etc.
        custom_styles:
          type: object
          description: AI/sanitized custom CSS keyed by concern (buttons, background, header, …)
        social_links:
          type: array
          items:
            type: object
            properties:
              platform:
                type: string
              url:
                type: string
        published:
          type: boolean
        view_count:
          type: integer

    Error:
      type: object
      properties:
        error:
          type: object
          properties:
            message:
              type: string
            status:
              type: integer
            code:
              type: string

paths:
  /v1/links:
    get:
      summary: List shortlinks
      description: Returns all shortlinks for the authenticated user, paginated.
      parameters:
        - name: limit
          in: query
          schema:
            type: integer
            default: 100
            maximum: 500
        - name: offset
          in: query
          schema:
            type: integer
            default: 0
      responses:
        "200":
          description: List of shortlinks
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/Shortlink"
                  total:
                    type: integer
                  has_more:
                    type: boolean

    post:
      summary: Create a shortlink
      description: Create a new shortlink mapping a short name to a destination URL.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [shortlink, url]
              properties:
                shortlink:
                  type: string
                  description: "Short name (e.g., my/docs, work/standup)"
                  example: my/docs
                url:
                  type: string
                  format: uri
                  description: Destination URL
                  example: https://docs.google.com/document/d/abc123
                description:
                  type: string
                  description: Optional description
                  example: Team documentation
      responses:
        "201":
          description: Shortlink created
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: "#/components/schemas/Shortlink"

  /v1/links/search:
    get:
      summary: Search shortlinks
      description: Search links by name, URL, or description.
      parameters:
        - name: q
          in: query
          required: true
          schema:
            type: string
          description: Search query
      responses:
        "200":
          description: Search results
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/Shortlink"

  /v1/links/{shortlink}:
    put:
      summary: Edit a shortlink
      description: Update the destination URL or description of a shortlink.
      parameters:
        - name: shortlink
          in: path
          required: true
          schema:
            type: string
          example: my/docs
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                url:
                  type: string
                  format: uri
                description:
                  type: string
      responses:
        "200":
          description: Shortlink updated
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: "#/components/schemas/Shortlink"

    delete:
      summary: Delete a shortlink
      description: Permanently delete a shortlink.
      parameters:
        - name: shortlink
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Shortlink deleted

  /v1/links/{shortlink}/clicks:
    get:
      summary: Get link analytics
      description: |
        Get click analytics for a shortlink including total clicks, unique visitors,
        daily breakdown, and breakdowns by country, city, device, browser, OS, and referrer.
      parameters:
        - name: shortlink
          in: path
          required: true
          schema:
            type: string
        - name: days
          in: query
          schema:
            type: integer
            default: 30
          description: Number of days of history
      responses:
        "200":
          description: Click analytics
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: "#/components/schemas/ClickAnalytics"

  /v1/links/{shortlink}/qr:
    get:
      summary: Get QR code config
      description: Get the saved QR code styling configuration for a shortlink.
      parameters:
        - name: shortlink
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: QR config
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: "#/components/schemas/QrConfig"

    put:
      summary: Save QR code config
      description: |
        Save styling for a shortlink's QR code. Supports custom colors,
        gradients, logo embedding, dot styles, and corner styles.
      parameters:
        - name: shortlink
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/QrConfig"
      responses:
        "200":
          description: QR config saved

  /v1/links/{shortlink}/qr/image:
    get:
      summary: Get QR code image
      description: Returns the QR code as an SVG or PNG image with saved styling applied.
      parameters:
        - name: shortlink
          in: path
          required: true
          schema:
            type: string
        - name: format
          in: query
          schema:
            type: string
            enum: [svg, png]
            default: svg
        - name: size
          in: query
          schema:
            type: integer
            default: 300
      responses:
        "200":
          description: QR code image
          content:
            image/svg+xml:
              schema:
                type: string
            image/png:
              schema:
                type: string
                format: binary

  /v1/bulk/links:
    post:
      summary: Bulk create shortlinks
      description: Create up to 50 shortlinks in a single request.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [links]
              properties:
                links:
                  type: array
                  maxItems: 50
                  items:
                    type: object
                    required: [shortlink, url]
                    properties:
                      shortlink:
                        type: string
                      url:
                        type: string
                        format: uri
                      description:
                        type: string
      responses:
        "201":
          description: Links created
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      created:
                        type: array
                        items:
                          $ref: "#/components/schemas/Shortlink"
                      errors:
                        type: array
                        items:
                          type: object

  /v1/profile:
    get:
      summary: Get your profile
      description: Get the authenticated user's link-in-bio profile.
      responses:
        "200":
          description: Profile data
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: "#/components/schemas/Profile"

  /v1/profile/publish:
    post:
      summary: Publish profile
      description: Make your link-in-bio profile publicly visible at urlinks.me/{username}.
      responses:
        "200":
          description: Profile published

  /v1/profile/custom-css:
    get:
      summary: Get custom CSS
      description: Get the custom CSS styles applied to your profile.
      responses:
        "200":
          description: Custom CSS
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object

    put:
      summary: Set custom CSS
      description: |
        Apply custom CSS to your profile page. Supports per-concern styling
        (background, buttons, header, cards, etc.) using .pc-* class selectors.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
      responses:
        "200":
          description: CSS updated

    delete:
      summary: Reset custom CSS
      description: Remove all custom CSS and revert to the theme defaults.
      responses:
        "200":
          description: CSS reset

  /v1/qr/templates:
    get:
      summary: List QR style templates
      description: Returns the user's saved, reusable QR style templates.
      responses:
        "200":
          description: List of templates
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      templates:
                        type: array
                        items:
                          $ref: "#/components/schemas/QrTemplate"
    post:
      summary: Save a QR style template
      description: Save a reusable QR style under a name. The style is applied to links via PUT /v1/links/{shortlink}/qr.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, config]
              properties:
                name:
                  type: string
                config:
                  $ref: "#/components/schemas/QrConfig"
      responses:
        "200":
          description: Template saved
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      template:
                        $ref: "#/components/schemas/QrTemplate"

  /v1/qr/templates/{id}:
    delete:
      summary: Delete a QR style template
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Template deleted
