# Manage links

Find, change, archive and delete your Clikso short links with the API. Bulk calls archive, move or delete many links in one request.

> **In short:**
>
> Find links with a search, change any field with `PUT`, and turn a link off by archiving it. Bulk calls archive, move or delete up to 100 links in one request.

## You need

* **An API key:** **Read** to find links. **Write** to change or delete them.
* **A role:** Editor or admin to make changes. Any member can read.
* **A plan:** Any plan, including Free.

## Find links

List the links in your workspace, newest first. This request searches for "summer" and asks for 20 links per page.

```bash
curl "https://app.clik.so/api/links?q=summer&limit=20" \
  -H "Authorization: Bearer $CLIKSO_API_KEY"
```

Response 200:

```json
{
  "status": 200,
  "success": true,
  "message": "Success",
  "data": [
    {
      "id": "3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c",
      "workspace_id": "8a1f2c3d-4b5e-4f60-9a7b-1c2d3e4f5a6b",
      "custom_domain_id": null,
      "domain": "clik.is",
      "domain_status": "default",
      "title": "Summer sale",
      "description": "",
      "short_code": "summer-sale",
      "destination_url": "https://example.com/summer-sale",
      "status": "active",
      "expires_at": null,
      "expired_redirect_url": null,
      "folder_id": "6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e",
      "ab_testing": [],
      "geo_targeting": null,
      "device_targeting": null,
      "qr_metadata": null,
      "og_preview": null,
      "meta_pixel_id": null,
      "tiktok_pixel_id": null,
      "ga4_measurement_id": null,
      "gtm_container_id": null,
      "has_password": false,
      "click_count": 128,
      "created_by": "c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f",
      "created_at": "2026-10-09T09:30:00.000Z",
      "updated_at": "2026-10-09T09:30:00.000Z",
      "tags": [
        {
          "id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
          "name": "launch",
          "color": "#3b82f6"
        }
      ],
      "creator": {
        "id": "c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f",
        "display_name": "Asha Rao",
        "email": "asha@example.com",
        "photo_url": ""
      }
    }
  ],
  "meta": {
    "total": 1,
    "limit": 20,
    "offset": 0,
    "total_is_capped": false,
    "has_more": false
  }
}
```

You can narrow the list with these query parameters:

* `q` — a word to look for in the title, slug, destination URL or description.
* `folder_id` — only links in this folder.
* `status` — `active`, `archived` or `expired`.
* `tags` — tag ids, separated by commas. A link matches if it has any of them.
* `sort_by` — `created_at`, `title`, `status` or `click_count`. Add `order` as `asc` or `desc`.

### Get every page

A page holds up to 200 links. To get them all, start with `offset` set to `0`. For the next page, add your `limit` to `offset`. Stop when `meta.has_more` is `false`.

```bash
curl "https://app.clik.so/api/links?limit=20&offset=20" \
  -H "Authorization: Bearer $CLIKSO_API_KEY"
```

## Get one link

Use the link's `id` to read it again. You get one link, with the same fields as in the list.

```bash
curl "https://app.clik.so/api/links/3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c" \
  -H "Authorization: Bearer $CLIKSO_API_KEY"
```

## Change a link

Send only the fields you want to change. Fields you leave out keep their value. This call is `PUT`, but it works like a patch.

```bash
curl -X PUT "https://app.clik.so/api/links/3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c" \
  -H "Authorization: Bearer $CLIKSO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "destination_url": "https://example.com/autumn-sale",
    "title": "Autumn sale",
    "expires_at": null
  }'
```

Response 200:

```json
{
  "status": 200,
  "success": true,
  "message": "Link updated",
  "data": {
    "id": "3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c",
    "workspace_id": "8a1f2c3d-4b5e-4f60-9a7b-1c2d3e4f5a6b",
    "custom_domain_id": null,
    "domain": "clik.is",
    "domain_status": "default",
    "title": "Autumn sale",
    "description": "",
    "short_code": "summer-sale",
    "destination_url": "https://example.com/autumn-sale",
    "status": "active",
    "expires_at": null,
    "expired_redirect_url": null,
    "folder_id": "6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e",
    "ab_testing": [],
    "geo_targeting": null,
    "device_targeting": null,
    "qr_metadata": null,
    "og_preview": null,
    "meta_pixel_id": null,
    "tiktok_pixel_id": null,
    "ga4_measurement_id": null,
    "gtm_container_id": null,
    "has_password": false,
    "click_count": 128,
    "created_by": "c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f",
    "created_at": "2026-10-09T09:30:00.000Z",
    "updated_at": "2026-10-10T08:15:00.000Z",
    "tags": [
      {
        "id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
        "name": "launch",
        "color": "#3b82f6"
      }
    ],
    "creator": {
      "id": "c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f",
      "display_name": "Asha Rao",
      "email": "asha@example.com",
      "photo_url": ""
    }
  }
}
```

A few rules for the body:

* Send `null` to clear a field. For example, `expires_at: null` removes the expiry, and `geo_targeting: null` removes the country rules. `{}` (or `[]` for `ab_testing`) clears the rule objects too.
* `tags` replaces the whole list. Send `[]` to remove every tag. Send `null`, or leave it out, to keep the tags.
* Keep `title` to 60 characters and `description` to 250. Longer values get `422 VALIDATION_ERROR`, and `details.field` names the field.

### Change the slug or the destination

You can change `short_code` and `destination_url` at any time.

A new `destination_url` keeps the same short URL. Everyone who already has the link now lands on the new page.

> **A new slug breaks the old short URL:**
>
> When you change `short_code` or the domain, the old short URL stops working at once. Printed QR codes and old posts that use it will fail. Change the destination instead when you can.

## Archive a link

Archiving turns a link off without deleting it. Its short URL stops working, and its click history stays. Set `status` back to `active` to turn it on again.

```bash
curl -X PUT "https://app.clik.so/api/links/3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c" \
  -H "Authorization: Bearer $CLIKSO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "archived"
  }'
```

## Delete a link

Deleting stops the short URL at once. You cannot undo it through the API, so archive the link if you might want it back.

```bash
curl -X DELETE "https://app.clik.so/api/links/3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c" \
  -H "Authorization: Bearer $CLIKSO_API_KEY"
```

After the delete, the short code is free again on that domain. A new link can then use it.

## Change many links at once

### Archive, restore or move links

Send up to 100 link ids with a new `status`, a new `folder_id`, or both. Use `folder_id: null` to take the links out of their folders.

```bash
curl -X PATCH "https://app.clik.so/api/links/bulk" \
  -H "Authorization: Bearer $CLIKSO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "ids": [
      "3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c",
      "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a"
    ],
    "status": "archived"
  }'
```

Response 200:

```json
{
  "status": 200,
  "success": true,
  "message": "Success",
  "data": {
    "updated_count": 2
  }
}
```

### Delete links

Send up to 100 link ids. This is a `DELETE` request with a JSON body.

```bash
curl -X DELETE "https://app.clik.so/api/links/bulk" \
  -H "Authorization: Bearer $CLIKSO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "ids": [
      "3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c",
      "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a"
    ]
  }'
```

Response 200:

```json
{
  "status": 200,
  "success": true,
  "message": "Success",
  "data": {
    "deleted_count": 2,
    "skipped_banned_count": 0,
    "skipped_banned_ids": []
  }
}
```

## What you get back

Every call returns the usual JSON envelope: `status`, `success`, `message` and `data`. What sits in `data` depends on the call:

* **List links:** an array of links. Paging details are in `meta`, next to `data`: `total`, `limit`, `offset`, `total_is_capped` and `has_more`.
* **Get a link** and **Update a link:** one link.
* **Delete a link:** no body at all, just a `204` status.
* **Update many links:** `updated_count`, the number of links that changed.
* **Delete many links:** `deleted_count`, plus `skipped_banned_count` and `skipped_banned_ids` for links that could not be deleted.

## Common errors

| Status | Code                  | What it means                                                                                         | What to do                                                                                               |
| ------ | --------------------- | ----------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| 401    | `UNAUTHORIZED`        | The key is missing or wrong.                                                                          | Send `Authorization: Bearer clik_live_…` with a key from Settings → API.                                 |
| 403    | `FORBIDDEN`           | The key only has Read permission, or its creator is a viewer.                                         | Check the key’s permission and your role. If you send `Workspace-Id`, it must match the key’s workspace. |
| 404    | `NOT_FOUND`           | No link with this id in your workspace. It may be deleted.                                            | Check the id. Ids from another workspace are never found.                                                |
| 409    | `CONFLICT`            | The new `short_code` is taken on that domain. Or you tried to delete a link Clikso removed for abuse. | Pick another `short_code`. A link removed for abuse cannot be deleted.                                   |
| 422    | `VALIDATION_ERROR`    | A field is wrong or too long, or `ids` is empty or too long.                                          | Fix the field and send the request again.                                                                |
| 422    | `DESTINATION_BLOCKED` | The new destination is another link shortener or a blocked site.                                      | Show `error.message` to the user as it is. Do not retry.                                                 |
| 429    | `RATE_LIMITED`        | The key sent too many requests this minute.                                                           | Wait the number of seconds in the `Retry-After` header, then try again.                                  |

## Good to know

* A larger `limit` than 200 is cut to 200, not refused. The default is 50.
* `meta.total` stops counting at 10,000. When `total_is_capped` is `true`, page with `has_more` instead.
* `status=active` leaves out links whose expiry date has passed, even if their stored status still says `active`.
* Deleted links never show up in the list.
* Bulk calls skip ids they cannot find, without an error. Check `updated_count` or `deleted_count`.
* A link that Clikso removed for abuse cannot be deleted. Bulk delete skips it and lists it in `skipped_banned_ids`.
* There is no bulk create and no bulk tagging. To tag many links, update each link's `tags`.
* `click_count` is the link's total since it was made. For a date range, use the [analytics calls](https://clik.so/docs/guides/analytics).

---

Source: https://clik.so/docs/guides/manage-links
