Skip to main content
An Attachment is a file Relay stores for a message. Uploading takes four calls. You allocate an Attachment by describing the file, and Relay hands you a signed upload URL. You put the raw bytes there, then send the Attachment ID in a media part. The Attachment belongs to the agent that allocated it, and only that agent can send it. Keep the Attachment ID; the signed URLs are temporary credentials. For a file already hosted publicly, Import media from a URL skips the upload. The upload URL lives 15 minutes. A download URL lives 60 minutes from the moment Relay issues it, and you can ask for a fresh one by ID at any time. Attachment types and limits has the size and metadata rules; the ceiling is 100 MiB.

Allocate the Attachment

Call POST /v1/attachments (reference) with the file’s name, type, and exact size; the SDK method is relay.attachments.create. Relay returns 200 with the allocation, and attachment_id is the value to keep.

Upload the bytes

PUT the raw bytes to upload_url as the whole body, with the required headers unchanged. With curl that is --data-binary @report.pdf, and the SDK helper relay.attachments.upload applies the headers for you. A successful upload returns 204. Base64 and multipart encoding change the body and fail the length check. The signed URL is the credential here; do not send your Agent Token to the upload host. If the result is uncertain, read the Attachment before you retry. Retry the complete bytes on the same URL only while the Attachment is pending and the URL has not expired; after expiry, allocate again.

Verify the upload

Call GET /v1/attachments/{attachmentId} (reference); the SDK method is relay.attachments.retrieve. Send only when status is complete.

Send the Attachment

Send a media part with the ID through either send path:
Relay returns 202 with the message. The media part in the response carries the Attachment ID and a signed download URL. Reuse the same idempotency key and body after an uncertain send.

When it fails

Next steps