The File object
The Files API attaches files to records and reads them back. A file can go on any of these record types:
CONTACT, LEAD, DEAL, COMPANY, QUOTE, CONTRACT, TASK, NOTE, CASE, CAMPAIGN, OFFERING
The entity value is case-insensitive, so contact and CONTACT both work.
| Field | Type | Notes |
|---|---|---|
id | string | The file ID (read-only). Use it to fetch or delete the file |
entity | string | The record type the file is on, in upper case |
recordId | string | The agentlyleads ID of that record |
kind | string | attachment on every record type except offerings. On an offering, document or image |
fileName | string | The file's name, up to 255 characters |
contentType | string | The MIME type as stored, e.g. application/pdf |
size | integer | Size in bytes |
createdAt | string (ISO 8601) | When the file was attached (read-only) |
downloadUrl | string | Only on GET /api/v1/files/{id}. A signed link to the bytes, valid for 5 minutes |
downloadUrlExpiresAt | string (ISO 8601) | Only alongside downloadUrl. When the link stops working |
Example object
{
"id": "cmq3file0alk34567890",
"entity": "CONTACT",
"recordId": "cmq2cont0alk34567891",
"kind": "attachment",
"fileName": "signed-nda.pdf",
"contentType": "application/pdf",
"size": 184320,
"createdAt": "2026-09-27T14:02:00.000Z"
}Addressing a record
recordId takes the record's agentlyleads ID. For record types that carry an externalId, it also accepts that, so an integration can attach a file using its own ID for the record without looking ours up first.
| Record type | agentlyleads ID | externalId |
|---|---|---|
CONTACT, LEAD, DEAL, COMPANY, TASK, NOTE, OFFERING | Yes | Yes |
QUOTE, CONTRACT, CASE, CAMPAIGN | Yes | No |
The agentlyleads ID is tried first. Responses always report the agentlyleads ID in recordId, whichever one you sent.
Size limits
| How the bytes arrive | Limit |
|---|---|
| Multipart upload, base64 in JSON, or a URL we fetch | 10 MB |
| Upload URL (the two-step flow) | 50 MB |
Some record types set a lower limit of their own, described below. See Uploading files for the three ways to send a file.
Rules for each record type
Most records take any file type. Two have rules of their own, and the API applies them exactly as the record pages in the app do.
Offerings. An offering keeps product photos and documents apart, and the API sorts a file into one or the other by its type:
- An image (
image/*) becomes one of the offering's product photos, withkind: "image". Photos are limited to 10 MB each and 12 per offering. - Anything else is a document, with
kind: "document", and must be a PDF, Excel, CSV or Word file. Documents are limited to 25 MB each (10 MB when sent directly rather than through an upload URL) and 20 per offering. Remove one before adding a 21st.
When the MIME type is missing or application/octet-stream, the file extension (.pdf, .xlsx, .xls, .csv, .docx, .doc) decides. A file whose type is known and not on that list is refused even if its name ends in .pdf.
Campaigns. A file on a campaign is sent as an attachment with every recipient email. For that reason files can only be added or removed while the campaign is in DRAFT, SCHEDULED or OUTREACH status. Once it has sent, its files are fixed, because they describe mail that has already gone out.
Notes on specific fields
No uploader is recorded for API uploads. A file added through the app remembers who added it. A file added with an API key does not, since a key belongs to the workspace rather than a person.
downloadUrl always downloads. The link is served as an attachment, so opening it saves the file instead of rendering it in the browser. The link expires after 5 minutes; call GET /api/v1/files/{id} again for a fresh one.
Product photos report what we know. A photo's fileName is its alt text, and its size and contentType come from storage. When those were never recorded for a photo, they read 0 and image/*.
File storage has to be configured on the deployment. If it isn't, uploading a file, requesting an upload URL and fetching a download link all return 503 with "File storage isn't configured for this workspace."