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
| Method | Path | Summary |
|---|---|---|
| GET | /v1/sticker-packsList the company's sticker packs with nested stickers. | List the company's sticker packs with nested stickers. |
| POST | /v1/sticker-packsCreate a sticker pack (name, tray_emoji). | Create a sticker pack (name, tray_emoji). |
| POST | /v1/sticker-packs/{pack}Update a pack — name, tray_emoji, position (sort order). | Update a pack — name, tray_emoji, position (sort order). |
| DELETE | /v1/sticker-packs/{pack}Delete a pack along with all of its stickers. | Delete a pack along with all of its stickers. |
| POST | /v1/sticker-packs/{pack}/stickersUpload one or more stickers into a pack (multipart/form-data, files[], up to 120 files, up to 5 MB each). | 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-messageAdd a sticker from an incoming message into the "From chats" system pack (created lazily). | Add a sticker from an incoming message into the "From chats" system pack (created lazily). |
| POST | /v1/sticker-packs/{pack}/stickers/from-messageAdd a sticker from an incoming message into a given pack. | Add a sticker from an incoming message into a given pack. |
| POST | /v1/sticker-packs/import/telegramQueue 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. | 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). | 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. | Delete a sticker from its pack. |
| GET | /v1/stickers/{sticker}/filePublic, permanent signed link to a sticker's file (WebP) — no Authorization header. | Public, permanent signed link to a sticker's file (WebP) — no Authorization header. |
Examples
Create a sticker pack
Request
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
{
"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
curl -X GET "https://api.aisar.app/v1/sticker-packs" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"Response
{
"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
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
{
"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
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
{
"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
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
{
"data": {
"status": "queued",
"name": "CoolPack",
"title": "Cool Pack"
}
}Move a sticker to another pack
Request
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
{
"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
}
}
}