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

# List Your URLs

> List all URLs owned by the authenticated user.

Returns a paginated list of shortened URLs with support for filtering,
sorting, and full-text search on aliases and destination URLs.

**Authentication**: Required.

**API Key Scope**: `urls:manage`, `urls:read`, or `admin:all`

**Rate Limits**: 60/min, 5,000/day

**Pagination**: Use `page` and `pageSize` query params. Response includes
`hasNext` boolean and `total` count.

**Sorting**: Sort by `created_at`, `last_click`, or `total_clicks` in
ascending or descending order.

**Filtering**: Pass a JSON-encoded `filter` parameter with fields like
`status`, `createdAfter`, `createdBefore`, `passwordSet`, `maxClicksSet`,
and `search`.



## OpenAPI

````yaml /openapi-v1.json get /api/v1/urls
openapi: 3.1.0
info:
  title: spoo.me
  description: >-
    REST API for spoo.me — free and open-source URL shortening service serving
    400k+ redirects/day.


    Authenticate using either:

    - **API Key**: `Authorization: Bearer spoo_<your_key>`

    - **JWT Token**: `Authorization: Bearer <jwt>` (obtained via /auth/login)

    - **Session Cookie**: `access_token` cookie (set automatically on login)
  contact:
    name: spoo.me
    url: https://spoo.me/contact
    email: support@spoo.me
  license:
    name: AGPL-3.0
    url: https://github.com/spoo-me/spoo/blob/main/LICENSE
  version: 1.0.0
servers:
  - url: https://spoo.me
    description: Production
security:
  - ApiKeyAuth: []
  - JWTAuth: []
tags:
  - name: URL Shortening
    description: Create new shortened URLs
  - name: Link Management
    description: List, update, and delete your shortened URLs
  - name: Statistics
    description: Click analytics and data export
  - name: API Keys
    description: Create and manage API keys for programmatic access
  - name: Authentication
    description: Login, register, password management, and email verification
  - name: OAuth
    description: OAuth provider login, linking, and unlinking
  - name: System
    description: Health checks and server metrics
paths:
  /api/v1/urls:
    get:
      tags:
        - Link Management
      summary: List Your URLs
      description: >-
        List all URLs owned by the authenticated user.


        Returns a paginated list of shortened URLs with support for filtering,

        sorting, and full-text search on aliases and destination URLs.


        **Authentication**: Required.


        **API Key Scope**: `urls:manage`, `urls:read`, or `admin:all`


        **Rate Limits**: 60/min, 5,000/day


        **Pagination**: Use `page` and `pageSize` query params. Response
        includes

        `hasNext` boolean and `total` count.


        **Sorting**: Sort by `created_at`, `last_click`, or `total_clicks` in

        ascending or descending order.


        **Filtering**: Pass a JSON-encoded `filter` parameter with fields like

        `status`, `createdAfter`, `createdBefore`, `passwordSet`,
        `maxClicksSet`,

        and `search`.
      operationId: listUrls
      parameters:
        - name: page
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            description: 'Page number (default: 1)'
            examples:
              - 1
            default: 1
            title: Page
          description: 'Page number (default: 1)'
        - name: pageSize
          in: query
          required: false
          schema:
            type: integer
            maximum: 100
            minimum: 1
            description: 'Items per page (default: 20, max: 100)'
            examples:
              - 20
            default: 20
            title: Pagesize
          description: 'Items per page (default: 20, max: 100)'
        - name: sortBy
          in: query
          required: false
          schema:
            enum:
              - created_at
              - last_click
              - total_clicks
            type: string
            description: Field to sort by
            default: created_at
            title: Sortby
          description: Field to sort by
        - name: sortOrder
          in: query
          required: false
          schema:
            enum:
              - ascending
              - asc
              - '1'
              - descending
              - desc
              - '-1'
            type: string
            description: Sort direction
            default: descending
            title: Sortorder
          description: Sort direction
        - name: filter
          in: query
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            description: >-
              JSON string containing filter criteria for URLs. Format:
              `{"field": value}`


              **Available filter fields:**


              - **status** — Filter by URL status (`"ACTIVE"` or `"INACTIVE"`)

              - **createdAfter** — Filter URLs created after this date (ISO 8601
              datetime or Unix timestamp)

              - **createdBefore** — Filter URLs created before this date (ISO
              8601 datetime or Unix timestamp)

              - **passwordSet** — Filter by password protection (boolean:
              `true`/`false`)

              - **maxClicksSet** — Filter by click limit presence (boolean:
              `true`/`false`)

              - **search** — Search in alias or long_url (case-insensitive
              string)


              **Value formats:**


              - **status**: String — `"ACTIVE"` or `"INACTIVE"` (case-sensitive)

              - **createdAfter / createdBefore**: ISO 8601 datetime string
              (e.g., `"2024-01-01T00:00:00Z"`) or Unix timestamp (e.g.,
              `1704067200`)

              - **passwordSet / maxClicksSet**: Boolean — `true` or `false`

              - **search**: String — case-insensitive search term


              **Examples:**


              - `{"status": "ACTIVE"}` — Only active URLs

              - `{"passwordSet": true}` — Only password-protected URLs

              - `{"createdAfter": "2024-01-01T00:00:00Z"}` — URLs created after
              Jan 1, 2024

              - `{"status": "ACTIVE", "maxClicksSet": true}` — Active URLs with
              click limits

              - `{"search": "example"}` — URLs containing "example" in alias or
              long_url

              - `{"createdAfter": "2024-01-01", "createdBefore": "2024-12-31",
              "status": "ACTIVE"}` — Active URLs from 2024
            examples:
              - '{"status":"ACTIVE"}'
              - '{"passwordSet": true}'
              - '{"createdAfter": "2024-01-01T00:00:00Z"}'
              - '{"status": "ACTIVE", "maxClicksSet": true}'
              - '{"search": "example"}'
              - >-
                {"createdAfter": "2024-01-01", "createdBefore": "2024-12-31",
                "status": "ACTIVE"}
            title: Filter
          description: >-
            JSON string containing filter criteria for URLs. Format: `{"field":
            value}`


            **Available filter fields:**


            - **status** — Filter by URL status (`"ACTIVE"` or `"INACTIVE"`)

            - **createdAfter** — Filter URLs created after this date (ISO 8601
            datetime or Unix timestamp)

            - **createdBefore** — Filter URLs created before this date (ISO 8601
            datetime or Unix timestamp)

            - **passwordSet** — Filter by password protection (boolean:
            `true`/`false`)

            - **maxClicksSet** — Filter by click limit presence (boolean:
            `true`/`false`)

            - **search** — Search in alias or long_url (case-insensitive string)


            **Value formats:**


            - **status**: String — `"ACTIVE"` or `"INACTIVE"` (case-sensitive)

            - **createdAfter / createdBefore**: ISO 8601 datetime string (e.g.,
            `"2024-01-01T00:00:00Z"`) or Unix timestamp (e.g., `1704067200`)

            - **passwordSet / maxClicksSet**: Boolean — `true` or `false`

            - **search**: String — case-insensitive search term


            **Examples:**


            - `{"status": "ACTIVE"}` — Only active URLs

            - `{"passwordSet": true}` — Only password-protected URLs

            - `{"createdAfter": "2024-01-01T00:00:00Z"}` — URLs created after
            Jan 1, 2024

            - `{"status": "ACTIVE", "maxClicksSet": true}` — Active URLs with
            click limits

            - `{"search": "example"}` — URLs containing "example" in alias or
            long_url

            - `{"createdAfter": "2024-01-01", "createdBefore": "2024-12-31",
            "status": "ACTIVE"}` — Active URLs from 2024
        - name: filterBy
          in: query
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            description: Alias for filter parameter.
            title: Filterby
          description: Alias for filter parameter.
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UrlListResponse'
        '400':
          description: Bad Request — invalid parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized — missing or invalid credentials
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden — insufficient permissions or scope
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '429':
          description: Rate limit exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
components:
  schemas:
    UrlListResponse:
      properties:
        items:
          items:
            $ref: '#/components/schemas/UrlListItem'
          type: array
          title: Items
        page:
          type: integer
          title: Page
        pageSize:
          type: integer
          title: Pagesize
        total:
          type: integer
          title: Total
        hasNext:
          type: boolean
          title: Hasnext
        sortBy:
          type: string
          title: Sortby
        sortOrder:
          type: string
          title: Sortorder
      type: object
      required:
        - items
        - page
        - pageSize
        - total
        - hasNext
        - sortBy
        - sortOrder
      title: UrlListResponse
      description: >-
        Response body for GET /api/v1/urls.


        Uses camelCase field names to match the existing Flask endpoint exactly.

        Field names are camelCase here (not snake_case + alias) because this is
        a

        response-only model — we build it explicitly in the route handler.
    ErrorResponse:
      properties:
        error:
          type: string
          title: Error
        error_code:
          type: string
          title: Error Code
        field:
          anyOf:
            - type: string
            - type: 'null'
          title: Field
        details:
          anyOf:
            - {}
            - type: 'null'
          title: Details
      type: object
      required:
        - error
        - error_code
      title: ErrorResponse
      description: Standard error JSON body produced by the AppError exception handler.
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    UrlListItem:
      properties:
        id:
          type: string
          title: Id
        alias:
          anyOf:
            - type: string
            - type: 'null'
          title: Alias
        long_url:
          anyOf:
            - type: string
            - type: 'null'
          title: Long Url
        status:
          anyOf:
            - type: string
            - type: 'null'
          title: Status
        created_at:
          anyOf:
            - type: string
            - type: 'null'
          title: Created At
        expire_after:
          anyOf:
            - type: integer
            - type: 'null'
          title: Expire After
        max_clicks:
          anyOf:
            - type: integer
            - type: 'null'
          title: Max Clicks
        private_stats:
          anyOf:
            - type: boolean
            - type: 'null'
          title: Private Stats
        block_bots:
          anyOf:
            - type: boolean
            - type: 'null'
          title: Block Bots
        password_set:
          type: boolean
          title: Password Set
        total_clicks:
          anyOf:
            - type: integer
            - type: 'null'
          title: Total Clicks
        last_click:
          anyOf:
            - type: string
            - type: 'null'
          title: Last Click
      type: object
      required:
        - id
        - password_set
      title: UrlListItem
      description: >-
        A single URL entry inside UrlListResponse.items.


        ``created_at`` and ``last_click`` are ISO 8601 strings (e.g.
        "2024-01-01T00:00:00Z").

        ``expire_after`` is a Unix timestamp integer or null.

        These formats match the existing endpoint exactly.
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
              - type: string
              - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
        input:
          title: Input
        ctx:
          type: object
          title: Context
      type: object
      required:
        - loc
        - msg
        - type
      title: ValidationError
  securitySchemes:
    ApiKeyAuth:
      type: http
      scheme: bearer
      bearerFormat: spoo_<key>
      description: 'API key authentication. Pass your key as: `Bearer spoo_<your_key>`'
    JWTAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: 'JWT access token from /auth/login. Pass as: `Bearer <jwt_token>`'

````