Skip to content
AISARAISAR
REST API

Stickers

The company's sticker library: packs of static stickers (WebP, 512×512) that an operator sends into a chat as a regular attachment. This group manages packs and individual stickers — creation, file uploads, adding a sticker straight from an incoming message, importing a public Telegram sticker set, and serving a sticker's bytes via a public signed URL (for rendering in a picker UI).

Permissions

Gated by sticker.view / sticker.create / sticker.update / sticker.delete. The Agent role has sticker.view and sticker.create by default (can browse the library and add stickers, including via the "Add to library" chat action), but not sticker.update/sticker.delete — renaming, moving between packs, and deleting are Manager/Admin only.

Tenancy: 404, not 403

Same as the Snippets group: accessing a pack or sticker that belongs to another company returns 404 Sticker pack not found. / 404 Sticker not found., not 403 — the caller cannot distinguish "does not exist" from "belongs to another company".

File upload

POST /v1/sticker-packs/{pack}/stickers is multipart/form-data with a files[] field (1–120 files per call, PNG/JPG/JPEG/WebP, up to 5 MB each). Every file is server-converted to a static 512×512 WebP. A single bad file does not roll back the whole batch: successfully processed files land in created[], the rest land in skipped[] with a human-readable reason (e.g. exceeding the 25-megapixel decode limit, or an unsupported format).

"Add to library" from a message

There are two endpoints for adding a sticker received in an incoming message: POST /v1/sticker-packs/{pack}/stickers/from-message — into a given pack, and POST /v1/sticker-packs/stickers/from-message (no {pack}) — into the lazily-created system "From chats" pack. Both accept {message_id, attachment_id}; the attachment must be a genuine WebP sticker (checked against the RIFF/WEBP byte signature, not the claimed mime_type), and the message/attachment must belong to the current company and to a conversation the calling user can access (otherwise 422 for a foreign/non-existent message_id/attachment_id, 403 when conversation access is missing).

Importing a public Telegram set

POST /v1/sticker-packs/import/telegram accepts {link} — a https://t.me/addstickers/<name> URL (or a bare set name). As of 2026-08-23 the import is asynchronous: the request only runs a cheap synchronous check (a single getStickerSet call — link parsing, token resolution, set existence, non-empty, not fully animated) and, if it passes, immediately responds 202 Accepted with {status: "queued", name, title}, queueing the actual download on the photos queue. Every "this can never succeed" case (broken link, no Telegram bot available, set not found/empty/fully animated) still returns 422 immediately, without queueing anything. The import outcome (success or error, imported/skipped_animated counts, truncated flag) arrives as a separate sticker.pack.import.finished event (company WebSocket channel + webhook) — it is no longer part of the POST response. Imported stickers only skip Telegram's animated formats (TGS/WebM); every other sticker keeps its own Telegram emoji tag as emoji_tags. The set limit is 120 static stickers per pack (truncated: true on the event if the set was longer and part of it was dropped).

The public sticker file URL

Every sticker in a response carries a url — a signed link to GET /v1/stickers/{sticker}/file. That route is public (no Authorization header — the signature itself is the authorization) and PERMANENT, not time-limited: the sticker picker renders dozens of <img> tags at once and relies on aggressive browser caching. A single leaked link can only be revoked by deleting the sticker (the soft delete hides the file — a 404 on the old link); revoking every link at once requires rotating the platform's APP_KEY.

Endpoints

MethodPath
GET/v1/sticker-packs

List the company's sticker packs with nested stickers.

POST/v1/sticker-packs

Create a sticker pack (name, tray_emoji).

POST/v1/sticker-packs/{pack}

Update a pack — name, tray_emoji, position (sort order).

DELETE/v1/sticker-packs/{pack}

Delete a pack along with all of its stickers.

POST/v1/sticker-packs/{pack}/stickers

Upload one or more stickers into a pack (multipart/form-data, files[], up to 120 files, up to 5 MB each).

POST/v1/sticker-packs/stickers/from-message

Add a sticker from an incoming message into the "From chats" system pack (created lazily).

POST/v1/sticker-packs/{pack}/stickers/from-message

Add a sticker from an incoming message into a given pack.

POST/v1/sticker-packs/import/telegram

Queue a background import of a public Telegram sticker set by link (t.me/addstickers/…) — 202, the outcome arrives via the sticker.pack.import.finished event.

PATCH/v1/stickers/{sticker}

Update a sticker — emoji_tags, position, or move it to another pack (sticker_pack_id).

DELETE/v1/stickers/{sticker}

Delete a sticker from its pack.

GET/v1/stickers/{sticker}/file

Public, permanent signed link to a sticker's file (WebP) — no Authorization header.

Examples

Create a sticker pack

Request

bash
curl -X POST "https://api.aisar.app/v1/sticker-packs" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Reactions",
    "tray_emoji": "😀"
  }'

Response

json
{
  "data": {
    "message": "Sticker pack created.",
    "pack": {
      "id": 14,
      "name": "Reactions",
      "is_system": false,
      "source": "manual",
      "tray_emoji": "😀",
      "position": 0,
      "stickers_count": 0,
      "stickers": []
    }
  }
}

List sticker packs

Request

bash
curl -X GET "https://api.aisar.app/v1/sticker-packs" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Accept: application/json"

Response

json
{
  "data": [
    {
      "id": 14,
      "name": "Reactions",
      "is_system": false,
      "source": "manual",
      "tray_emoji": "😀",
      "position": 0,
      "stickers_count": 1,
      "stickers": [
        {
          "id": 87,
          "pack_id": 14,
          "url": "https://api.aisar.app/v1/stickers/87/file?signature=...",
          "width": 512,
          "height": 512,
          "size": 41230,
          "is_animated": false,
          "emoji_tags": ["😀"],
          "position": 0
        }
      ]
    }
  ]
}

Upload stickers into a pack

Request

bash
curl -X POST "https://api.aisar.app/v1/sticker-packs/14/stickers" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -F "files[]=@/path/to/sticker1.png" \
  -F "files[]=@/path/to/sticker2.png"

Response

json
{
  "data": {
    "created": [
      {
        "id": 88,
        "pack_id": 14,
        "url": "https://api.aisar.app/v1/stickers/88/file?signature=...",
        "width": 512,
        "height": 512,
        "size": 38940,
        "is_animated": false,
        "emoji_tags": [],
        "position": 1
      }
    ],
    "skipped": [
      { "filename": "sticker2.png", "reason": "Image exceeds the maximum decodable pixel count." }
    ]
  }
}

Add to library from an incoming message

Request

bash
curl -X POST "https://api.aisar.app/v1/sticker-packs/stickers/from-message" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "message_id": 1001,
    "attachment_id": 55
  }'

Response

json
{
  "data": {
    "message": "Sticker added to library.",
    "pack_id": 15,
    "item": {
      "id": 89,
      "pack_id": 15,
      "url": "https://api.aisar.app/v1/stickers/89/file?signature=...",
      "width": 512,
      "height": 512,
      "size": 27510,
      "is_animated": false,
      "emoji_tags": [],
      "position": 0
    }
  }
}

Import a Telegram sticker set (202 — queued)

Request

bash
curl -X POST "https://api.aisar.app/v1/sticker-packs/import/telegram" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "link": "https://t.me/addstickers/CoolPack"
  }'

Response

json
{
  "data": {
    "status": "queued",
    "name": "CoolPack",
    "title": "Cool Pack"
  }
}

Move a sticker to another pack

Request

bash
curl -X PATCH "https://api.aisar.app/v1/stickers/87" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "sticker_pack_id": 14,
    "emoji_tags": ["😀", "👍"]
  }'

Response

json
{
  "data": {
    "message": "Sticker updated.",
    "sticker": {
      "id": 87,
      "pack_id": 14,
      "url": "https://api.aisar.app/v1/stickers/87/file?signature=...",
      "width": 512,
      "height": 512,
      "size": 41230,
      "is_animated": false,
      "emoji_tags": ["😀", "👍"],
      "position": 0
    }
  }
}