---
title: "Shorten a URL"
method: POST
path: "/shorten"
tags: ["URLs"]
---

# Shorten a URL

`POST /shorten`

## Request

- Base URL: `https://gajo.io/api/v1`
- URL: `https://gajo.io/api/v1/shorten`
- Auth: API key in header `x-api-key`

Creates a short link on your plan: code length, maximum lifetime and deep-link support follow the plan. `lifetimeDays` is clamped to the plan maximum (60 days on Free, 120 on Basic, unlimited on Pro); omit it to get the maximum. `fallbackUrl` is only valid when `url` is an app deep link (custom scheme such as `myapp://...`), and custom schemes require a Pro plan. Each call counts against your monthly URL allowance; once it is used up the API returns `429`. With `customCode` (Pro), the link uses your custom code and redirects at `https://gajo.io/c/{code}`: an unclaimed code is claimed for you, and one of your own codes is used if it isn't currently linked to a URL. A code that's taken, released, or already linked returns `409` (change a linked code's destination with `PUT /urls/{code}`). Custom-code links don't expire, so `lifetimeDays` can't be combined with `customCode`.

## Request body

- ShortenRequest
  - `url` string, required: Destination URL. Supported schemes: `http`, `https`, `mailto`, `tel`, `ftp`, `sftp`. Pro plans may also shorten app deep links with a custom scheme (e.g. `myapp://product/42`). URLs pointing at gajo.io are rejected.
  - `customCode` string, nullable: Pro only. A custom code for the link (3-50 letters, digits, or hyphens; stored lowercase). The link redirects at `https://gajo.io/c/{code}` and the response has `isCustomCode: true`. An unclaimed code is claimed for you; one of your own codes is reused if it isn't linked to a URL. Can't be combined with `lifetimeDays`.
  - `lifetimeDays` integer, nullable: Days until the link expires. Omit for your plan maximum. Values above the plan maximum are clamped to it (60 on Free, 120 on Basic); Pro has no maximum, and omitting it on Pro creates a link that never expires.
  - `fallbackUrl` string, nullable: Only valid when `url` is an app deep link (custom scheme, which requires Pro). A web URL that visitors are sent to when the app is not installed, such as the App Store or Google Play listing. Sending it with an ordinary web `url` is rejected with `400`.

## Response `200`

The new short link. Share it as `https://gajo.io/{shortCode}`.

- ShortUrlResult: Envelope shared by every response.
  - `success` true, required: `true` when the request succeeded.
  - `message` string, nullable: Human-readable status or error message. Often `null` on reads.
  - `data` object, required: A short link. Generated codes redirect at `https://gajo.io/{shortCode}`; custom codes (`isCustomCode: true`, created in the Pro dashboard) redirect at `https://gajo.io/c/{shortCode}`. All redirects are HTTP 302.
    - `shortCode` string, required: The short code. Generated codes are never reassigned.
    - `originalUrl` string, required: Destination URL (may be an app deep link on Pro).
    - `fallbackUrl` string, nullable, required: Web fallback used when `originalUrl` is an app deep link and the app is not installed (e.g. the App Store listing). `null` otherwise.
    - `active` boolean, required: `false` once the link has been deactivated.
    - `clickCount` integer, required: Human clicks (bot and link-preview traffic excluded).
    - `isCustomCode` boolean, required: `true` for Pro custom codes (served under `/c/`).
    - `createdDate` string, date-time, required
    - `expiresDate` string, date-time, nullable, required: When the link stops redirecting; `null` = never expires.

## Other responses

- `400`: Invalid request. `message` explains what to fix.
- `401`: The `x-api-key` header is missing, or the key is unknown or revoked.
- `403`: `customCode` was sent but your plan is not Pro.
- `409`: The `customCode` can't be used: it belongs to another account, was released, clashes with a generated code, or is already linked to one of your URLs.
- `429`: Either the per-minute rate limit was exceeded (`Retry-After` is set), or the plan's monthly URL allowance is used up (no `Retry-After`; wait for the next calendar month or upgrade).
- `500`: Unexpected server error.

---

[API](https://skmtc.dev/gajo/apis/gajo-api.md) · [All operations](https://skmtc.dev/gajo/apis/gajo-api/llms.txt) · [OpenAPI document](https://skmtc.dev/gajo/apis/gajo-api/revisions/de6fe920cc26?raw)
