# Files

Source: https://phonebox.dev/docs/api-reference/files

> List, upload, download and delete files in a phone's shared storage, and the rules for their paths.



Files live in the phone's shared storage under `/sdcard` and stay there while the phone is parked. Every file request needs a `ready` phone. [Files](/docs/using-phones/files) covers the same requests from the CLI and the SDK.

## Paths [#paths]

Each request names its file or directory in the `path` query parameter:

* A path is `/sdcard`, or a path inside it. `/storage/emulated/0` is another name for the same place and works the same way.
* It has at most 1024 characters, and it can't contain `.` or `..` segments.
* URL-encode it when it has spaces or other special characters.

A path that breaks these rules fails with `400 validation_failed`, whose `details.issues` names `path`.

## List files [#list-files]

`GET /v1/phones/{id}/files` needs the `phones:read` scope.

Lists one directory.

| Parameter | Type   | Default   | Rules                  |
| --------- | ------ | --------- | ---------------------- |
| `path`    | string | `/sdcard` | The directory to list. |

```bash
curl "https://phonebox.dev/v1/phones/ph_7kx2m6q4v3ta/files?path=/sdcard/Download" \
  -H "Authorization: Bearer $PHONEBOX_API_KEY"
```

```json title="Response: files"
{
  "path": "/sdcard/Download",
  "data": [
    { "name": "report.pdf", "type": "file", "size": 482133, "modified_at": "2026-09-29T10:09:14.000Z" },
    { "name": "receipts", "type": "directory", "size": 4096, "modified_at": "2026-09-29T10:04:52.000Z" }
  ]
}
```

| Field                | Type              | Meaning                                                |
| -------------------- | ----------------- | ------------------------------------------------------ |
| `path`               | string            | The directory listed.                                  |
| `data[].name`        | string            | The entry's name.                                      |
| `data[].type`        | string            | `file`, `directory` or `other`.                        |
| `data[].size`        | number            | Its size in bytes.                                     |
| `data[].modified_at` | timestamp or null | When it last changed, or `null` when that isn't known. |

| Error                   | When                                                                                                   |
| ----------------------- | ------------------------------------------------------------------------------------------------------ |
| `400 validation_failed` | The path breaks the rules, or it names a file. For a file, `next` gives the request that downloads it. |
| `404 file_not_found`    | No directory exists at the path. `details.path` repeats it.                                            |

The readiness and phone-service errors in [Common errors](/docs/api-reference#common-errors) apply too.

## Upload a file [#upload-a-file]

`PUT /v1/phones/{id}/files` needs the `phones:control` scope.

Writes the request body, as raw bytes, to the file that `path` names. The body can be at most 4 MB, which is 4,000,000 bytes.

| Parameter | Type   | Default | Rules                                                       |
| --------- | ------ | ------- | ----------------------------------------------------------- |
| `path`    | string | None    | The file's full path, ending with its name. It is required. |

```bash
curl -X PUT "https://phonebox.dev/v1/phones/ph_7kx2m6q4v3ta/files?path=/sdcard/Download/report.pdf" \
  -H "Authorization: Bearer $PHONEBOX_API_KEY" \
  -H "Content-Type: application/octet-stream" \
  --data-binary @report.pdf
```

Directories on the way that don't exist yet are created. It answers `201 Created`:

```json title="Response: uploaded file"
{
  "path": "/sdcard/Download/report.pdf",
  "size": 482133
}
```

| Error                        | When                                                                                             |
| ---------------------------- | ------------------------------------------------------------------------------------------------ |
| `400 validation_failed`      | The path breaks the rules, or it doesn't end with a file name.                                   |
| `413 payload_too_large`      | The body is larger than 4 MB.                                                                    |
| `502 action_outcome_unknown` | The phone service didn't confirm the upload. List the directory to see whether the file arrived. |

The readiness and phone-service errors in [Common errors](/docs/api-reference#common-errors) apply too.

## Download a file [#download-a-file]

`GET /v1/phones/{id}/files/content` needs the `phones:read` scope.

Returns the file's bytes as `application/octet-stream`, with its name in the `Content-Disposition` header.

| Parameter | Type   | Default | Rules                                 |
| --------- | ------ | ------- | ------------------------------------- |
| `path`    | string | None    | The file to download. It is required. |

```bash
curl -o report.pdf "https://phonebox.dev/v1/phones/ph_7kx2m6q4v3ta/files/content?path=/sdcard/Download/report.pdf" \
  -H "Authorization: Bearer $PHONEBOX_API_KEY"
```

A file can be downloaded when it is at most 4 MB. When its size isn't known in advance, a download that passes 4 MB is cut off, so check that you received the whole file.

| Error                   | When                                                                                                         |
| ----------------------- | ------------------------------------------------------------------------------------------------------------ |
| `400 validation_failed` | The path breaks the rules, or it names a directory. For a directory, `next` gives the request that lists it. |
| `404 file_not_found`    | No file exists at the path. `details.path` repeats it.                                                       |
| `413 payload_too_large` | The file is larger than 4 MB.                                                                                |

The readiness and phone-service errors in [Common errors](/docs/api-reference#common-errors) apply too.

## Delete a file [#delete-a-file]

`DELETE /v1/phones/{id}/files` needs the `phones:control` scope.

Deletes a file. Directories return `400 validation_failed` without deleting any contents. Delete folders in the Files app on the phone instead; the console’s Files tab has an **Open Files** button.

| Parameter | Type   | Default | Rules                                                                                                         |
| --------- | ------ | ------- | ------------------------------------------------------------------------------------------------------------- |
| `path`    | string | None    | The file to delete. It is required; directories and the storage root cannot be deleted through this endpoint. |

```bash
curl -X DELETE "https://phonebox.dev/v1/phones/ph_7kx2m6q4v3ta/files?path=/sdcard/Download/report.pdf" \
  -H "Authorization: Bearer $PHONEBOX_API_KEY"
```

```json title="Response: delete file"
{
  "path": "/sdcard/Download/report.pdf",
  "deleted": true
}
```

| Error                        | When                                                                                                                                                                                     |
| ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400 validation_failed`      | The path breaks the rules, or it names a directory or the storage root. For directories, `next` explains how to use the phone’s Files app; no contents are deleted.                      |
| `404 file_not_found`         | Nothing exists at the path. `details.path` repeats it.                                                                                                                                   |
| `502 action_outcome_unknown` | The phone service didn't confirm the delete, and a follow-up read couldn't confirm that the path is absent. Follow `next` to list the parent directory before deciding whether to retry. |

After an unconfirmed deletion, Phonebox reads the parent directory once to check the result, without repeating the delete. If the path is confirmed absent, it returns `deleted: true`. A path already absent before the initial delete still returns `404 file_not_found`; a cleanup task can treat this as its desired state already reached.

The readiness and phone-service errors in [Common errors](/docs/api-reference#common-errors) apply too.
