# Create an encrypted area

Encrypts a piece of text or an uploaded file end-to-end and returns the new area's id. Use it
to share a credential, an API key, a private note, or a sensitive file: choose who it is for,
set the optional controls, and Aitronos either delivers it for you or hands you a **secure
link** to forward yourself.

> **Aitronos never holds a key that can read the area.** For a secure link, the decryption key
travels in the link's URL fragment (the part after `#`), which browsers never send to a
server — so the key never reaches Aitronos. Storage holds ciphertext only.


Requires authentication (bearer token or API key). The authenticated caller is the sender, so
there is no separate approval step. Creates are limited to 30 per minute per user; beyond that
the endpoint answers `429` with a `retry_after` in seconds.

**Encrypted areas are part of Conversations.** Where Conversations is enabled for your account,
encrypted areas are enabled with it and this endpoint works; where Conversations is switched
off, the endpoint answers `403`. There is nothing extra to turn on.

### Three rules to read before you call this

- **The secure link is returned exactly once and can never be re-issued.** The key inside it is
never stored, so nobody — including Aitronos — can produce the link again. If your client
loses the response body, the area is unrecoverable and you must create a new one. Capture
`secure_link` the moment you receive it.
- **`secure_link` is returned only when `audience` is `link`.** Every other audience is
delivered for you, so the response deliberately withholds the key-bearing URL.
- **This endpoint is not idempotent.** Repeating the same request creates a second, independent
area with its own key — there is no de-duplication. Retry only when you know the first call
did not return a `201`.


### Controls and their defaults

| Control | Default | Notes |
|  --- | --- | --- |
| `audience` | *(no default — required)* | Selects the security model. |
| `password` | none | Optional. Share it with the recipient yourself, over a different channel. |
| `burn_after_read` | off | Optional. The area self-destructs after the first successful open. |
| `expiry` | `1w` | **The area expires after 7 days unless you choose otherwise.** Pick `never` explicitly if it should never expire. |


`burn_after_read` and `expiry` apply to **every** audience — they are enforced by the server on
both the secure-link and the identity-sealed path.

`password` applies only to the secure-link audiences. It feeds the key derivation, and an
identity-sealed area has nowhere to carry it, so a password sent with an area that gets sealed
to another Aitronos user's identity is **dropped**: the response reports
`password_required: false` and names it in `controls_not_applied`. Read that list rather than
inferring the drop from `crypto_mode`.

## Body parameters

**`audience`** string required

Who the area is for. One of `user`, `email`, `whatsapp`, `imessage`, `slack`, `teams`, `link`.
`user` seals the area to another Aitronos user's identity in your organization — the strongest
option, because a forwarded copy stays sealed to them. `email` and the four messaging values
send a secure link over that channel. `link` creates a shareable secure link with no named
recipient and returns it to you.

Exactly one recipient field must be supplied, and it must be the one that matches the audience.
Supplying a field the audience does not accept, more than one, or none at all is a `422`.

| `audience` | Supply exactly one of |
|  --- | --- |
| `user` | `recipient_user_id` |
| `email` | `recipient_email` or `recipient_contact_id` |
| `whatsapp` | `recipient_handle`, `recipient_contact_id`, or the legacy `recipient_whatsapp` |
| `imessage`, `slack`, `teams` | `recipient_handle` or `recipient_contact_id` |
| `link` | *(none — a recipient field is rejected)* |


**`recipient_user_id`** string optional

Required when `audience` is `user`: the Aitronos user id of the recipient, who must be in the
same organization. Must be omitted for every other audience. Max 255 characters.

**`recipient_email`** string optional

Required when `audience` is `email`, unless you supply `recipient_contact_id` instead: the
recipient's email address. Must be omitted for every other audience. Max 320 characters.

**`recipient_handle`** string optional

Required for the messaging audiences, unless you supply `recipient_contact_id` instead: the
recipient's address on that channel — a phone number in E.164 form (for example
`+41791234567`) for `whatsapp` and `imessage`, a member id for `slack`, a directory object id
for `teams`. Must be omitted for the `user`, `email` and `link` audiences. Max 320 characters.

**`recipient_contact_id`** string optional

An existing contact to send to, instead of a raw address. Accepted for the four messaging
audiences, and for `email` when the send should go over that contact's email channel. Provide
either this or the audience's address field, never both. Must be omitted for `user` and `link`.
Max 255 characters.

**`recipient_whatsapp`** string optional

Legacy alias of `recipient_handle`, accepted only when `audience` is `whatsapp`. Provide exactly
one of the two, never both. Prefer `recipient_handle` for new integrations. Max 320 characters.

**`content_text`** string optional

The secret to encrypt, as inline text. Provide `content_text`, `file_ref`, or **both** —
supplying neither is a `422`. Sent together, the note is sealed alongside the file and the
recipient reads it without opening the attachment.
Preserved byte for byte, including leading and trailing whitespace, because whitespace can be
meaningful in a secret. Never stored in readable form and never written to a log. Max
1,048,576 characters — use `file_ref` for anything larger.

**`file_ref`** string optional

The id of an already-uploaded file to encrypt, which must belong to you. Provide
`content_text`, `file_ref`, or both. Use this rather than `content_text` for anything larger
than a short secret. Max 255 characters.

**Any file type is accepted**, including an archive of several files — upload it through
[the encrypted-area upload endpoint](/api-reference/encrypted-areas/upload) first. That
endpoint takes arbitrary bytes, because a file sealed here is encrypted rather than read; the
general file upload restricts types because it parses and indexes what you send it.

**Two size limits apply, and the lower one depends on the audience.** A file sealed to another
Aitronos user's identity may be up to the full encrypted-area limit (100 MB). A file sent as a
**secure link** — every audience except an enrolled `user` recipient — may be up to **32 MB**,
because that format carries the file inside the sealed payload. A file between the two is
refused with `413` and `reason: attachment_too_large_external` rather than sealed into a link
nobody could open.

**`title`** string optional

A display label shown to the recipient alongside the sealed card. **Not secret** — it is
rendered into the card and, for the `user` audience, stored as part of the delivered message.
Never put any part of the secret here. Defaults to `Encrypted area`. Max 120 characters.

**`password`** string optional

A password the recipient must enter to open the area. It is folded into the key derivation on
the recipient's device, is never sent to Aitronos when they open the area, and is never echoed
back, delivered, or logged — share it with the recipient yourself, over a different channel.
Off by default. Preserved byte for byte. Max 1024 characters.

**`burn_after_read`** boolean optional

When `true`, the area self-destructs after the first successful open. Defaults to `false`. Must
be a real boolean — a string such as `"true"` is rejected with a `422`, because silently
enabling a destructive option would be worse than an error.

**`expiry`** string optional

How long the area stays openable. One of `1h`, `1d`, `1w`, `30d`, `never`. **Defaults to `1w` —
the area expires after 7 days unless you choose otherwise.** Choose `never` explicitly if it
should not expire.

Unknown fields are rejected with a `422` rather than ignored, so a misspelled control can never
be silently dropped.

## Returns

`201 Created`. The response is marked `Cache-Control: no-store`.

> **Retry on `503`, never on `500`.** The two storage failures are reported differently on
purpose, and only one is worth retrying. A **503** is transient: it carries a `Retry-After`
header (and a `retry_after` field, in seconds), and the same request will likely succeed
shortly. A **500** is a configuration fault on our side that a retry can never clear — surface
it and stop rather than looping. In both cases **nothing was created**: an area exists only
once you have received a `201` with an `encbin_id`.


**`encbin_id`** string · The new area's id (`encbin_`-prefixed). Use it with the fetch endpoints.
**`audience`** string · The audience the area was actually sealed for.
**`crypto_mode`** string · `recipient_bound` when sealed to a recipient's identity, or `external`
when opened by a key carried in the link.
**`format_version`** string · The sealing format the area was written in.
**`fell_back_to_link`** boolean · `true` when a `user` audience could not be sealed to that
user's identity (they have no key enrolled) and was sealed as a recipient-addressed secure link
instead.
**`secure_link`** string · The complete secure link, **including the decryption key in its URL
fragment**. Present only for `audience: "link"`, returned only once, and never re-issuable.
`null` for every other audience. Treat it as the secret it is.
**`sealed_card_token`** string · The chat token that renders the sealed card for this area. It
carries the area id, audience and title only — never a key and never the content.
**`recipient_ref`** string · A non-secret echo of who the area was addressed to (a user id, an
email address, or a channel handle). `null` for `audience: "link"`.
**`password_required`** boolean · Whether a password is needed to open the area, **as resolved**
— an identity-sealed area ignores a requested password and reports `false`.
**`burn_after_read`** boolean · Whether the area self-destructs on first open, **as resolved**.
**`expires_at`** string · When the area stops being openable (ISO-8601, UTC), **as resolved**, or
`null` when it does not expire. This endpoint emits the numeric-offset form
(`2026-08-01T09:00:00.103591+00:00`); the fetch endpoints emit the same instant in the
`Z` form. Parse it with a real ISO-8601 parser rather than matching on a `Z` suffix.
**`controls_not_applied`** array of strings · The controls you **asked for** that this area does
not carry. Empty when nothing was dropped. Today the only member is `"password"`, and it appears
only when a password was sent and the area was sealed to a recipient's identity. It is keyed off
what you requested, so an identity-sealed area created without a password returns `[]` rather
than advertising a loss you never asked for. Show this to the sender instead of comparing
`password_required` against your request — a control this list does not name **was** applied.
**`delivery`** object · How the area is being delivered. Six fields, below.
**`security_disclosure`** object · Machine-readable security facts to show the sender. Seven
fields, below.

### `delivery`

**`status`** string · What this request did about delivery: `returned_in_response` (the `link`
audience — the link is in this response and there is no send), `queued` (the delivery was
recorded and fires once the area is durably stored), or `not_queued` (the delivery could not be
recorded — the area exists but nothing will be sent). It describes the request, not the eventual
send outcome.
**`delivered`** boolean · Always `false`. Delivery happens after this response is returned, so no
send outcome can honestly be reported here.
**`detail`** string · A short human-readable note about the delivery. Never a secret.
**`audience`** string · The audience the area was sealed for.
**`channel`** string · The transport the area is delivered over — `internal`, `email`,
`whatsapp`, `imessage`, `slack`, or `teams` — or `null` for `audience: "link"`, which has no
send.
**`channel_delivery_available`** boolean · Whether this build can deliver to the chosen channel.
It is **currently `true` for every supported channel**; a `false` would mean the area was created
and sealed but will not be delivered. This describes **the channel's support in this build, not
your environment's configuration** — it will not go `false` because a mail server is down or a
messaging account is disconnected. Those surface as a failed delivery afterwards, not here. The
field exists so a channel that is not yet supported can be identified without a change to this
response shape.

### `security_disclosure`

Facts only — your interface owns the wording.

**`level`** string · `identity_sealed` when the area is sealed to a specific recipient's identity
(only they can open it, even if it is forwarded), or `link_key` when it is opened by a key
carried in the link.
**`key_travels_in_link`** boolean · Whether the decryption key rides in the link's URL fragment.
The fragment never reaches Aitronos — but anywhere the link is pasted, the key goes with it.
**`anyone_with_link_can_open`** boolean · Whether possession of the link alone is enough to open
the area (`true` for a key-in-link area with no password).
**`password_required`** boolean · Whether a password must be entered to open the area.
**`burn_after_read`** boolean · Whether the area self-destructs after the first open.
**`expires_at`** string · When the area stops being openable (ISO-8601, UTC), or `null`. Same numeric-offset form as the top-level `expires_at` above.
**`fell_back_to_link`** boolean · `true` when a `user` audience was sealed as a secure link
because the recipient has no key enrolled — worth surfacing, because the security level is then
`link_key` rather than `identity_sealed`.

Example

```bash cURL
curl -X POST "https://api.aitronos.com/v1/encrypted-areas" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "audience": "link",
    "content_text": "staging-db-password: hunter2",
    "title": "Staging database password",
    "burn_after_read": true,
    "expiry": "1d"
  }'
```


```python Python SDK
# pip install aitronos-sdk
#
# The Python SDK does not expose a typed `encrypted_areas` namespace yet, so call
# the endpoint directly with the same credential you would pass to `Aitronos(...)`
# — an API key or a bearer token, both sent as `Authorization: Bearer <value>`.
import httpx

API_KEY = "your-api-key"

area = httpx.post(
    "https://api.aitronos.com/v1/encrypted-areas",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "audience": "link",
        "content_text": "staging-db-password: hunter2",
        "title": "Staging database password",
        "burn_after_read": True,
        "expiry": "1d",
    },
).json()

# Capture this now — the link is returned once and can never be re-issued.
print(area["secure_link"])
print(area["security_disclosure"]["anyone_with_link_can_open"])
```


```python Python
import requests

resp = requests.post(
    "https://api.aitronos.com/v1/encrypted-areas",
    headers={"Authorization": f"Bearer {ACCESS_TOKEN}"},
    json={
        "audience": "email",
        "recipient_email": "colleague@example.com",
        "content_text": "staging-db-password: hunter2",
        "title": "Staging database password",
        "password": "shared-out-of-band",
    },
)
area = resp.json()
# `secure_link` is null here — the email audience is delivered for you.
print(area["encbin_id"], area["delivery"]["status"], area["delivery"]["channel"])
```


```javascript JavaScript
const resp = await fetch('https://api.aitronos.com/v1/encrypted-areas', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${accessToken}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    audience: 'user',
    recipient_user_id: 'usr_4f2a1c9e7b8d40a3915c2e6f8a0b1d7c',
    content_text: 'staging-db-password: hunter2',
    title: 'Staging database password',
  }),
});
const area = await resp.json();
// Sealed to that user's identity: no link, and the controls resolve to off.
console.log(area.security_disclosure.level, area.fell_back_to_link);
```

**Response:**


```json 201 Created
{
  "encbin_id": "encbin_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6",
  "audience": "link",
  "crypto_mode": "external",
  "format_version": "v2",
  "fell_back_to_link": false,
  "secure_link": "https://chat.aitronos.com/encrypted-area/encbin_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6#3xK9uQr7...",
  "sealed_card_token": "{{encrypted_area | id::encbin_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6 | audience::link | title::Staging database password}}",
  "recipient_ref": null,
  "password_required": false,
  "burn_after_read": true,
  "expires_at": "2026-08-01T09:00:00.103591+00:00",
  "delivery": {
    "status": "returned_in_response",
    "delivered": false,
    "detail": "The secure link is in this response; forward it yourself.",
    "audience": "link",
    "channel": null,
    "channel_delivery_available": true
  },
  "security_disclosure": {
    "level": "link_key",
    "key_travels_in_link": true,
    "anyone_with_link_can_open": true,
    "password_required": false,
    "burn_after_read": true,
    "expires_at": "2026-08-01T09:00:00.103591+00:00",
    "fell_back_to_link": false
  }
}
```

> For a delivered audience the shape is the same, with `secure_link` `null`,
`recipient_ref` set, and `delivery.status` `queued` with the matching `channel`.


Errors

```json 422 Invalid request
{ "success": false, "error": { "code": "VALIDATION_ERROR", "message": "Provide content_text, file_ref, or both.", "system_message": "Request validation failed", "type": "validation_error", "status": 422, "details": { "fields": [ { "field": "", "message": "Provide content_text, file_ref, or both.", "type": "value_error" } ] }, "trace_id": "...", "timestamp": "..." } }
```


```json 413 File too large for a secure link
{ "success": false, "error": { "code": "PAYLOAD_TOO_LARGE", "message": "This file is too large to send as a secure link (48 MB; the limit is 32 MB). Send it to a colleague in your organization instead, or send a smaller file.", "system_message": "This file is too large to send as a secure link (48 MB; the limit is 32 MB). Send it to a colleague in your organization instead, or send a smaller file.", "type": "validation_error", "status": 413, "details": { "reason": "attachment_too_large_external", "size": 50331648, "cap": 33554432 }, "trace_id": "...", "timestamp": "..." } }
```


```json 403 Not enabled
{ "success": false, "error": { "code": "FEATURE_DISABLED", "message": "This feature is not currently enabled for your organization.", "system_message": "Encrypted areas are not enabled for this account", "type": "authorization_error", "status": 403, "details": { "feature": "encrypted_area" }, "trace_id": "...", "timestamp": "..." } }
```


```json 429 Too many creates
{ "success": false, "error": { "code": "RATE_LIMIT_EXCEEDED", "message": "Too many requests. Please wait a moment and try again.", "system_message": "Rate limit exceeded", "type": "rate_limit_error", "status": 429, "details": { "limit": 30, "window_seconds": 60, "retry_after": 42 }, "retry_after": 42, "trace_id": "...", "timestamp": "..." } }
```


```json 503 Storage temporarily unavailable
{ "success": false, "error": { "code": "SERVICE_TEMPORARILY_UNAVAILABLE", "message": "Secure storage is temporarily unavailable. Please try again in a moment.", "system_message": "Encrypted-area storage is unavailable.", "type": "service_unavailable", "status": 503, "details": { "reason": "storage_backend_unavailable", "retry_after": 2 }, "retry_after": 2, "trace_id": "...", "timestamp": "..." } }
```


```json 500 Storage unavailable
{ "success": false, "error": { "code": "STORAGE_ERROR", "message": "Encrypted areas cannot be created right now because secure storage is not available. Retrying will not help — this needs an administrator.", "system_message": "Encrypted-area storage is unavailable.", "type": "server_error", "status": 500, "details": { "reason": "storage_backend_error" }, "trace_id": "...", "timestamp": "..." } }
```

## Related resources

- [Fetch a recipient-bound encrypted area](/docs/api-reference/encrypted-areas/fetch-recipient-bound) — and its open counterpart.
- [Fetch a secure-link encrypted area](/docs/api-reference/encrypted-areas/fetch-secure-link) — and its open counterpart.
- [Encrypted areas overview](/docs/api-reference/encrypted-areas/introduction)