Attachments API Reference
Attachments API Reference
Attachments allow tenants to upload files to engagements. Uploaded files are stored in Supabase Storage and automatically processed to generate a manifest and context index that the engine uses during crew execution.
Base URL: /api/engagements/:id/attachments
Authentication: All endpoints require authentication (cookie session or Bearer API key).
List Attachments
GET /api/engagements/:id/attachmentsReturns all attachments for the specified engagement.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Engagement ID |
Response
{
"attachments": [
{
"id": "clxyz100att",
"filename": "brand-guidelines.pdf",
"mimeType": "application/pdf",
"sizeBytes": 2451890,
"category": "brand_assets",
"summary": "Official brand guidelines including color palette and typography",
"uploadedBy": "clxyz200usr",
"createdAt": "2025-06-01T09:15:00.000Z"
},
{
"id": "clxyz101att",
"filename": "competitor-data.csv",
"mimeType": "text/csv",
"sizeBytes": 34521,
"category": "data",
"summary": null,
"uploadedBy": "clxyz200usr",
"createdAt": "2025-06-01T09:20:00.000Z"
}
]
}Example
curl -X GET https://app.groundtruth.ai/api/engagements/clxyz500eng/attachments \
-H "Authorization: Bearer gt_live_abc123..."Upload Attachment
POST /api/engagements/:id/attachmentsUploads a file to the engagement. Requires write access (member+ role or read_write API key scope).
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Engagement ID |
Request
Content-Type: multipart/form-data
| Field | Type | Required | Description |
|---|---|---|---|
file | file | Yes | The file to upload |
category | string | No | One of: reference, styleguide, design_inspiration, data, brand_assets |
summary | string | No | Human-readable description of the file contents |
Allowed File Types
| Category | Extensions |
|---|---|
| Modern Office | .pdf, .docx, .xlsx, .pptx |
| Legacy Office | .doc, .xls, .ppt |
| Open formats | .odt, .ods, .odp, .rtf |
| Text / data | .csv, .txt, .md, .json, .yaml, .yml |
| Web | .html, .htm |
| Images | .png, .jpg, .jpeg, .svg |
| Archives | .zip |
MIME types are automatically normalized from file extension. This fixes browsers that misreport Office XML formats (.docx, .xlsx, .pptx) as application/octet-stream or application/zip.
Plan Limits
| Plan | Max File Size | Max Total Storage |
|---|---|---|
| Starter | 10 MB | 100 MB |
| Professional | 50 MB | 500 MB |
| Enterprise | 100 MB | 2 GB |
Response
Status: 201 Created
{
"attachment": {
"id": "clxyz102att",
"filename": "market-research.pdf",
"mimeType": "application/pdf",
"sizeBytes": 1048576,
"category": "reference",
"summary": "Q3 2025 market research report",
"uploadedBy": "clxyz200usr",
"createdAt": "2025-06-01T10:00:00.000Z"
}
}Side Effects
- Regenerates the attachment manifest for the engagement
- Regenerates the context index used by the engine during crew execution
- Dispatches
attachment.uploadedwebhook event
Example
curl -X POST https://app.groundtruth.ai/api/engagements/clxyz500eng/attachments \
-H "Authorization: Bearer gt_live_abc123..." \
-F "file=@/path/to/market-research.pdf" \
-F "category=reference" \
-F "summary=Q3 2025 market research report"Errors
| Status | Description |
|---|---|
| 400 | No file provided, unsupported file type, or file exceeds size limit |
| 403 | Write access required |
| 404 | Engagement not found |
| 413 | Total storage limit exceeded for current plan |
Get Attachment
GET /api/engagements/:id/attachments/:attachmentIdReturns attachment metadata along with a signed download URL.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Engagement ID |
attachmentId | string | Attachment ID |
Response
{
"attachment": {
"id": "clxyz100att",
"filename": "brand-guidelines.pdf",
"mimeType": "application/pdf",
"sizeBytes": 2451890,
"category": "brand_assets",
"summary": "Official brand guidelines including color palette and typography",
"uploadedBy": "clxyz200usr",
"createdAt": "2025-06-01T09:15:00.000Z"
},
"downloadUrl": "https://xyz.supabase.co/storage/v1/object/sign/attachments/..."
}The downloadUrl is a signed URL valid for 1 hour from the time of the request. After expiry, request a new URL by calling this endpoint again.
Example
curl -X GET https://app.groundtruth.ai/api/engagements/clxyz500eng/attachments/clxyz100att \
-H "Authorization: Bearer gt_live_abc123..."Errors
| Status | Description |
|---|---|
| 404 | Attachment or engagement not found |
Delete Attachment
DELETE /api/engagements/:id/attachments/:attachmentIdDeletes an attachment from the engagement. Requires write access. Removes the file from Supabase Storage and regenerates the manifest.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Engagement ID |
attachmentId | string | Attachment ID |
Response
{
"success": true
}Side Effects
- Removes the file from Supabase Storage
- Regenerates the attachment manifest for the engagement
Example
curl -X DELETE https://app.groundtruth.ai/api/engagements/clxyz500eng/attachments/clxyz100att \
-H "Authorization: Bearer gt_live_abc123..."Errors
| Status | Description |
|---|---|
| 403 | Write access required |
| 404 | Attachment or engagement not found |
Add URL as Attachment
POST /api/engagements/:id/attachments/from-urlFetches a URL, extracts its text content, and stores it as a markdown attachment. The engine can then use this content as context during crew execution. Requires write access.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Engagement ID |
Request
Content-Type: application/json
| Field | Type | Required | Description |
|---|---|---|---|
url | string | Yes | The URL to fetch (must be HTTP or HTTPS) |
category | string | No | One of: reference, styleguide, design_inspiration, data, brand_assets |
Response
Status: 201 Created
{
"attachment": {
"id": "clxyz103att",
"filename": "example.com_blog_post.md",
"mimeType": "text/markdown",
"sizeBytes": 15234,
"category": "reference",
"summary": "Fetched from example.com: Blog Post Title",
"sourceUrl": "https://example.com/blog/post",
"uploadedBy": "clxyz200usr",
"createdAt": "2025-06-01T10:30:00.000Z"
}
}Behavior
- Fetches the URL with a 15-second timeout
- HTML content is converted to plain text (scripts/styles stripped)
- Content is stored as a
.mdfile with source metadata header - Duplicate filenames are auto-suffixed (
_1,_2, etc.) - Internal/private IPs are blocked (localhost, 10.x, 192.168.x, 172.16-31.x)
- Maximum fetched content size: 5MB (text truncated to 500KB)
- Plan-based storage limits apply (same as file uploads)
Side Effects
- Regenerates the attachment manifest for the engagement
- Regenerates the context index used by the engine during crew execution
- Dispatches
attachment.uploadedwebhook event (includessourceUrlfield)
Example
curl -X POST https://app.groundtruth.ai/api/engagements/clxyz500eng/attachments/from-url \
-H "Authorization: Bearer gt_live_abc123..." \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/market-report", "category": "reference"}'Errors
| Status | Description |
|---|---|
| 400 | Missing URL, invalid URL format, unsupported scheme, or private IP |
| 403 | Write access required |
| 404 | Engagement not found |
| 413 | Fetched content exceeds plan storage limits |
| 422 | URL could not be fetched or returned no extractable content |