The Icons endpoint serves notification icon images referenced from notification data. Each icon ID is derived from the originating notification (session, ID, timestamp, and extension). This page documents the single endpoint that streams those images back, including the caching headers that let clients reuse a previously fetched icon and the rate-limit boundaries enforced on icon requests.
Get notification icon
Section titled “Get notification icon”GET /api/v1/notifications/icons/{iconId}
Section titled “GET /api/v1/notifications/icons/{iconId}”Serves a notification icon image. Icon IDs are derived from notification data (session, ID, timestamp, extension).
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
iconId | path | string | Yes | The unique identifier for the icon (e.g., 6_10_1749024932903.png) |
If-None-Match | header | string | No | ETag(s) from an earlier response, or *. A match returns 304. Overrides If-Modified-Since. |
If-Modified-Since | header | string | No | HTTP date; returns 304 when the icon has not changed since then (whole seconds). Ignored when If-None-Match is sent. |
Example request
Section titled “Example request”curl -X GET "https://67e89abc123def456789abcd-890abcdef12345678901cdef-n-1.node-example-1.containers.hoody.com/api/v1/notifications/icons/6_10_1749024932903.png" \ -H "Authorization: Bearer <token>"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-n-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.notifications.icons.get("6_10_1749024932903.png");Response
Section titled “Response”The response body is the icon image. The bytes are returned in one of the supported formats: image/png, image/jpeg, image/webp, image/avif, image/gif, or image/bmp, depending on the file that resolves for the requested icon ID. The body is not JSON.
Response headers:
| Name | Description | Example |
|---|---|---|
Content-Type | MIME type of the image | image/png |
Cache-Control | public, max-age=<ICON_CACHE_MAX_AGE>[, immutable]; default public, max-age=31536000, immutable. Absent when ICON_CACHE_MAX_AGE is 0. | public, max-age=31536000, immutable |
ETag | Weak entity tag (when ENABLE_ETAG is on) | W/"1a2b-5f3c" |
Last-Modified | File modification time as an IMF-fixdate in GMT, whole seconds (when ENABLE_LAST_MODIFIED is on) | Wed, 04 Jun 2025 08:15:22 GMT |
The response has no body. It carries the same Cache-Control, ETag, and Last-Modified headers as the 200 response, so the cached icon can be reused as-is.
Returned when the icon ID fails validation, or when no icon file resolves for the requested ID. A missing icon is reported here rather than as a 404, because this route has no 404 status.
{ "error": "Icon not found", "success": false}| Error Code | Title | Description | Resolution |
|---|---|---|---|
ICON_NOT_FOUND | Icon file not found | No icon file resolves for the requested icon ID | Take the icon ID from a notification’s icon_url and send it unchanged |
INVALID_ICON_ID | Invalid icon ID | The icon ID failed validation: unsupported extension, path traversal, or an otherwise unsafe filename | Allowed extensions are jpg, jpeg, png, webp, avif, gif and bmp |
Returned when the icon endpoint’s rate limit has been exceeded.
{ "success": false, "error": "Rate Limit Exceeded", "message": "You have exceeded the 60 requests in 1 minutes limit on this endpoint."}| Error Code | Title | Description | Resolution |
|---|---|---|---|
RATE_LIMIT_EXCEEDED | Rate limit exceeded | Too many requests from your IP address | Wait the number of seconds in the Retry-After header, then retry. Default limits per client IP per minute: 60 for every route, 10 for notify, 100 for icons |
The Retry-After response header carries the whole seconds until the current window ends (rounded up, at least 1).
{ "details": "An unexpected error occurred", "error": "Internal Server Error", "success": false}