Files and attachments
The attachments API separates metadata reads from file access. List and get operations never expose an internal storage path or download credential. When you need the bytes, request a short-lived bearer URL for one attachment.
List attachments for a resource
Section titled “List attachments for a resource”GET /v1/attachments requires both entity_type and entity_id:
curl "https://api.agencytitan.com/v1/attachments?entity_type=task&entity_id=11111111-1111-4111-8111-111111111111&sort=created_at&order=desc" \ --header "Authorization: Bearer $AGENCYTITAN_API_KEY" \ --header "Accept: application/json"The operation supports the standard limit, offset, sort, and order parameters plus case-insensitive search over filename and content type. The current entity_type enum is published in the operation schema; use that enum instead of sending an arbitrary resource name.
Before returning metadata, AgencyTitan reads the parent resource through its normal public authorization path. If the caller cannot read the parent, it cannot enumerate the parent’s attachments.
Each item contains:
id, used by metadata and download-URL operationsfilename,content_type, andsize_bytescreated_atand nullablecreated_byparent_entity.typeandparent_entity.id
Get attachment metadata
Section titled “Get attachment metadata”Use GET /v1/attachments/{id} when you already know the attachment ID. AgencyTitan re-evaluates read access to the parent before returning the same metadata shape. The response does not contain file bytes or a URL.
Issue a download URL
Section titled “Issue a download URL”POST /v1/attachments/{id}/download-url mints a short-lived bearer credential. It uses POST because it issues a credential, although it does not change product data.
curl --request POST "https://api.agencytitan.com/v1/attachments/22222222-2222-4222-8222-222222222222/download-url" \ --header "Authorization: Bearer $AGENCYTITAN_API_KEY" \ --header "Content-Type: application/json" \ --data '{"expires_in": 300}'expires_in is measured in seconds. It defaults to 300, with a minimum of 60 and a maximum of 3600.
The response uses the standard single-item envelope:
{ "data": { "url": "https://storage.example.com/signed/file", "expires_at": "2026-08-08T14:35:00.000Z", "filename": "kickoff-notes.pdf", "content_type": "application/pdf", "size_bytes": 24576 }}Read access to the parent is checked again when the URL is issued. The returned URL is transferable and grants temporary access without the AgencyTitan authorization header, so treat it as a secret:
- Request it only when the download is ready to begin.
- Use the shortest practical TTL.
- Do not log, persist, cache, or send it to an untrusted client.
- Issue a new URL after
expires_at; do not attempt to refresh or modify the signed URL. - If parent access is revoked after issuance, assume the URL can remain usable until its TTL expires.
Attachment references in GET /v1/ticket-messages contain metadata only. Pass the referenced attachment ID to the download-URL operation when the caller is ready to fetch it.