> ## Documentation Index
> Fetch the complete documentation index at: https://veryfront.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# External files

> Read and change files in a user's own OneDrive, SharePoint, or Google Drive through a project.

External files are the files and folders in a user's own OneDrive, SharePoint, or Google Drive. Veryfront reaches them through a project with that user's personal provider connection. They are separate from project files and uploads, which Veryfront stores itself.

The [REST](https://veryfront.com/docs/cloud/rest/apis/integrations.md), [GraphQL](https://veryfront.com/docs/cloud/graphql/apis/integrations.md), and [MCP](https://veryfront.com/docs/cloud/mcp/apis/integrations.md) references list every field. This page covers the rules that apply across them. GraphQL uses camelCase names, such as `folderId`, `pageInfo`, and `contentEncoding`.

## Access

Every call needs two grants:

* **Project access**: Your Veryfront credential must allow the operation in the project.
  * **Read**: Needs `project.integrations.read`.
  * **Create, update, move, create folder, and delete**: Need `project.integrations.connect`. An API key also needs the delete scope to delete.
  * **Import**: Needs `project.uploads.write` and upload edit access to the destination.
* **Personal connection**: You must connect your own provider account. A connection that another project member made doesn't apply to your calls.

GraphQL and the MCP `get_external_file` tool accept user credentials only. REST and the other MCP tools also accept agent, run, and service-account credentials when the acting user has a personal connection.

## Providers and IDs

The `provider` value is `onedrive`, `sharepoint`, or `drive` (Google Drive). REST routes start with `/projects/{project_reference}/external-files/{provider}`.

Item and folder IDs are opaque. Use the `id` that a listing returns:

* **OneDrive and Google Drive**: The provider item ID, or `root` for the drive root.
* **SharePoint**: The root lists the sites you can reach. A site has the ID `sp-site:{siteId}`, and items inside it use `{siteId}|{itemId}`.

Each item has a `kind` of `file` or `folder`.

## List and search

List returns one folder as a page with `data` and `page_info`. Pass `folder_id` to open a folder, or omit it for the provider root. Pass `page_info.next` as `cursor` to get the next page.

A cursor works only with the provider, folder, and query that returned it.

| Surface | `limit` range | Default |
| - | - | - |
| REST | 1 to 100 | 20 |
| GraphQL and MCP | 1 to 200 | The provider's page size |

Add `query` to search. With `folder_id`, OneDrive and SharePoint search the folder and its subfolders. Google Drive searches only the items directly inside the folder.

Without `folder_id`, OneDrive and Google Drive search the whole drive. SharePoint needs a site or folder ID to search.

## Read content

A read returns the whole file or an error, never partial content. `content_encoding` is `utf8` for a text MIME type with no charset or a UTF-8 or ASCII charset, and `base64` for every other file, including text in another charset such as UTF-16. Decode the content by the returned `content_encoding`.

Content over 100,000 characters returns `limit_exceeded` with reason `content_too_large`. Files over 50 MiB return `limit_exceeded` with reason `file_too_large`. Import large files into the project instead.

## Create and update

Create adds a new file and never replaces one. OneDrive and SharePoint return `conflict` when the folder already holds a file with that name. Google Drive allows duplicate names.

Update replaces a file's content. Send the file's `etag` as `If-Match` on REST, `ifMatch` on GraphQL, or `if_match` on MCP. The write returns `conflict` when the file changed since you read it.

OneDrive and SharePoint check the `etag` in the write itself. Google Drive checks it in a separate read before the write, so the write can still overwrite a change made in between.

Set `content_encoding` to `utf8` or `base64`. It defaults to `utf8`, except on GraphQL `updateExternalFile`, which defaults to `base64`.

Create, create folder, and import accept an idempotency key. A retry with the same key and input within 24 hours returns the first result instead of a second item.

Move changes an item's folder, its name, or both. SharePoint items move only within their site.

## Import into the project

Import copies one external file into project Uploads. The upload then follows the [Projects API](https://veryfront.com/docs/cloud/apis/projects.md) rules for uploads. Import doesn't index the file for knowledge retrieval.

| Surface | Destination without a folder | Timestamp prefix default |
| - | - | - |
| REST and GraphQL | The Uploads root | `false` |
| MCP `import_external_file` | `external-imports` | `true` without a folder |

Set `folder_path` (GraphQL `folderPath`) to choose a folder inside Uploads. The upload inherits the folder's visibility unless you set `visibility`. Veryfront exports Google Docs and Slides as PDF, and Sheets as XLSX.

A full storage quota returns `limit_exceeded` with reason `storage_quota_exceeded`. An existing upload at the destination returns `conflict`.

## Delete

Delete removes one file or folder, including the folder's contents. The result `status` says what the provider did:

* **`trashed`**: OneDrive and SharePoint moved the item to the recycle bin.
* **`deleted`**: Google Drive deleted the item permanently. It skips the Drive trash, so you can't restore it.

A Google Drive folder delete also permanently deletes the items in it that you own. It leaves items that other users own.

## MCP confirmation

`update_external_file` and `delete_external_file` require `confirm: true`. `confirm: false` refuses the call without changes.

## Errors

All names in the [operation table](#operation-names) return the same stable codes. REST returns them as a Problem with `code` and, where a code has more than one cause, `reason`.

MCP returns the same members under the same names in the error condition. GraphQL returns them in `extensions.code` and `extensions.reason`.

| Code | Meaning | What to do |
| - | - | - |
| `not_ready` | Reason `provider_connection_required`: your connection is missing or expired. REST uses HTTP 428. | Connect or reconnect at the connect URL, then retry. |
| `limit_exceeded` | Reason `provider_rate_limited`, or a delay in `retry_after_seconds` on REST and MCP or `extensions.retryAfterSeconds` on GraphQL: the provider rate-limited the call, or another import is busy. REST uses HTTP 429. | Wait for that delay when it is present (REST also sends `Retry-After`). Without it, back off exponentially. Then retry. |
| `limit_exceeded` | Any other case, such as `file_too_large`, `storage_quota_exceeded`, or a plan limit. | Don't retry. Change the request. |
| `conflict` | A name clash, a stale `etag`, or an idempotency key conflict. | For a name clash, pick another name or destination. For a stale `etag`, read the item again. For a key conflict, see [Idempotency conflicts](#idempotency-conflicts). |
| `not_found` | The item or project doesn't exist or you can't access it. | Check the ID, your role, and your API key scopes. |
| `forbidden` | The provider refuses the action on the item, or an import lacks upload edit access to the destination or the upload admin access that `visibility` needs. MCP and the other GraphQL fields also use it when your role or API key scope doesn't allow the operation. | Don't retry. Get the access, or choose another item or destination. |
| `forbidden` | Reason `personal_connection_required`: GraphQL or the MCP `get_external_file` tool got agent, run, or service-account credentials. | Call with user credentials. |
| `invalid_input` | The request is invalid, including a cursor from another listing. | Fix the request. |
| `unauthenticated` | The request has no valid credentials. REST uses HTTP 401. | Sign in or send a valid API key. |
| `internal` | Reason `provider_unavailable`: the provider didn't answer. REST uses HTTP 503. | Back off, then retry. |
| `internal` | No reason: the server failed. REST uses HTTP 500. | Don't retry automatically. Report the error if it persists. |

The connect URL is `connect_url` on REST and MCP, and `extensions.connection.connectUrl` on GraphQL.

REST, GraphQL `externalFileContent`, and GraphQL `createExternalFile` return `not_found`, not `forbidden`, when your project role or API key scope doesn't allow the operation.

### Idempotency conflicts

A `conflict` for an idempotency key carries `idempotency.state`:

* **`in_progress`**: The first request is still running. Retry with the same key and input after the delay in `idempotency.retry_after_seconds` on REST, or `idempotency.retryAfterSeconds` on GraphQL and MCP.
* **`payload_mismatch`**: Another request used the key with different input. Use a new key for the new input.
* **`outcome_unknown`**: Veryfront can't tell whether the first request changed anything. Check the destination before you retry, using `idempotency.recovery` when it is present. A new key can create a second item.

## Operation names

| Operation | REST | GraphQL | MCP |
| - | - | - | - |
| List or search | `GET .../external-files/{provider}` | `externalFiles` | `list_external_files` |
| Get metadata | `GET .../external-files/{provider}/{file_id}` | `externalFile` | `get_external_file` |
| Read content | `GET .../external-files/{provider}/{file_id}/content` | `externalFileContent` | `read_external_file_content` |
| Create file | `POST .../external-files/{provider}` | `createExternalFile` | `create_external_file` |
| Update file | `PUT .../external-files/{provider}/{file_id}` | `updateExternalFile` | `update_external_file` |
| Move or rename | `POST .../external-files/{provider}/{file_id}/move` | `moveExternalFile` | `move_external_file` |
| Delete | `DELETE .../external-files/{provider}/{file_id}` | `deleteExternalFile` | `delete_external_file` |
| Create folder | `POST .../external-files/{provider}/folders` | `createExternalFolder` | `create_external_folder` |
| Import | `POST .../external-files/{provider}/{file_id}/import` | `importExternalFile` | `import_external_file` |

### Deprecated names

These names still work but keep their old errors. Move to the names above:

* **REST `/providers/{provider}/...` routes**: Use the `/projects/{project_reference}/external-files/{provider}` routes.
* **`search_external_files` and `searchExternalFiles`**: Use list with `query`.
* **`read_external_file` and `readExternalFile`**: Use read content. The old names cut content at the size limit.
* **`write_external_file` and `uploadExternalFile`**: Use create or update. The old names can overwrite an existing OneDrive or SharePoint file.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.