Files
A file is a document your team has exchanged by email. Carom groups every attachment with the same file name into one file, so a proposal sent back and forth three times is one file with three attachments, each tied to the message that carried it. Use this resource to find documents by type, sender, or the people involved, name and describe them, and download any attachment.
A file is visible to your key when a message it was attached to is visible, or when someone shared the file with your key’s user. Files come only from mail; the API can’t create them. The one endpoint here that accepts bytes, Upload an image, stores avatars for contacts and logos for organizations, and its uploads never become files.
#The file object
Returned by every file endpoint. List responses add shared_with_me; retrieving or updating a single file adds its tasks, comments, and shares.
Attributes
-
idstring · uuidUnique identifier for the file.
-
namestring · nullableDisplay name. Starts as the name the file was first attached under; change it with Update a file.
-
file_namestring · nullableThe file name as attached. Carom groups attachments by this value, and downloads use it.
-
extensionstring · nullableThe part of
file_nameafter the last dot, such aspdf. -
descriptionstring · nullableFree-form notes about the file.
-
attachment_countinteger · nullableHow many times the file has been attached to a message.
-
pinnedboolean · nullableWhether your key’s user has pinned this file.
-
first_sent_atstring · date-time · nullableWhen the earliest attachment was sent.
-
last_sent_atstring · date-time · nullableWhen the most recent attachment was sent. The default sort for List files.
-
sender_email_addressesarray of stringsEvery address that sent a message carrying the file.
-
recipient_email_addressesarray of stringsEvery address those messages went to, including cc and bcc.
-
participantsobjectKeyed by each sender and recipient address. The value is the contact with that address when one is visible to your key, and null otherwise.
-
attachmentsarray of objects · nullableEach time the file was attached to a message visible to your key. Pass an attachment’s
idto Download an attachment or Create a download URL.Show 12 child attributesHide child attributes
idstring · uuidfile_idstring · uuid · nullablesizeinteger · nullableSize in bytes, as the mail provider reported it.
content_typestring · nullableThe MIME type the message declared.
inlineboolean · nullableTrue for an image embedded in the body of the message rather than attached to it.
content_idstring · nullableThe MIME
Content-IDthe message’s HTML body uses to reference this attachment ascid:content_id.decorativebooleanTrue for a signature logo, a tracking pixel, or an image that appears only in quoted earlier messages, rather than a file someone meant to send. List files and Count files leave these out unless you pass
include_decorative=true.sent_atstring · date-time · nullablesender_email_addressstring · nullablerecipient_email_addressesarray of strings-
threadobject · nullableThe thread the message belongs to, with its
id,subject,snippet,participant_email_addresses,participant_names,created_at, andupdated_at.participant_namesmaps each address to the display name in the mail headers, or null when the headers carried none. messageobject · nullableThe message that carried the attachment, with its
idandsnippet.
-
tagsarray of tags · nullableTags applied to this file.
-
shared_with_mebooleanList responses only. True when the file was shared with your key’s user directly or through a group.
{
"id": "2f74c67f-f5c9-4c1b-9dfc-15095b59207f",
"name": "Wildgrove renewal proposal",
"file_name": "Wildgrove-Renewal-2027.pdf",
"extension": "pdf",
"description": "Final pricing for the 14 existing properties. Oakland is priced separately.",
"attachment_count": 2,
"pinned": true,
"first_sent_at": "2026-09-02T22:14:08.614Z",
"last_sent_at": "2026-09-09T16:31:45.287Z",
"sender_email_addresses": ["dana@harborline.example", "priya@wildgrove.example"],
"recipient_email_addresses": ["priya@wildgrove.example", "dana@harborline.example"],
"participants": {
"dana@harborline.example": null,
"priya@wildgrove.example": {
"id": "1f3c9a52-7b0e-4d4a-9c1e-2a6f0d8b3e41",
"name": "Priya Natarajan",
…
}
},
"attachments": [
{
"id": "522c93e3-bf69-4a33-9747-f39a51034d6e",
"file_id": "2f74c67f-f5c9-4c1b-9dfc-15095b59207f",
"size": 482117,
"content_type": "application/pdf",
"inline": false,
"content_id": null,
"decorative": false,
"sent_at": "2026-09-09T16:31:45.287Z",
"sender_email_address": "dana@harborline.example",
"recipient_email_addresses": ["priya@wildgrove.example"],
"thread": {
"id": "f06a7a5f-4a85-423e-8adc-1c26a059eab3",
"subject": "Renewal proposal, revised",
…
},
"message": {
"id": "5fa35c09-d87c-4ff8-99e5-3e078b10267a",
"snippet": "Revised numbers attached. The Oakland pricing is in a separate sheet."
}
},
…
],
"tags": [
{
"id": "0f1e2d3c-4b5a-4968-8776-655443322110",
"name": "Customer",
"color": "#66b185"
}
]
}
#List files
Returns the files visible to your key, 50 per page, most recently sent first. Filter by name, type, sender, participant, dates, tags, or the records involved, and page through the result with a cursor.
A contact_id, organization_id, or space_id must name a record visible to your key. When that record has no email addresses whose correspondence is visible to your key, the list is empty.
By default the list leaves out decorative attachments: signature logos, tracking pixels, and images that appear only in quoted earlier messages. A file whose every attachment is decorative isn’t listed, and the counts, sizes, and dates of the other files cover only their other attachments. Pass include_decorative=true to include them.
Query parameters
-
querystringMatch against
nameandfile_name. Up to 500 characters. -
typestringOnly files with this
extension, such aspdf, without the dot. -
senderstringOnly files sent from this email address.
-
participantstringOnly files sent from or to this email address, including cc and bcc.
-
first_sent_beforestringAn ISO 8601 date. Only files first sent before it.
-
last_sent_afterstringAn ISO 8601 date. Only files most recently sent after it.
-
scopestringRestrict by which mail a file came through. Takes one of the values below or a mailbox id:
personal, your key’s user’s primary mailbox;subscribed, every mailbox they subscribe to; a mailbox id, mail that reached that mailbox.sharedreturns files shared with your key’s user, the same asslice=shared.allapplies no restriction, the same as omitting the parameter.personalsubscribedsharedall -
slicestringtasked: files with a task that belongs to your key’s user.shared: files shared with your key’s user, directly or through a group.pinned: files your key’s user has pinned.taskedsharedpinned -
contact_idstring · uuidOnly files sent from or to this contact’s email addresses.
-
organization_idstring · uuidOnly files sent from or to people at this organization.
-
space_idstring · uuidOnly files in this space.
-
tagsstringComma-separated tag ids, at most 50.
-
tag_operatorstringdefaultanyWhether a file must carry any of the given tags, or all of them.
anyall -
include_decorativebooleandefaultfalseInclude
decorativeattachments, and the files that have only those. -
sortstringdefaultlast_sent_atField to sort by.
sizeis the largest attachment’s size.last_sent_atnamesizeattachment_count -
orderstringDefaults to
ascfornameanddescfor the other sorts.ascdesc -
next_cursorstringOpaque token from the previous page’s
page_info.next_cursor. Omit to start from the beginning. See Pagination.
Returns
-
collectionobjectA page of files and the cursor to the next one.
Show 6 child attributesHide child attributes
-
recordsarray of filesUp to 50 files in the requested order.
-
page_infopage infoWhere this page sits in the full list. Pass
next_cursorback to fetch the next page whilehas_more_afteris true. -
sortstring · nullableThe
sortyou passed, or null when you used the default. -
orderstring · nullableThe
orderyou passed, or null when you used the default. -
filtersobject · nullableThe filters that were applied, echoed back.
-
slice_keystring · nullableThe
slicethat was applied.
-
Errors
- 400
invalid_requestA parameter is malformed, for example a date that isn’t ISO 8601 or more than 50 tag ids. - 400
invalid_cursorThe cursor is unreadable, or came from another list or sort. - 400
unsupported_cursor_directionYou passedprev_cursor. This list pages forward only. - 404
record_not_foundcontact_id,organization_id, orspace_idnames a record that isn’t visible to your key.
curl "https://api.carom.io/files?type=pdf&participant=priya@wildgrove.example" \
-H "Authorization: Bearer $CAROM_API_KEY"
{
"collection": {
"records": [
{
"id": "2f74c67f-f5c9-4c1b-9dfc-15095b59207f",
"name": "Wildgrove renewal proposal",
"file_name": "Wildgrove-Renewal-2027.pdf",
"attachment_count": 2,
"last_sent_at": "2026-09-09T16:31:45.287Z",
"shared_with_me": false,
…
},
{
"id": "b826560b-7df7-4790-bc71-5e994767fb84",
"name": "Oakland site survey",
"file_name": "Oakland-Site-Survey.pdf",
"attachment_count": 1,
"last_sent_at": "2026-09-04T19:05:22.539Z",
"shared_with_me": false,
…
}
],
"page_info": {
"limit": 50,
"next_cursor": null,
"prev_cursor": null,
"has_more_after": false,
"has_more_before": false
},
"sort": null,
"order": null,
"filters": {
"type": "pdf",
"participant": "priya@wildgrove.example"
},
"slice_key": null
}
}
#Retrieve a file
Returns a single file with its attachments, participants, and tags, plus the open tasks, comments, and shares attached to it.
Path parameters
-
idstring · uuidrequiredThe file’s id.
Returns
The file object, wrapped in file, without shared_with_me and with these additional attributes.
Errors
- 404
record_not_foundNo file with that id is visible to your key.
curl https://api.carom.io/files/2f74c67f-f5c9-4c1b-9dfc-15095b59207f \
-H "Authorization: Bearer $CAROM_API_KEY"
{
"file": {
"id": "2f74c67f-f5c9-4c1b-9dfc-15095b59207f",
"name": "Wildgrove renewal proposal",
"file_name": "Wildgrove-Renewal-2027.pdf",
…
"tasks": [
{
"id": "7c6dc498-83ce-44ae-8afd-8b1a3641ed8f",
"description": "Send Priya the renewal redline before the call",
"due": "2026-09-21",
…
}
],
"comments": [],
"shares": []
}
}
#Update a file
Changes a file’s display name or description and leaves the rest alone. Anyone who can see a file can edit these two fields, and everyone who can see it sees the change. The attachments and their file names are not affected.
Path parameters
-
idstring · uuidrequired
Request body application/json
-
fileobjectrequiredShow 2 child attributesHide child attributes
-
namestring · nullableNew display name.
-
descriptionstring · nullableFree-form notes about the file.
-
Returns
The updated file, wrapped in file, in the same shape as Retrieve a file.
Errors
- 400
invalid_requestThe body has nofileobject, or a field isn’t a string. - 404
record_not_foundNo file with that id is visible to your key.
curl -X PATCH https://api.carom.io/files/2f74c67f-f5c9-4c1b-9dfc-15095b59207f \
-H "Authorization: Bearer $CAROM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file": {
"name": "Wildgrove renewal proposal",
"description": "Final pricing for the 14 existing properties. Oakland is priced separately."
}
}'
{
"file": {
"id": "2f74c67f-f5c9-4c1b-9dfc-15095b59207f",
"name": "Wildgrove renewal proposal",
"file_name": "Wildgrove-Renewal-2027.pdf",
"description": "Final pricing for the 14 existing properties. Oakland is priced separately.",
…
}
}
#Count files
Counts the files that List files would return for the same filters, without fetching them. Counting stops at cap when you give one, which keeps the call fast on large accounts.
Query parameters
-
query,type,sender,participant,first_sent_before,last_sent_after,scope,slice,contact_id,organization_id,space_id,tags,tag_operator,include_decorativeAs on List files.
-
capintegerStop counting at this many. When the cap is reached,
totalequalscapandexactis false.
Returns
-
countcountShow 4 child attributesHide child attributes
totalintegerexactbooleanFalse when counting stopped at
cap.cappedbooleanTrue when counting stopped at
cap.capinteger · nullableThe cap that was applied, or null.
Errors
- 400
invalid_requestA parameter is malformed, for example a date that isn’t ISO 8601. - 404
record_not_foundcontact_id,organization_id, orspace_idnames a record that isn’t visible to your key.
curl "https://api.carom.io/files/count?type=pdf&cap=1000" \
-H "Authorization: Bearer $CAROM_API_KEY"
{
"count": {
"total": 263,
"exact": true,
"capped": false,
"cap": 1000
}
}
#Download an attachment
Returns the bytes of one attachment of the file. Attachments of the same file can differ, since each is whatever was attached to its message, so name the one you want with attachment_id.
Downloading an attachment larger than 25 MB can fail with 413 source_too_large.
Path parameters
-
idstring · uuidrequiredThe file’s id.
Query parameters
-
attachment_idstring · uuidrequiredAn
idfrom the file’sattachments.
Returns
The raw bytes. Content-Type is the type the bytes themselves show when Carom recognizes them (common image formats, PDF, HTML, and SVG), whatever the file’s extension says. Otherwise it is chosen from the file’s extension, or is application/octet-stream when the extension is unknown. Content-Disposition is attachment with the file’s file_name, including a UTF-8 filename* form for names outside ASCII.
Errors
- 400
invalid_requestattachment_idis missing. - 404
record_not_foundNo attachment with thatattachment_idis visible to your key, or it belongs to a different file. - 413
source_too_largeThe attachment is larger than 25 MB and can’t be retrieved. - 502
source_fetch_failedThe mail provider didn’t return the attachment. - 502
source_handle_unavailableThe attachment can no longer be retrieved from the mail provider. - 502
storage_unavailableCarom’s file storage didn’t respond. Retry later.
curl -OJ "https://api.carom.io/files/2f74c67f-f5c9-4c1b-9dfc-15095b59207f/download?attachment_id=522c93e3-bf69-4a33-9747-f39a51034d6e" \
-H "Authorization: Bearer $CAROM_API_KEY"
Content-Type: application/pdf
Content-Disposition: attachment; filename="Wildgrove-Renewal-2027.pdf"; filename*=UTF-8''Wildgrove-Renewal-2027.pdf
#Create a download URL
Returns a temporary URL for one attachment that can be fetched without an API key, valid for one hour. Use it to hand a download to a browser or another service instead of proxying the bytes through your own server. Anyone who has the URL can download the attachment until it expires.
The 25 MB limit on Download an attachment applies here too. The URL opens most types in the browser; HTML, SVG, and XML files are served as downloads instead, including an HTML or SVG file with another extension.
Path parameters
-
idstring · uuidrequiredAn attachment’s id, from a file’s
attachments.
Returns
-
presigned_urlstringThe download URL, a signed URL that needs no API key.
-
expires_atstring · date-timeWhen the URL stops working, one hour after the request.
-
filenamestringThe file’s
file_name. -
content_typestringThe type the URL serves, chosen as on Download an attachment: from the bytes when Carom recognizes them, otherwise from the file’s extension.
Errors
- 404
record_not_foundNo attachment with that id is visible to your key. - 413
source_too_largeThe attachment is larger than 25 MB and can’t be retrieved. - 502
source_fetch_failedThe mail provider didn’t return the attachment. - 502
source_handle_unavailableThe attachment can no longer be retrieved from the mail provider. - 502
storage_unavailableCarom’s file storage didn’t respond. Retry later.
curl -X POST https://api.carom.io/attachments/522c93e3-bf69-4a33-9747-f39a51034d6e/presigned_urls \
-H "Authorization: Bearer $CAROM_API_KEY"
{
"presigned_url": "https://files.carom.io/…?signature=…",
"expires_at": "2026-09-19T15:04:10.771Z",
"filename": "Wildgrove-Renewal-2027.pdf",
"content_type": "application/pdf"
}
#Upload an image
Stores an image to use as a contact’s avatar or an organization’s logo. An upload is not a file: it never appears in List files, and the only thing you can do with it is attach it to a record. Upload with kind set to avatar, then pass the returned id as avatar_upload_id when you create or update a contact; for a logo, pass it as logo_upload_id when you create or update an organization.
Each upload can be attached once, only by the user who uploaded it, and only to a record of its kind. Carom deletes uploads that are still unattached 24 hours after they were made.
Carom checks and re-encodes every image. It accepts JPEG, PNG, WebP, GIF, and HEIC files up to 10 MB and 8000 pixels on each side, shrinks the image to at most 512 pixels on its long edge for an avatar or 1024 for a logo, and saves it as PNG if it has transparency and JPEG otherwise. Metadata such as the location a photo was taken is removed. Animated images keep their first frame.
Request body multipart/form-data
-
kindstringrequiredWhat the image is for.
avatarlogo -
filebinaryrequiredThe image, as a file part. Carom identifies the format from the bytes and ignores the declared type and file name.
Returns
HTTP 201 and the upload, wrapped in upload.
-
idstring · uuidPass this as
avatar_upload_idorlogo_upload_id. -
source_urlstringWhere the processed image is served, for a preview.
Errors
- 400
invalid_requestkindis missing or notavatarorlogo, orfileisn’t a file part. - 413
upload_too_largeThe image is larger than 10 MB. - 422
unsupported_image_typeThe bytes aren’t a JPEG, PNG, WebP, GIF, or HEIC image Carom can read. - 422
image_dimensions_too_largeThe image is wider or taller than 8000 pixels. - 422
image_decode_failedThe image could not be re-encoded. - 502
storage_unavailableCarom’s file storage didn’t accept the image. Retry later.
curl https://api.carom.io/uploads \
-H "Authorization: Bearer $CAROM_API_KEY" \
-F "kind=avatar" \
-F "file=@priya.jpg"
{
"upload": {
"id": "e9525330-ab78-4b0d-83ba-f6bc669d7ed4",
"source_url": "https://usercontent.carom.io/3f9c1a7e5b2d4086a1c7e9f0b3d5a8c2.jpg"
}
}