basePath: /
consumes:
- application/json
definitions:
  BadFilter:
    properties:
      code:
        example: ERR006
        type: string
      message:
        example: 'Key: ''Options.Limit'' Error:Field validation for ''Limit'' failed
          on the ''max'' tag'
        type: string
      reason:
        example: Bad filter request - The filter of the request has validation errors
        type: string
    type: object
  BadRequest:
    properties:
      code:
        example: ERR001
        type: string
      message:
        example: 'target_url: must be a valid request URL.'
        type: string
      reason:
        example: Bad request - The request could not be understood by the service
          due to malformed syntax
        type: string
    type: object
  Click:
    properties:
      bot:
        description: Whether the click was recognised as made by a bot rather than
          a person
        example: false
        type: boolean
      campaign:
        description: Campaign of the clicked short link
        example: marketing-aug-2026
        type: string
      click_time:
        description: Moment the visitor followed the link
        example: "2026-07-21T09:12:44Z"
        type: string
      creation_time:
        description: Moment the click was stored
        example: "2026-07-21T09:12:45Z"
        type: string
      geo_ip:
        allOf:
        - $ref: '#/definitions/GeoIP'
        description: Location the IP address was resolved to
      id:
        description: Unique identifier of the click
        example: 68a1f0c4b2d9e14a7c3f5b02
        type: string
      recipient:
        description: Phone number the clicked link was created for
        example: "48123456789"
        type: string
      remote_ip:
        description: IP address the visitor came from
        example: 83.25.136.211
        type: string
      suffix:
        description: Suffix of the clicked short link
        example: uH5DB
        type: string
      user_agent:
        allOf:
        - $ref: '#/definitions/UserAgent'
        description: Parsed User-Agent of the visitor
      user_agent_original:
        description: User-Agent the visitor came with, as received
        example: Mozilla/5.0 (Linux; Android 6.0.1; MotoG3) AppleWebKit/537.36 (KHTML,
          like Gecko) Chrome/79.0.3945.79 Mobile Safari/537.36
        type: string
    type: object
  CreateShortLinkRequest:
    properties:
      campaign:
        description: Campaign to group the link under
        example: marketing-aug-2026
        type: string
      event_method:
        description: HTTP method to call the webhook with. Required together with
          event_url
        enum:
        - POST
        - GET
        example: POST
        type: string
      event_url:
        description: Webhook to call on every click on the link. Required together
          with event_method
        example: https://hooks.integrations.apifonica.com/exponea/sms-event-handler
        maxLength: 128
        minLength: 11
        type: string
      expire_time:
        description: Moment the link stops working, six months after creation by default.
          Must be in the future
        example: "2030-01-16T15:38:56Z"
        type: string
      recipient:
        description: Phone number of the recipient the link is created for
        example: "48123456789"
        type: string
      suffix:
        description: |-
          Custom suffix for the link, letters, digits and the characters -._~ only.
          Omit it to get an automatically generated one
        example: summer-sale
        maxLength: 64
        minLength: 1
        type: string
      tag:
        description: Arbitrary string passed through to the webhook payload
        example: campaign_id=42&action_type=click
        maxLength: 512
        type: string
      target_url:
        description: URL the visitor is redirected to
        example: https://www.apifonica.com
        maxLength: 1024
        minLength: 5
        type: string
    required:
    - campaign
    - target_url
    type: object
  GeoIP:
    properties:
      city:
        description: City the IP address was resolved to
        example: Bydgoszcz
        type: string
      country:
        description: Country the IP address was resolved to
        example: Poland
        type: string
      country_iso:
        description: ISO 3166-1 alpha-2 code of that country
        example: PL
        type: string
      location_latitude:
        description: Latitude of the resolved location, in degrees
        example: 53.1281
        type: number
      location_longitude:
        description: Longitude of the resolved location, in degrees
        example: 18.0204
        type: number
      time_zone:
        description: IANA time zone of the resolved location
        example: Europe/Warsaw
        type: string
    type: object
  NotAuthorized:
    properties:
      code:
        example: ERR201
        type: string
      message:
        example: You don’t have necessary permissions for the resource.
        type: string
      reason:
        example: Authentication Error - account_sid or account_token was incorrect
        type: string
    type: object
  PreviewShortLinkRequest:
    properties:
      suffix:
        description: |-
          Custom suffix for the link, letters, digits and the characters -._~ only.
          Omit it to get an automatically generated one
        example: summer-sale
        maxLength: 64
        minLength: 1
        type: string
      target_url:
        description: URL the short link would redirect to
        example: https://www.apifonica.com
        maxLength: 1024
        minLength: 5
        type: string
    required:
    - target_url
    type: object
  ResourceConflict:
    properties:
      code:
        example: ERR013
        type: string
      message:
        example: duplicate Suffix 'myPromo'
        type: string
      reason:
        example: Resource conflict
        type: string
    type: object
  RuntimeError:
    properties:
      code:
        example: ERR003
        type: string
      message:
        example: An unexpected error occurred
        type: string
      reason:
        example: Runtime error - The service encountered an unexpected condition which
          prevented it from fulfilling your request
        type: string
    type: object
  ShortLink:
    properties:
      account_sid:
        description: Account the link belongs to
        example: acce6382de8-b9d1-31b0-baa4-10984bf7fb72
        type: string
      campaign:
        description: Campaign the link belongs to
        example: marketing-aug-2026
        type: string
      creation_time:
        description: Moment the link was created
        example: "2026-07-20T15:38:56Z"
        type: string
      domain:
        description: Short domain the link was created on
        example: apif.me
        type: string
      event_method:
        description: HTTP method the webhook is called with
        example: POST
        type: string
      event_url:
        description: Webhook called on every click on the link
        example: https://hooks.integrations.apifonica.com/exponea/sms-event-handler
        type: string
      expire_time:
        description: Moment the link stops working and is deleted, six months after
          creation by default
        example: "2027-01-16T15:38:56Z"
        type: string
      id:
        description: Unique identifier of the short link
        example: 5e182e945798aaa1cfa5ba11
        type: string
      recipient:
        description: Phone number of the recipient the link was created for
        example: "48123456789"
        type: string
      suffix:
        description: Suffix that identifies the link on the short domain
        example: uH5DB
        type: string
      tag:
        description: Arbitrary string passed through to the webhook payload
        example: campaign_id=42&action_type=click
        type: string
      target_url:
        description: URL the visitor is redirected to
        example: https://www.apifonica.com
        type: string
      update_time:
        description: Moment the link was last changed
        example: "2026-07-20T15:38:56Z"
        type: string
      url:
        description: Short URL to hand out to your recipients
        example: https://apif.me/uH5DB
        type: string
    type: object
  ShortLinkPreview:
    properties:
      domain:
        description: Short domain the link would be created on
        example: apif.me
        type: string
      suffix:
        description: Suffix the link would get
        example: uH5DB
        type: string
      target_url:
        description: URL the visitor would be redirected to
        example: https://www.apifonica.com
        type: string
      url:
        description: Short URL the link would get
        example: https://apif.me/uH5DB
        type: string
    type: object
  StorageFetchError:
    properties:
      code:
        example: ERR022
        type: string
      message:
        example: Failed to retrieve resource from database
        type: string
      reason:
        example: Runtime error while fetching resources
        type: string
    type: object
  Unauthorized:
    properties:
      code:
        example: ERR204
        type: string
      message:
        example: Your AccountSid or AuthToken was incorrect.
        type: string
      reason:
        example: Authentication Error - No credentials provided
        type: string
    type: object
  UserAgent:
    properties:
      browser:
        description: Browser or other client software the visitor used
        example: Chrome
        type: string
      browser_version:
        description: Version of that browser
        example: "79"
        type: string
      capabilities:
        description: Client features as reported by whatismybrowser, for example javascript
        example:
        - javascript
        items:
          type: string
        type: array
      hardware_sub_type:
        description: Narrower class of the device within hardware_type, for example
          smartphone or tablet
        example: smartphone
        type: string
      hardware_type:
        description: Class of the device as reported by whatismybrowser, for example
          mobile or computer
        example: mobile
        type: string
      mobile:
        description: Whether the visitor's device is a phone
        example: true
        type: boolean
      os:
        description: Operating system the visitor's device runs
        example: Android
        type: string
      os_version:
        description: Version of that operating system
        example: Marshmallow
        type: string
      simple_operating_platform_string:
        description: Short device and platform name as reported by whatismybrowser
        example: Motorola MotoG3
        type: string
      software_sub_type:
        description: Narrower class of the client software within software_type, for
          example web-browser
        example: web-browser
        type: string
      software_type:
        description: Class of the client software as reported by whatismybrowser,
          for example browser or bot
        example: browser
        type: string
      source_user_agent_info:
        description: 'Parser the values above came from: whatismybrowser, xojoc, or
          both separated by a pipe'
        example: whatismybrowser
        type: string
      tablet:
        description: Whether the visitor's device is a tablet
        example: false
        type: boolean
    type: object
host: shortener.apifonica.com
info:
  contact:
    email: info@apifonica.com
    name: Apifonica Support
    url: https://www.apifonica.com/en/company/contacts
  description: |
    ## Overview

    Apifonica Shortener API turns long target URLs into short links like `https://apif.me/uH5DB` and records
    the clicks on them, including GeoIP and User-Agent data of the visitor. A short link answers with a
    permanent redirect, so a browser that has already followed it may serve the target from its own cache
    without reaching Apifonica again — such repeat visits are not recorded.

    The API has two areas:

    - **[Links](#tag/Links)** — [create short links](#operation/createShortLink) and
      [browse the ones you already created](#operation/getShortLinks).
    - **[Clicks](#tag/Clicks)** — [read click statistics](#operation/getClicks) and the
      [public redirect endpoint](#operation/handleClick) that serves the short link.

    A short link may also carry a webhook: when it is clicked, Apifonica sends an event to the URL you specified
    in `event_url`, so you can track clicks in your own system.

    ## Authentication

    <SecurityDefinitions />

    You need to authenticate all your requests using a valid pair of Apifonica credentials — `account_sid` and
    `account_token`.

    You can find them in your [Apifonica Personal Account](https://account-smsbot.apifonica.com/dashboard/integrations).

    More details can be found in the [Apifonica FAQ](https://www.apifonica.com/en/developers/faq/basics/).

    Every link and click resource belongs to the account that created it — you only ever see your own data.
    The public redirect endpoint [`GET /handle/{suffix}`](#operation/handleClick) needs no authentication.

    ## Lifetime of a link

    Every short link expires. By default it stops working six months after creation; pass `expire_time` in
    [Create a short link](#operation/createShortLink) to choose a different moment — any moment in the future
    is accepted, earlier or later than the default. An expired link is removed from the collection shortly
    after its `expire_time`, so it disappears from [Get short links](#operation/getShortLinks) and stops
    redirecting.

    Clicks are kept for eight months after the click happened, then removed.

    ## Pagination

    The collection endpoints ([`GET /link`](#operation/getShortLinks), [`GET /click`](#operation/getClicks))
    return items page by page, newest first by default.

    ### Request query parameters

    - **`limit`** (int, optional): number of items to return — a positive integer, `100` by default and
      `50000` at most.
    - **`order`** (string, optional): `desc` (default) or `asc`. Items are ordered by the moment they were
      stored, which for clicks can differ slightly from `click_time`.
    - **`last_id`** (string, optional): ID of the last item of the previous page. Omit it to get the **first
      page**, then pass the value of the `X-Last-ID` response header to get the next one.

    ### Response format

    The body is a plain array of resources. Pagination details come in the response headers:

    - **`X-Total-Count`** — total number of items matching your filters. It ignores `last_id`, so it stays the
      same while you page through the collection. The header is omitted when nothing matches.
    - **`X-Filtered-Count`** — number of items returned on the current page.
    - **`X-Last-ID`** — ID of the last returned item, to be used as `last_id` for the next page.

    The status code tells you what you got:

    - **`200 OK`** — the page holds every item matching your filters.
    - **`206 Partial Content`** — your filters match more items than the page holds. Note that the last
      non-empty page of a walk also comes back as `206`.
    - **`204 No Content`** — nothing to return: either no item matches your filters, or you reached the end of
      the collection and the page is empty. There is no body. `X-Total-Count` comes with the second case only —
      when nothing matches your filters at all, no counter header is sent.

    Both endpoints also answer `HEAD` requests — same filters, no body — when you only need the counters. Note
    that a `HEAD` response carries no `X-Last-ID`, and its `X-Filtered-Count` is the page size you asked for in
    `limit` rather than a real count.

    ## Short domains

    By default short links are created on the `apif.me` domain. A custom short domain can be configured for your
    account, in which case it is used for all new links and returned in the `domain` field of the response.
    Contact [Apifonica Support](https://www.apifonica.com/en/company/contacts) to set one up.
  termsOfService: https://www.apifonica.com/public/legal/apifonica_terms_of_service.pdf
  title: Shortener
  version: "1.0"
  x-logo:
    altText: Apifonica logo
    url: https://apifonica.com/public/img/logo.svg
paths:
  /click:
    get:
      description: |-
        Returns the clicks registered on your short links, newest first. Filter them by `suffix` or
        `campaign`, drop the clicks made by bots with `with_bots=false` and page through the result
        with `limit` and `last_id`.
      operationId: getClicks
      parameters:
      - description: Filter by short link suffix
        in: query
        name: suffix
        type: string
        x-example: uH5DB
      - description: Filter by campaign
        in: query
        name: campaign
        type: string
        x-example: marketing-aug-2026
      - default: true
        description: Include clicks made by bots. Send `false` or `0` to exclude them
        in: query
        name: with_bots
        type: boolean
      - description: ID of the last item of the previous page
        in: query
        name: last_id
        type: string
        x-example: 5e182e945798aaa1cfa5ba11
      - default: 100
        description: Number of items to return, a positive integer, 50000 at most
        in: query
        name: limit
        type: integer
      - default: desc
        description: Sort order by the moment clicks were stored
        enum:
        - desc
        - asc
        in: query
        name: order
        type: string
      responses:
        "200":
          description: All matching clicks fit into the returned page
          headers:
            X-Filtered-Count:
              description: Number of clicks returned on this page
              type: integer
            X-Last-ID:
              description: ID of the last returned click, pass it as `last_id` for
                the next page
              type: string
            X-Total-Count:
              description: Total number of clicks matching the filters, ignoring `last_id`
              type: integer
          schema:
            items:
              $ref: '#/definitions/Click'
            type: array
        "204":
          description: 'Nothing to return: no clicks match the filters, or the page
            is empty. X-Total-Count is sent only when the filters match something'
        "206":
          description: There are more clicks matching the filters than the returned
            page holds
          headers:
            X-Filtered-Count:
              description: Number of clicks returned on this page
              type: integer
            X-Last-ID:
              description: ID of the last returned click, pass it as `last_id` for
                the next page
              type: string
            X-Total-Count:
              description: Total number of clicks matching the filters, ignoring `last_id`
              type: integer
          schema:
            items:
              $ref: '#/definitions/Click'
            type: array
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/BadFilter'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/Unauthorized'
        "403":
          description: Forbidden
          schema:
            $ref: '#/definitions/NotAuthorized'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/StorageFetchError'
      security:
      - BasicAuth: []
      summary: Get clicks
      tags:
      - Clicks
    head:
      description: Accepts the same filters as `GET /click` and returns only the counter
        headers, without a body.
      operationId: headClicks
      parameters:
      - description: Filter by short link suffix
        in: query
        name: suffix
        type: string
        x-example: uH5DB
      - description: Filter by campaign
        in: query
        name: campaign
        type: string
        x-example: marketing-aug-2026
      - default: true
        description: Count clicks made by bots. Send `false` or `0` to exclude them
        in: query
        name: with_bots
        type: boolean
      - default: 100
        description: Page size reported back in X-Filtered-Count
        in: query
        name: limit
        type: integer
      responses:
        "200":
          description: All matching clicks fit into one page
          headers:
            X-Filtered-Count:
              description: Page size you requested in `limit`, not a count
              type: integer
            X-Total-Count:
              description: Total number of clicks matching the filters
              type: integer
        "204":
          description: Nothing to report for these filters and page size
        "206":
          description: The result is bigger than one page
          headers:
            X-Filtered-Count:
              description: Page size you requested in `limit`, not a count
              type: integer
            X-Total-Count:
              description: Total number of clicks matching the filters
              type: integer
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/BadFilter'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/Unauthorized'
        "403":
          description: Forbidden
          schema:
            $ref: '#/definitions/NotAuthorized'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/StorageFetchError'
      security:
      - BasicAuth: []
      summary: Count clicks
      tags:
      - Clicks
  /handle/{suffix}:
    get:
      description: |-
        Public endpoint behind the short domain: redirects the visitor to the target URL of the link
        and registers the click with GeoIP and User-Agent data in the background. If the link is
        unknown or has already expired, a `Not found` page is returned instead.
        No authentication required.
      operationId: handleClick
      parameters:
      - description: Short link suffix
        in: path
        name: suffix
        required: true
        type: string
        x-example: uH5DB
      produces:
      - text/plain
      responses:
        "301":
          description: Visitor is redirected to the target URL of the short link
          headers:
            Location:
              description: Target URL of the short link
              type: string
        "404":
          description: Short link is unknown or has expired
          schema:
            type: string
      summary: Follow a short link
      tags:
      - Clicks
  /link:
    get:
      description: |-
        Returns the short links of your account, newest first. Narrow the result down by `campaign`
        or `suffix` and page through it with `limit` and `last_id`.
      operationId: getShortLinks
      parameters:
      - description: Filter by campaign
        in: query
        name: campaign
        type: string
        x-example: marketing-aug-2026
      - description: Filter by suffix
        in: query
        name: suffix
        type: string
        x-example: uH5DB
      - description: ID of the last item of the previous page
        in: query
        name: last_id
        type: string
        x-example: 5e182e945798aaa1cfa5ba11
      - default: 100
        description: Number of items to return, a positive integer, 50000 at most
        in: query
        name: limit
        type: integer
      - default: desc
        description: Sort order by the moment links were stored
        enum:
        - desc
        - asc
        in: query
        name: order
        type: string
      responses:
        "200":
          description: All matching short links fit into the returned page
          headers:
            X-Filtered-Count:
              description: Number of short links returned on this page
              type: integer
            X-Last-ID:
              description: ID of the last returned short link, pass it as `last_id`
                for the next page
              type: string
            X-Total-Count:
              description: Total number of short links matching the filters, ignoring
                `last_id`
              type: integer
          schema:
            items:
              $ref: '#/definitions/ShortLink'
            type: array
        "204":
          description: 'Nothing to return: no short links match the filters, or the
            page is empty. X-Total-Count is sent only when the filters match something'
        "206":
          description: There are more short links matching the filters than the returned
            page holds
          headers:
            X-Filtered-Count:
              description: Number of short links returned on this page
              type: integer
            X-Last-ID:
              description: ID of the last returned short link, pass it as `last_id`
                for the next page
              type: string
            X-Total-Count:
              description: Total number of short links matching the filters, ignoring
                `last_id`
              type: integer
          schema:
            items:
              $ref: '#/definitions/ShortLink'
            type: array
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/BadFilter'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/Unauthorized'
        "403":
          description: Forbidden
          schema:
            $ref: '#/definitions/NotAuthorized'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/StorageFetchError'
      security:
      - BasicAuth: []
      summary: Get short links
      tags:
      - Links
    head:
      description: Accepts the same filters as `GET /link` and returns only the counter
        headers, without a body.
      operationId: headShortLinks
      parameters:
      - description: Filter by campaign
        in: query
        name: campaign
        type: string
        x-example: marketing-aug-2026
      - description: Filter by suffix
        in: query
        name: suffix
        type: string
        x-example: uH5DB
      - default: 100
        description: Page size reported back in X-Filtered-Count
        in: query
        name: limit
        type: integer
      responses:
        "200":
          description: All matching short links fit into one page
          headers:
            X-Filtered-Count:
              description: Page size you requested in `limit`, not a count
              type: integer
            X-Total-Count:
              description: Total number of short links matching the filters
              type: integer
        "204":
          description: Nothing to report for these filters and page size
        "206":
          description: The result is bigger than one page
          headers:
            X-Filtered-Count:
              description: Page size you requested in `limit`, not a count
              type: integer
            X-Total-Count:
              description: Total number of short links matching the filters
              type: integer
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/BadFilter'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/Unauthorized'
        "403":
          description: Forbidden
          schema:
            $ref: '#/definitions/NotAuthorized'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/StorageFetchError'
      security:
      - BasicAuth: []
      summary: Count short links
      tags:
      - Links
    post:
      description: |-
        Creates a short link that redirects a visitor to `target_url`. The suffix is generated
        automatically unless you provide your own one in `suffix`.
        Every link expires: six months after creation by default, or at the `expire_time` you pass.
        An expired link stops redirecting and is removed from the collection.
        Pass `event_url` and `event_method` to have Apifonica call your webhook on every click.
      operationId: createShortLink
      parameters:
      - description: Short link parameters
        in: body
        name: request
        required: true
        schema:
          $ref: '#/definitions/CreateShortLinkRequest'
      responses:
        "201":
          description: Created
          schema:
            $ref: '#/definitions/ShortLink'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/BadRequest'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/Unauthorized'
        "403":
          description: Forbidden
          schema:
            $ref: '#/definitions/NotAuthorized'
        "409":
          description: Conflict
          schema:
            $ref: '#/definitions/ResourceConflict'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/RuntimeError'
      security:
      - BasicAuth: []
      summary: Create a short link
      tags:
      - Links
  /link/preview:
    post:
      description: |-
        Generates a short link for `target_url` without storing it, so you can show the customer how
        the link is going to look. The returned suffix is not reserved: a later `POST /link` call may
        produce a different one.
      operationId: previewShortLink
      parameters:
      - description: Target URL to preview
        in: body
        name: request
        required: true
        schema:
          $ref: '#/definitions/PreviewShortLinkRequest'
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/ShortLinkPreview'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/BadRequest'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/Unauthorized'
        "403":
          description: Forbidden
          schema:
            $ref: '#/definitions/NotAuthorized'
      security:
      - BasicAuth: []
      summary: Preview a short link
      tags:
      - Links
produces:
- application/json
schemes:
- https
securityDefinitions:
  BasicAuth:
    type: basic
swagger: "2.0"
tags:
- description: 'Short link management: create links and browse the ones you already
    created'
  name: Links
- description: Click statistics and the public redirect endpoint that serves a short
    link
  name: Clicks
