GET …/content
API v1 · stablestatus
Docs / Sending
GET
/v1/messages/{id}/content
Decrypts and returns the retained body — subject, html, text, variables. Viewing content is a distinct, audit-logged act, never a side effect of listing messages.
Authentication
Requires messages:read-content. That ability is mutually exclusive with messages:send — the panel will not mint a key that has both, and resolution rejects one that does. A messages:read key without messages:read-content also gets 403.
Worked example
captured LOCAL with messages:read-content
{
"subject": "Reset password",
"html": "<p>Reset <a href=\"https://basalt.app/reset/tk_9f2a81\">link</a> (30m)</p>",
"text": "Reset https://basalt.app/reset/tk_9f2a81 (30m)",
"variables": {
"reset_url": "https://basalt.app/reset/tk_9f2a81",
"expires_minutes": 30
},
"expires_at": null
}Responses & failures
410body past retention
response body
{
"message": "Content expired",
"completed_at": null
}Ciphertext present but undecryptable returns 503 with type: body_unreadable — never an empty successful body.
Audit
Every successful content read writes an audit event message.content_viewed with the API key id. That is why this endpoint is separate from list and show.