API referenceAttachments

Mint a signed download URL for an attachment

Returns JSON with a short-lived downloadUrl for the file, a branded shareUrl (a human-viewable Dairo share page, or null until the file passes its malware scan), the attachment metadata (filename, contentType, sizeBytes, disposition, messageId, createdAt), and expiresInSeconds.

Endpoint
GET https://api.dairo.app/v1/attachments/{attachmentId}/url

Returns JSON with a short-lived downloadUrl for the file, a branded shareUrl (a human-viewable Dairo share page, or null until the file passes its malware scan), the attachment metadata (filename, contentType, sizeBytes, disposition, messageId, createdAt), and expiresInSeconds. Reach for this when you want to redirect a browser to the file or pass a link to another service rather than proxying bytes through your own API. expiryHours sets the requested validity window as an integer from 1 to 168 (up to 7 days) and defaults to 5 minutes when omitted; a non-integer or out-of-range value returns 400. Once the file has passed its malware scan, both links are branded Dairo links; before that, downloadUrl is a direct link for you alone, valid for at most one hour whatever expiryHours asks (expiresInSeconds reports the lifetime granted), and there is no shareUrl. A file the scan flagged is withheld with a 403, and an id your key can't reach returns 404.

Scope: messages:read. Send the API key as a bearer token; Scopes lists what each one reaches.

Request

cURL
curl "https://api.dairo.app/v1/attachments/3fa85f64-5717-4562-b3fc-2c963f66afa6/url" \
  -H "Authorization: Bearer $DAIRO_API_KEY"

Path parameters

NameTypeRequiredDescription
attachmentIdstring (uuid)yesThe attachment's ID.

Query parameters

NameTypeRequiredDescription
expiryHoursintegernoSigned URL expiry in hours. Defaults to about 5 minutes when omitted. Maximum is 168 hours / one week. An attachment whose malware scan has not passed gets an owner-only URL capped at one hour; expiresInSeconds reports the lifetime granted. (minimum 1, maximum 168)

Response

200 Success. Body: application/json, AttachmentDownloadUrlResponse.

FieldTypeRequiredDescription
attachmentMessageAttachmentyes
downloadUrlstring (uri)yes
expiresInSecondsintegeryes(minimum 1, maximum 604800)
shareUrlstring (uri)yesHuman branded Dairo share page URL for the attachment.
200
{
  "attachment": {
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "filename": null,
    "contentType": null,
    "sizeBytes": null,
    "contentId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "createdAt": "2026-10-19T09:30:00Z",
    "messageId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "disposition": "attachment"
  },
  "downloadUrl": "https://example.com",
  "expiresInSeconds": 1,
  "shareUrl": "https://example.com"
}

Errors

Every error has the same body, {"error": {"type", "code", "message", "param"}}; branch on code. Errors lists every code.

StatusMeaning
400The request is malformed or a value is invalid (invalid_request, invalid_domain, idempotency_key_mismatch).
401The API key is missing or invalid.
403The key lacks the scope this endpoint needs (scope_missing) or may not do this (not_permitted).
404No such resource in this account (resource_not_found).
422The request is well-formed but a field failed validation (validation_failed).
429Rate limit, plan limit, budget or spend cap reached (rate_limited, plan_limit_reached, budget_exceeded, spend_cap_reached).
500An unexpected error; retry with backoff, then contact support (internal_error).

On this page