Skip to main content
curl "https://api.chroniclehq.com/api/v1/uploads/create-target" \
  -X POST \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "file_name": "research-notes.pdf",
    "content_type": "application/pdf",
    "declared_file_size": 524288
  }'
{
  "url": "https://chronicle-attachments.s3.us-east-1.amazonaws.com/",
  "fields": [
    { "name": "Content-Type", "value": "application/pdf" },
    {
      "name": "key",
      "value": "file-attachments/ws_123/abc-research-notes.pdf"
    },
    { "name": "Policy", "value": "..." },
    { "name": "X-Amz-Signature", "value": "..." }
  ],
  "path": "file-attachments/ws_123/abc-research-notes.pdf",
  "download_url": "https://chronicle-attachments.s3.us-east-1.amazonaws.com/file-attachments/ws_123/abc-research-notes.pdf?X-Amz-..."
}
curl "https://api.chroniclehq.com/api/v1/uploads/create-target" \
  -X POST \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "file_name": "research-notes.pdf",
    "content_type": "application/pdf",
    "declared_file_size": 524288
  }'

Parameters

file_name
string
required
The file’s original name, including extension. Used for display and to derive the file type downstream.
content_type
string
required
The MIME type of the file (for example application/pdf). Must be in the allowed list — see the FAQ below.
declared_file_size
number
required
The size of the file in bytes. Capped at 50 MB; the cap is also enforced by S3 on the upload itself.

Response

{
  "url": "https://chronicle-attachments.s3.us-east-1.amazonaws.com/",
  "fields": [
    { "name": "Content-Type", "value": "application/pdf" },
    {
      "name": "key",
      "value": "file-attachments/ws_123/abc-research-notes.pdf"
    },
    { "name": "Policy", "value": "..." },
    { "name": "X-Amz-Signature", "value": "..." }
  ],
  "path": "file-attachments/ws_123/abc-research-notes.pdf",
  "download_url": "https://chronicle-attachments.s3.us-east-1.amazonaws.com/file-attachments/ws_123/abc-research-notes.pdf?X-Amz-..."
}
url
string
The S3 endpoint to POST the file to.
fields
object[]
Form fields that must be included in the multipart upload, in order, before the file field. Each entry has name and value.
path
string
The S3 object key the file will be stored under.
download_url
string
A signed GET URL valid for 7 days. Pass this as the url on each attachment object when calling POST /presentations/generate or POST /presentations/generate/:generationId/message.

Uploading the file

After this endpoint returns, post the file directly to S3 using the returned url and fields. The file field must come last in the form.
curl "$URL" \
  -F "Content-Type=application/pdf" \
  -F "key=file-attachments/ws_123/abc-research-notes.pdf" \
  -F "Policy=..." \
  -F "X-Amz-Signature=..." \
  -F "file=@research-notes.pdf"
A successful upload returns 204 No Content. Do not send an Authorization header on this request — S3 will reject it. Once uploaded, reference the file in a generation by passing the captured download_url:
Attachment object
{
  "id": "att_123",
  "url": "<download_url from create-target>",
  "file_name": "research-notes.pdf",
  "type": "application/pdf"
}

FAQs

The presigned POST sends the file bytes straight to S3, so large attachments don’t traverse the Chronicle API. The Chronicle endpoint stays lightweight (just metadata) and the upload itself can stream through S3’s regional ingress.
.txt, .md, .pdf, .pptx, and images (.jpg, .jpeg, .png, .gif, .webp).Sending content_type outside this list returns FILE_UPLOAD_ERROR.
50 MB per file. Larger files are rejected with FILE_UPLOAD_ERROR. The cap is enforced both at this endpoint (against declared_file_size) and at S3 (against the actual upload).
7 days. As long as you reference it in a generation within that window, it’ll work. After expiry you’ll need to upload the file again.
The workspace tied to your API key. Attachments are scoped to that workspace and aren’t visible to other workspaces.