Attachment API
Contents
The Attachment API provides direct access to Content Attachments without processing.
Location
By default, the API is available at:
http://localhost:8080/api/media:attachment/
The exact public URL can differ per environment based on virtual host configuration, which is commonly used to expose the API on a friendlier path — for example https://media.example.com/media:attachment/.
Headless clients obtain URL components through Guillotine: use mediaUrl { path queryString } for a media item’s original file, or attachments { attachmentUrl { path queryString } } for individual attachments. Prefix the returned path with your public API or media base URL, then append queryString unchanged. See Attachments for an example and Guillotine’s URL documentation for client handling.
Attachment URL structure
The attachment URL consists of the following components:
-
Media Locator with an optional (branch)
<project>(:<branch>)/<content-id>
masteris the default branch (referring to published content). Specifyingmasterbranch is an error - to avoid cache pollution. Since we only havemasteranddraftthere are only two options:/<project>/and/<project>:draft/ -
(Optional) fingerprint
:<attachment-fingerprint>- the fingerprint of the attachment.
If fingerprint is not supplied the response will not contain "immutable"Cache-Controlheader. -
Attachment name
<attachment-name>is not the Content Name, but the name of the attachment stored within the content. -
(Optional) download parameter
?download- the response will set theContent-Dispositionheader, if specified.
Example of an attachment URL on the root of a live site behind a Virtual Host:
/_/media:attachment/media-project/c82262a6-77d6-4276-b0e7-fe82f4eb57b8:ec25d6e4126c7064f82aaab8b34693fc/attachment.png?download
Media scope
You may limit which projects and branches are accessible by mounting the API in a Virtual Host context.
Use the setting endpoint.media.scope = <project1:draft>, <project2> in the Virtual Host Context.
Response
A successful response streams the attachment binary in the body. The API accepts GET, HEAD, and OPTIONS — any other method returns 405 Method Not Allowed.
Headers
-
Content-Type -
Set to the attachment’s MIME type. SVG attachments (
.svg,.svgz) are always served asimage/svg+xml. -
Content-Length -
Size of the attarchment, in bytes.
-
Accept-Ranges -
Always set to
bytes, signalling that the API supports partial downloads via theRangerequest header (see Range requests). -
Cache-Control -
Set only when the URL includes a fingerprint that matches the current binary hash. The value is taken from
media.public.cacheControlfor content publicly readable on themasterbranch, and frommedia.private.cacheControlotherwise. Requests without a fingerprint, or with a stale one, receive noCache-Controlheader and are therefore treated as non-cacheable by intermediaries. -
Content-Security-Policy -
Set when configured via the
media.contentSecurityPolicyportal config option. SVG responses use the separatemedia.contentSecurityPolicy.svgsetting, which lets you tighten policy specifically for the inline-script-capable image format. -
Content-Disposition -
Set to
attachment; filename="<name>"only when the?downloadquery parameter is present, prompting browsers to save the file rather than render it inline. -
Content-Encoding -
The platform-wide gzip filter is disabled by default (
gzip.enabled = false), so attachments are served uncompressed unless an operator opts in. This default keeps the API edge-cache and CDN friendly — so that services like Fastly can perform their own conditional compression and chunking without conflicting with an upstreamContent-Encoding.
Range requests
The API honours Range: bytes=… request headers, allowing clients to resume interrupted downloads or stream large media progressively.
-
Single range →
206 Partial ContentwithContent-Range: bytes <start>-<end>/<total>and a body containing the requested slice. -
Multiple ranges →
206 Partial ContentwithContent-Type: multipart/byteranges; boundary=…; the body is a multipart payload with each range as a separate part. -
Out-of-bounds range →
416 Requested Range Not SatisfiablewithContent-Range: bytes */<total>and an empty body.
GET /api/media:attachment/myproject/abc123:fp/large-video.mp4 HTTP/1.1
Range: bytes=0-1048575
HTTP/1.1 206 Partial Content
Content-Type: video/mp4
Content-Length: 1048576
Content-Range: bytes 0-1048575/52428800
Accept-Ranges: bytes
Configuration
The Attachment API is driven by two configuration files in your XP installation.
- CMS configuration
-
Controls media-serving behaviour:
media.public.cacheControl,media.private.cacheControl,media.contentSecurityPolicy,media.contentSecurityPolicy.svg, and the per-virtual-hostendpoint.media.scopeattribute. - System configuration
-
Controls platform-wide HTTP behaviour, including the Jetty gzip filter (
gzip.enabled,gzip.minSize) referenced in the headers section above.