POST /v1/uploads
Create an upload intent for a folder. Requires a future folder-scoped write credential. Returns an operation and a destination-specific transfer plan; it does not mean file bytes have been committed.
Request fields
| Location | Field | Type | Required | Description |
|---|---|---|---|---|
| Header | Authorization | string | Yes | Credential scoped to the authorized resource. |
| Header | Content-Type | string (media type) | Yes | application/json. |
| Header | Idempotency-Key | string | Yes | Stable retry identity for this upload intent. |
| Body | parent_id | string | Yes | Destination folder. |
| Body | name | string | Yes | New file name. |
| Body | size_bytes | integer (bytes) | Yes | Expected byte size. |
| Body | sha256 | string | Yes | Whole-file digest. |
| Body | replace_version_id | string | null | No | Expected current version when replacing. |
Request example
POST /v1/uploads
Authorization: Bearer <scoped token>
Idempotency-Key: invoice-8427
Content-Type: application/json
{
"parent_id": "folder_123",
"name": "invoice.pdf",
"size_bytes": 4194304,
"sha256": "<whole-file digest>",
"replace_version_id": null
}HTTP status codes
| Status | Meaning |
|---|---|
202 Accepted | Success response shown below. |
400 Bad Request | Invalid upload intent or file metadata. |
401 Unauthorized | Missing, expired, or invalid credential. |
403 Forbidden | Credential is valid but lacks the required scope or role. |
409 Conflict | Idempotency key reused with different input, or expected version changed. |
429 Too Many Requests | Rate limit reached; honor Retry-After when provided. |
503 Service Unavailable | Service temporarily unavailable; retry safely. |
Response fields
| Field | Type | Example |
|---|---|---|
operation_id | string | op_456 |
file_id | string | file_789 |
status | string | ready_to_transfer |
transfer | object | {…} |
transfer.method | string | direct |
transfer.capability | string | <short-lived, destination-scoped capability> |
Response example
202 Accepted
Content-Type: application/json
{
"operation_id": "op_456",
"file_id": "file_789",
"status": "ready_to_transfer",
"transfer": {
"method": "direct",
"capability": "<short-lived, destination-scoped capability>"
}
}How it works
An app declares the destination, size, content hash, and retry identity. Atom decides whether the bytes can go directly to the destination or need an explicitly permitted staging route.
The transfer plan would be short-lived and destination-scoped. A client would refresh an expired plan using the same operation ID; it must not create another file to resume. A future SDK could hide transport details.
A local-only folder returns waiting_for_device. The sender retains the bytes. Temporary cloud staging is a separate, owner-approved folder policy—not a silent fallback.
