> ISPO SDK documentation. [HTML](https://ispo.ai/docs/documents/Permissions_and_errors.html) · [Documentation index](https://ispo.ai/docs/llms.txt)

# <a id="request-access-then-use-it"></a>Request access, then use it

ISPO separates **what a project may request** from **what the user has granted**. Both must allow an operation. An SDK import, a descriptor edit, or a browser mock grants no authority.

For the file-publication example, include this request in the project's `.ispo/project.json` declaration:

```
{  "requests": {    "files": ["publish"]  }}
```

This is a fragment, not a replacement for the rest of the project descriptor. During admission or a host-reviewed access change, ISPO records the request envelope. The user then decides whether to allow the capability. Later source edits do not silently expand that envelope.

## <a id="handle-structured-errors"></a>Handle structured errors

SDK calls reject with `ProjectRpcError`. Branch on `code` and documented `details`; do not parse the human-readable message to infer authority.

```
import { files, ProjectRpcError } from '@ispo/sdk'export async function publishReport(content: string) {  try {    const receipt = await files.publish({ name: 'report.txt', content })    return { status: 'published', path: receipt.path } as const  } catch (error) {    if (error instanceof ProjectRpcError) {      switch (error.code) {        case 'outside-reviewed-eligibility':          return { status: 'needs-access-review' } as const        case 'capability-denied':        case 'files-denied':          return { status: 'needs-permission' } as const      }    }    throw error  }}
```

`outside-reviewed-eligibility` may require **Review changed access**. `capability-denied` and `files-denied` report refused access; let ISPO present the applicable review or grant flow. Permission states such as `not-requested`, `not-granted`, and `revoked` are not top-level `ProjectRpcError.code` values. Do not write grant stores, manufacture permission records, or retry until the user has allowed the operation.

If an operation reports an uncertain outcome, such as `ai-outcome-unknown`, do not blindly repeat it: an effect may already have started. Treat a picker returning `null` as cancellation, not failure. A grant-filtered empty entity result does not prove that the user's data store is empty.

## <a id="use-the-right-data-surface"></a>Use the right data surface

*   **Entities:** durable structured application state.
*   **Files:** artifacts the user can find and open.
*   **Blobs and Assets:** host-controlled renderable references and visual material.
*   **Secrets and Connectors:** credentials and connected accounts.

Use native ISPO connectors for services the host exposes. Never bypass their permission flow through another OAuth client, browser session, or direct provider API. If the required capability is unavailable, surface that state in your app.
