Read and asset routes
A Media Proxy read route resolves one path to one file and returns it. These paths are unversioned and sit under the base URL published as endpoints.media by instance discovery. The static object read uses endpoints.static_cdn.
Shared route contract
Section titled “Shared route contract”Methods and Authorisation define the contract every route here uses. No route here has a request-count rate limit.
Selector parsing defines query decoding. Byte ranges defines which ranges are recognised and which headers a 206 or 416 has.
Common responses
Section titled “Common responses”Every media read route can produce these statuses in addition to the ones in its own table.
| Status | Body | Condition |
|---|---|---|
| 403 | Forbidden | The cross-origin read policy refuses the request Origin on an mp or upload endpoint |
| 404 | Not found | The path is not a media route, the endpoint runs in relay mode, or the object does not exist |
| 405 | Method not allowed | The method is neither GET nor HEAD |
| 413 | Payload too large | The stored object exceeds the 500 MiB media bound |
| 502 | Bad gateway | The object store could not be read |
Get attachment
Section titled “Get attachment”GET/attachments/{path}Returns the attachment identified by the path, optionally transformed. The path and its signature come from the attachment URL the HTTP API returned. Request that URL as issued. A transformation parameter can be added to its query string.
Path parameters
Section titled “Path parameters”| Field | Type | Description |
|---|---|---|
| path1 | string | The attachment object path from a message attachment object |
1 FiveCord issues {channel_id}/{attachment_id}/{filename}. After percent-decoding, the storage key must be non-empty, must not begin with /, and must not contain an empty, ., or .. segment, or the route returns 400
Query parameters
Section titled “Query parameters”| Field | Type | Description |
|---|---|---|
| width? | integer | The output width in pixels (1 through the decoded edge bound, any other value returns 400) |
| height? | integer | The output height in pixels under the same rule |
| format? | string | The output format under the attachment and external format contract (any other value returns 400) |
| quality? | string | The encoder profile under the quality contract |
| animated? | boolean | Whether animated output is requested |
| effort?1 | integer | The WebP encoder effort, clamped to 9 |
| download? | boolean | Whether attachment disposition is requested |
| ex?2 | string | The expiry of the signed URL, as 8 lowercase hexadecimal digits of Unix seconds, or 0 on a data package URL |
| is?2 | string | The issue time of the signed URL, as 8 lowercase hexadecimal digits of Unix seconds |
| hm?2 | string | The signature, as 64 lowercase hexadecimal digits |
| uc?2 | string | The data package marker, always dp when present |
1 Read only on this route, and an empty or unparsable value is ignored. Only lossless animated WebP output uses a value above 6
2 Read under the report or enforce signed attachment URL policy, which also defines how they are parsed. enforce requires ex, is, and hm, and reads uc on every URL, where its presence selects the data package URL grammar
When a transformation runs defines the trigger.
When a transformation is requested, Range selects bytes from the transformed result.
An SVG attachment with a transformation parameter is rasterised, and format and quality select the output as they do for any other source, defaulting to WebP. Without a transformation parameter, only a Media Proxy in mp deployment mode rasterises it, always as lossless WebP. A Media Proxy in upload mode returns the stored SVG bytes.
A video source requires an explicit image format. A video request with width, height, quality, or animated=true and no format returns 400. A source that is neither an image nor a video returns 400 when format is present. Without format, FiveCord returns it unchanged.
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | Complete media representation | The object and selected representation are available |
| 206 | Selected media bytes | One range is satisfiable |
| 400 | Bad request | The decoded key, a dimension, the format, or the transformation request is invalid, or the transformation failed |
| 404 | Not found | The attachment object does not exist and the signed attachment URL policy is off or report |
| 404 | This content is no longer available. | The signed attachment URL policy refuses the signature, or the object does not exist under enforce |
| 416 | empty | The range is unsatisfiable |
| 504 | Gateway timeout | Transformation capacity was unavailable or the transformation exceeded its deadline |
Common responses also apply.
Get signed external media
Section titled “Get signed external media”GET/external/{signature}/{target}Returns external media through FiveCord, optionally transformed. Use the signed URL supplied by the HTTP API.
FiveCord constructs the signed path and exposes it on these fields:
proxy_urlof an embed media objectproxy_icon_urlof an embed author objectproxy_icon_urlof an embed footer objectproxy_urlof a resolved GIF entryproxy_srcof a GIF media format object
A field holds a signed external path only when its source URL is external. A URL already under the Media Proxy endpoint keeps that endpoint, and gets an attachment URL signature when it names an attachment of this instance. Any URL the deployment cannot sign is returned verbatim, so a client MUST request the value exactly as issued and MUST NOT assume it has the signed shape.
Path parameters
Section titled “Path parameters”| Field | Type | Description |
|---|---|---|
| signature | string | The signature from the issued URL |
| target | string | The opaque target from the issued URL |
A client MUST preserve both components exactly as issued and MUST NOT decode or reconstruct either one. The signature covers the target component alone, so adding or changing a query parameter does not invalidate it. A path with no / after /external/ returns 400.
Target validation
Section titled “Target validation”FiveCord validates the decoded target before every request and again for every redirect hop. It must be at most 8,192 bytes, must use http or https, must have a non-zero port when it names one, and must not contain credentials or a control character. A fragment is dropped before the fetch.
The target must resolve to a public internet address. Private, local and reserved addresses are rejected, including through redirects.
A hostname whose lookup fails or resolves to no address returns 400.
A redirect beyond the five-redirect bound, a repeated URL, or a redirect without a Location header returns 502. A redirect to a rejected target returns 400.
Query parameters
Section titled “Query parameters”| Field | Type | Description |
|---|---|---|
| width? | integer | The output width in pixels (1 through the decoded edge bound, any other value returns 400) |
| height? | integer | The output height in pixels under the same rule |
| format? | string | The output format under the attachment and external format contract (any other value returns 400) |
| quality? | string | The encoder profile under the quality contract |
| animated? | boolean | Whether animated output is requested |
| download? | boolean | Whether attachment disposition is requested |
effort is read only on Get attachment and is ignored here.
A transformation begins when width, height, format, or quality is present, when animated resolves to true, when the target filename ends in .svg, or when the origin body is SVG by media type or by its first bytes. A transforming request forwards no Range to the origin and applies the client range to the transformed bytes, so a satisfiable range returns 206 and an unsatisfiable range returns 416.
A non-transforming request can forward the range to the origin. Handle both 200 and 206 responses and use their range headers, as described in Byte ranges.
FiveCord returns 503 when it cannot reserve or allocate a buffer for the origin body. A HEAD with no transformation and no forwarded range can build Content-Type and Content-Length from the origin’s own HEAD response, so those headers can differ from a GET response.
A video target requires an explicit image format to produce a thumbnail. Without one, FiveCord returns the original bytes unchanged, and it does the same for a target that is neither an image nor a video.
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | Complete external representation | The validated origin returned a complete representation |
| 2061 | Selected external bytes | The origin answered a forwarded range, or a range over buffered or transformed bytes is satisfiable |
| 400 | Bad request | The path shape, decoded URL, redirect target, transformation request, or transformation is invalid or prohibited |
| 401 | Unauthorized | The path signature is invalid |
| 413 | Payload too large | The origin declared or delivered more than 500 MiB |
| 416 | empty | A local range is unsatisfiable |
| 502 | Bad gateway | The origin could not be reached, exceeded the redirect bound, or returned an unsuccessful status that the paragraph below this table does not list |
| 503 | Service unavailable | FiveCord could not reserve or allocate a buffer for the origin body |
| 504 | Gateway timeout | Transformation capacity was unavailable or the transformation exceeded its deadline |
1 A forwarded range relays the origin Content-Range and Content-Length unchanged and omits either header the origin did not send, so a chunked origin 206 produces a 206 with no Content-Length. A local range over buffered or transformed bytes always has both
An origin status of 400, 401, 403, 404, 405, 406, 408, 409, 410, 411, 412, 413, 414, 415, 416, 428, or 429 reaches the client unchanged with the plain-text body Upstream fetch failed, and the origin body and headers are not returned. Any other unsuccessful origin status becomes 502. Common responses also apply.
Side effects
Section titled “Side effects”The route requests the target from the validated third-party origin using the user agent Mozilla/5.0 (compatible; FiveCordbot/1.0; +https://fivecord.tech), which is visible to that origin.
Get theme CSS
Section titled “Get theme CSS”GET/themes/{path}Returns a theme stylesheet with the fixed media type text/css; charset=utf-8. The themes resource writes the object to themes/{theme_id}.css.
Path parameters
Section titled “Path parameters”| Field | Type | Description |
|---|---|---|
| path1 | string | The path below /themes/, whose raw route path must end in the exact lowercase suffix .css |
1 After percent-decoding, the storage key must be non-empty, must not begin with /, and must not contain an empty, ., or .. segment, or the route returns 400
The route selects no representation and accepts a Range.
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | Complete CSS representation | The theme object is available |
| 206 | Selected CSS bytes | One range is satisfiable |
| 400 | Bad request | The decoded theme key is invalid |
| 416 | empty | The range is unsatisfiable |
Common responses also apply. A path that does not end in .css is not a theme path and falls through to 404.
Get entrance sound
Section titled “Get entrance sound”GET/entrance-sounds/{user_id}/{filename}Returns the stored audio of a user entrance sound. The entrance sounds resource writes the object to entrance-sounds/{user_id}/{hash}.{ext}.
Path parameters
Section titled “Path parameters”| Field | Type | Description |
|---|---|---|
| user_id1 | string | The owning user snowflake |
| filename2 | string | {hash}.{ext} for the stored sound |
1 A non-empty run of ASCII digits. Any other value makes the path unroutable and returns 404
2 Use the hash returned by the API. The extension is the exact lowercase mp3, ogg, m4a, or wav
The route selects no representation, accepts a Range, and sends no Content-Disposition. A successful response streams the stored bytes with the detected audio media type and the one-year no-transform cache policy.
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | Complete audio representation | The sound object is available |
| 206 | Selected audio bytes | One range is satisfiable |
| 416 | empty | The range is unsatisfiable |
Common responses also apply.
Image asset contract
Section titled “Image asset contract”An image asset is a stored picture FiveCord serves at a requested size and format, such as an avatar, a guild icon, or an emoji. The asset hash comes from the resource object, and the path combines the owning resource, that hash, and a file extension. On an emoji or sticker path the filename is the identifier itself. The grammar, query parameters, and responses below apply to every image asset route. Asset size selection defines every size class.
A client builds the complete URL from the Media Proxy base URL, the path template for the asset class, the hash, and a file extension.
FiveCord matches an asset path by its shape alone. A path with the wrong number of segments, an empty owner segment, or a filename without exactly one dot is not an asset path and returns 404. A hash containing anything but ASCII letters, digits, and _ returns 404 as well, as does an extension outside the known image set. The known set is png, jpg, jpeg, webp, gif, apng, avif, heic, heif, jxl, and svg, matched case-insensitively.
Use the hash returned by the API. Do not calculate one from the image yourself.
An owner segment of the literal . or .. parses as an asset path but produces an unsafe storage key and returns 400. So does a hash of the literal a_ on an avatar, icon, branding, banner, splash, embed splash, or guild member asset path.
Query parameters
Section titled “Query parameters”| Field | Type | Description |
|---|---|---|
| size?1 | integer | The requested square edge in pixels, snapped to the size ladder and clamped to the asset class |
| format?2 | string | The requested output format, also accepted under the name fmt |
| quality? | string | The encoder profile under the quality contract, defaulting to high |
| animated?3 | boolean | Whether animated output is requested |
| download? | boolean | Whether attachment disposition is requested |
1 An absent or unparsable value selects 128 before clamping. No value is rejected
2 Accepts case-insensitive auto, png, jpg, jpeg, webp, gif, apng, and avif, where auto keeps path-based selection and avif selects WebP. Any other value falls back to path-based selection, and a sticker path always selects WebP and ignores the field
3 An absent value keeps the hash-derived default, which is animated only for an a_ hash. PNG and JPEG output has no animation
width, height, and effort are not read on an asset path, and no asset query value produces a 400. The route accepts a Range over the selected representation.
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | Complete asset representation | The original or transformed asset is available |
| 206 | Selected asset bytes | One range is satisfiable |
| 400 | Bad request | An owner segment of . or .., or a hash of a_ on a path other than an emoji or sticker path, makes the storage key unsafe |
| 404 | Not found | The path is not a valid asset path or the asset does not exist |
| 416 | empty | The range is unsatisfiable |
| 5001 | Transcode failed | A required transcode failed and the source is not directly displayable |
| 504 | Gateway timeout | Transformation capacity was unavailable or the transformation exceeded its deadline |
1 A failed transcode whose stored media type begins with image/ and is not image/avif, image/heic, image/heif, or SVG instead returns 200 with the original stored bytes and media type but without Content-Disposition
Common responses also apply. Transformations defines geometry, animation, output formats, and original representation selection.
Get user avatar
Section titled “Get user avatar”GET/avatars/{user_id}/{hash}.{ext}Returns the user avatar under the icon size class.
Path parameters
Section titled “Path parameters”| Field | Type | Description |
|---|---|---|
| user_id | string | The owning user snowflake paired with the avatar hash |
| hash | string | The avatar hash, under the image asset contract |
| ext | string | The path extension, which selects the output format |
Response
Section titled “Response”The image asset response applies.
Get guild icon
Section titled “Get guild icon”GET/icons/{guild_id}/{hash}.{ext}Returns the guild icon under the icon size class.
Path parameters
Section titled “Path parameters”| Field | Type | Description |
|---|---|---|
| guild_id | string | The owning guild snowflake paired with the icon hash |
| hash | string | The icon hash, under the image asset contract |
| ext | string | The path extension, which selects the output format |
Response
Section titled “Response”The image asset response applies.
Get instance branding
Section titled “Get instance branding”GET/branding/{entity_id}/{hash}.{ext}Returns the instance branding image written by Create branding asset, under the icon size class.
Path parameters
Section titled “Path parameters”| Field | Type | Description |
|---|---|---|
| entity_id | string | The instance branding entity key supplied by the branding URL |
| hash | string | The branding hash, under the image asset contract |
| ext | string | The path extension, which selects the output format |
Response
Section titled “Response”The image asset response applies.
Get owner banner
Section titled “Get owner banner”GET/banners/{owner_id}/{hash}.{ext}Returns the owner banner under the banner size class.
Path parameters
Section titled “Path parameters”| Field | Type | Description |
|---|---|---|
| owner_id | string | The owning user or guild snowflake paired with the banner hash |
| hash | string | The banner hash, under the image asset contract |
| ext | string | The path extension, which selects the output format |
Response
Section titled “Response”The image asset response applies.
Get guild splash
Section titled “Get guild splash”GET/splashes/{guild_id}/{hash}.{ext}Returns the guild splash under the banner size class.
Path parameters
Section titled “Path parameters”| Field | Type | Description |
|---|---|---|
| guild_id | string | The owning guild snowflake paired with the splash hash |
| hash | string | The splash hash, under the image asset contract |
| ext | string | The path extension, which selects the output format |
Response
Section titled “Response”The image asset response applies.
Get guild embed splash
Section titled “Get guild embed splash”GET/embed-splashes/{guild_id}/{hash}.{ext}Returns the guild embed splash under the banner size class.
Path parameters
Section titled “Path parameters”| Field | Type | Description |
|---|---|---|
| guild_id | string | The owning guild snowflake paired with the embed splash hash |
| hash | string | The embed splash hash, under the image asset contract |
| ext | string | The path extension, which selects the output format |
Response
Section titled “Response”The image asset response applies.
Get guild member avatar
Section titled “Get guild member avatar”GET/guilds/{guild_id}/users/{user_id}/avatars/{hash}.{ext}Returns the guild member avatar under the icon size class.
Path parameters
Section titled “Path parameters”| Field | Type | Description |
|---|---|---|
| guild_id | string | The guild snowflake owning the member asset |
| user_id | string | The member user snowflake paired with the member avatar hash |
| hash | string | The member avatar hash, under the image asset contract |
| ext | string | The path extension, which selects the output format |
Response
Section titled “Response”The image asset response applies.
Get guild member banner
Section titled “Get guild member banner”GET/guilds/{guild_id}/users/{user_id}/banners/{hash}.{ext}Returns the guild member banner under the banner size class.
Path parameters
Section titled “Path parameters”| Field | Type | Description |
|---|---|---|
| guild_id | string | The guild snowflake owning the member asset |
| user_id | string | The member user snowflake paired with the member banner hash |
| hash | string | The member banner hash, under the image asset contract |
| ext | string | The path extension, which selects the output format |
Response
Section titled “Response”The image asset response applies.
Get emoji image
Section titled “Get emoji image”GET/emojis/{emoji_id}.{ext}Returns the emoji image under the emoji size class with a square cover crop.
Path parameters
Section titled “Path parameters”| Field | Type | Description |
|---|---|---|
| emoji_id1 | string | The emoji snowflake, which is also the storage key |
| ext2 | string | The path extension, which selects the output format |
1 Any non-empty run of ASCII letters, digits, and _. FiveCord clients request {emoji_id}.webp
2 An extension whose encoder is not enabled for output selects WebP instead
Emoji requests default to static output. Use animated=true for animation, without adding an a_ prefix to the identifier.
Response
Section titled “Response”The image asset response applies.
Get sticker image
Section titled “Get sticker image”GET/stickers/{sticker_id}.{ext}Returns the sticker image under the sticker size class with a square cover crop. Output is always WebP, except that an animated GIF source stays GIF when animated resolves to true.
Path parameters
Section titled “Path parameters”| Field | Type | Description |
|---|---|---|
| sticker_id1 | string | The sticker snowflake, which is also the storage key |
| ext | string | The path extension, used only as the source hint |
1 Any non-empty run of ASCII letters, digits, and _. FiveCord clients request {sticker_id}.webp
Sticker requests default to static output. Use animated=true for animation, without adding an a_ prefix to the identifier.
Response
Section titled “Response”The image asset response applies.
Get static object
Section titled “Get static object”GET/{key}Returns a raw object from the static bucket. The route exists only on the static deployment mode, published as endpoints.static_cdn by instance discovery. It serves default avatars, client bundles, and other published files.
The complete request path is the storage key after percent-decoding. The route applies no transformation and reads no query parameter. The response uses the detected media type and the one-year cache policy, and a static endpoint omits X-Robots-Tag.
Path parameters
Section titled “Path parameters”| Field | Type | Description |
|---|---|---|
| key1 | string | The object key in the static bucket, taken from the complete request path |
1 After percent-decoding, the key must be non-empty, must not begin with /, and must not contain an empty, ., or .. segment, or the route returns 400
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | Complete object | The object is available |
| 206 | Selected bytes | One range is satisfiable |
| 400 | Bad request | The decoded key is invalid |
| 416 | empty | The range is unsatisfiable |
Common responses also apply.
Operator and internal endpoints
Section titled “Operator and internal endpoints”These paths are not part of the public API surface and are not published by instance discovery. A client MUST NOT depend on them.
| Path | Method | Description |
|---|---|---|
/_health | GET | Returns 200 while the process is running |
/_metrics | GET | Returns the Prometheus text exposition of the process. A request from a non-loopback address returns 403 |
/_metadata | POST | Extracts media metadata, a placeholder, and an optional NSFW verdict for the HTTP API |
/_sniff | POST | Returns the media type detected in the first 8 KiB of a staged upload for the HTTP API |
/_thumbnail | POST | Produces a WebP thumbnail of a staged upload for the HTTP API |
/_frames | POST | Extracts one JPEG video frame for the HTTP API |
/_metadata, /_sniff, /_thumbnail, and /_frames require Authorization: Bearer {deployment secret key} and return 401 without it. Their JSON request bodies are bounded, and a body beyond the bound returns 413.
/_sniff returns 200 with a JSON content_type. It is the image, video, or audio media type the Media Proxy detects in the upload, or null when the bytes are SVG or a type it cannot process. An upload key that names no object returns 404.