Skip to content
FiveCord Docs

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.

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.

Every media read route can produce these statuses in addition to the ones in its own table.

StatusBodyCondition
403ForbiddenThe cross-origin read policy refuses the request Origin on an mp or upload endpoint
404Not foundThe path is not a media route, the endpoint runs in relay mode, or the object does not exist
405Method not allowedThe method is neither GET nor HEAD
413Payload too largeThe stored object exceeds the 500 MiB media bound
502Bad gatewayThe object store could not be read
GET/attachments/{path}Unauthenticated

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.

FieldTypeDescription
path1stringThe 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

FieldTypeDescription
width?integerThe output width in pixels (1 through the decoded edge bound, any other value returns 400)
height?integerThe output height in pixels under the same rule
format?stringThe output format under the attachment and external format contract (any other value returns 400)
quality?stringThe encoder profile under the quality contract
animated?booleanWhether animated output is requested
effort?1integerThe WebP encoder effort, clamped to 9
download?booleanWhether attachment disposition is requested
ex?2stringThe expiry of the signed URL, as 8 lowercase hexadecimal digits of Unix seconds, or 0 on a data package URL
is?2stringThe issue time of the signed URL, as 8 lowercase hexadecimal digits of Unix seconds
hm?2stringThe signature, as 64 lowercase hexadecimal digits
uc?2stringThe 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.

StatusBodyCondition
200Complete media representationThe object and selected representation are available
206Selected media bytesOne range is satisfiable
400Bad requestThe decoded key, a dimension, the format, or the transformation request is invalid, or the transformation failed
404Not foundThe attachment object does not exist and the signed attachment URL policy is off or report
404This content is no longer available.The signed attachment URL policy refuses the signature, or the object does not exist under enforce
416emptyThe range is unsatisfiable
504Gateway timeoutTransformation capacity was unavailable or the transformation exceeded its deadline

Common responses also apply.

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:

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.

FieldTypeDescription
signaturestringThe signature from the issued URL
targetstringThe 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.

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.

FieldTypeDescription
width?integerThe output width in pixels (1 through the decoded edge bound, any other value returns 400)
height?integerThe output height in pixels under the same rule
format?stringThe output format under the attachment and external format contract (any other value returns 400)
quality?stringThe encoder profile under the quality contract
animated?booleanWhether animated output is requested
download?booleanWhether 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.

StatusBodyCondition
200Complete external representationThe validated origin returned a complete representation
2061Selected external bytesThe origin answered a forwarded range, or a range over buffered or transformed bytes is satisfiable
400Bad requestThe path shape, decoded URL, redirect target, transformation request, or transformation is invalid or prohibited
401UnauthorizedThe path signature is invalid
413Payload too largeThe origin declared or delivered more than 500 MiB
416emptyA local range is unsatisfiable
502Bad gatewayThe origin could not be reached, exceeded the redirect bound, or returned an unsuccessful status that the paragraph below this table does not list
503Service unavailableFiveCord could not reserve or allocate a buffer for the origin body
504Gateway timeoutTransformation 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.

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/themes/{path}Unauthenticated

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.

FieldTypeDescription
path1stringThe 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.

StatusBodyCondition
200Complete CSS representationThe theme object is available
206Selected CSS bytesOne range is satisfiable
400Bad requestThe decoded theme key is invalid
416emptyThe 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-sounds/{user_id}/{filename}Unauthenticated

Returns the stored audio of a user entrance sound. The entrance sounds resource writes the object to entrance-sounds/{user_id}/{hash}.{ext}.

FieldTypeDescription
user_id1stringThe owning user snowflake
filename2string{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.

StatusBodyCondition
200Complete audio representationThe sound object is available
206Selected audio bytesOne range is satisfiable
416emptyThe range is unsatisfiable

Common responses also apply.

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.

FieldTypeDescription
size?1integerThe requested square edge in pixels, snapped to the size ladder and clamped to the asset class
format?2stringThe requested output format, also accepted under the name fmt
quality?stringThe encoder profile under the quality contract, defaulting to high
animated?3booleanWhether animated output is requested
download?booleanWhether 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.

StatusBodyCondition
200Complete asset representationThe original or transformed asset is available
206Selected asset bytesOne range is satisfiable
400Bad requestAn owner segment of . or .., or a hash of a_ on a path other than an emoji or sticker path, makes the storage key unsafe
404Not foundThe path is not a valid asset path or the asset does not exist
416emptyThe range is unsatisfiable
5001Transcode failedA required transcode failed and the source is not directly displayable
504Gateway timeoutTransformation 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/avatars/{user_id}/{hash}.{ext}Unauthenticated

Returns the user avatar under the icon size class.

FieldTypeDescription
user_idstringThe owning user snowflake paired with the avatar hash
hashstringThe avatar hash, under the image asset contract
extstringThe path extension, which selects the output format

The image asset response applies.

GET/icons/{guild_id}/{hash}.{ext}Unauthenticated

Returns the guild icon under the icon size class.

FieldTypeDescription
guild_idstringThe owning guild snowflake paired with the icon hash
hashstringThe icon hash, under the image asset contract
extstringThe path extension, which selects the output format

The image asset response applies.

GET/branding/{entity_id}/{hash}.{ext}Unauthenticated

Returns the instance branding image written by Create branding asset, under the icon size class.

FieldTypeDescription
entity_idstringThe instance branding entity key supplied by the branding URL
hashstringThe branding hash, under the image asset contract
extstringThe path extension, which selects the output format

The image asset response applies.

GET/banners/{owner_id}/{hash}.{ext}Unauthenticated

Returns the owner banner under the banner size class.

FieldTypeDescription
owner_idstringThe owning user or guild snowflake paired with the banner hash
hashstringThe banner hash, under the image asset contract
extstringThe path extension, which selects the output format

The image asset response applies.

GET/splashes/{guild_id}/{hash}.{ext}Unauthenticated

Returns the guild splash under the banner size class.

FieldTypeDescription
guild_idstringThe owning guild snowflake paired with the splash hash
hashstringThe splash hash, under the image asset contract
extstringThe path extension, which selects the output format

The image asset response applies.

GET/embed-splashes/{guild_id}/{hash}.{ext}Unauthenticated

Returns the guild embed splash under the banner size class.

FieldTypeDescription
guild_idstringThe owning guild snowflake paired with the embed splash hash
hashstringThe embed splash hash, under the image asset contract
extstringThe path extension, which selects the output format

The image asset response applies.

GET/guilds/{guild_id}/users/{user_id}/avatars/{hash}.{ext}Unauthenticated

Returns the guild member avatar under the icon size class.

FieldTypeDescription
guild_idstringThe guild snowflake owning the member asset
user_idstringThe member user snowflake paired with the member avatar hash
hashstringThe member avatar hash, under the image asset contract
extstringThe path extension, which selects the output format

The image asset response applies.

GET/guilds/{guild_id}/users/{user_id}/banners/{hash}.{ext}Unauthenticated

Returns the guild member banner under the banner size class.

FieldTypeDescription
guild_idstringThe guild snowflake owning the member asset
user_idstringThe member user snowflake paired with the member banner hash
hashstringThe member banner hash, under the image asset contract
extstringThe path extension, which selects the output format

The image asset response applies.

GET/emojis/{emoji_id}.{ext}Unauthenticated

Returns the emoji image under the emoji size class with a square cover crop.

FieldTypeDescription
emoji_id1stringThe emoji snowflake, which is also the storage key
ext2stringThe 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.

The image asset response applies.

GET/stickers/{sticker_id}.{ext}Unauthenticated

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.

FieldTypeDescription
sticker_id1stringThe sticker snowflake, which is also the storage key
extstringThe 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.

The image asset response applies.

GET/{key}Unauthenticated

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.

FieldTypeDescription
key1stringThe 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

StatusBodyCondition
200Complete objectThe object is available
206Selected bytesOne range is satisfiable
400Bad requestThe decoded key is invalid
416emptyThe range is unsatisfiable

Common responses also apply.

These paths are not part of the public API surface and are not published by instance discovery. A client MUST NOT depend on them.

PathMethodDescription
/_healthGETReturns 200 while the process is running
/_metricsGETReturns the Prometheus text exposition of the process. A request from a non-loopback address returns 403
/_metadataPOSTExtracts media metadata, a placeholder, and an optional NSFW verdict for the HTTP API
/_sniffPOSTReturns the media type detected in the first 8 KiB of a staged upload for the HTTP API
/_thumbnailPOSTProduces a WebP thumbnail of a staged upload for the HTTP API
/_framesPOSTExtracts 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.