# Connect another app to Orbit Zero

Source: https://orbitstore.dev/guides/ps4/orbit-zero-integrations/ · Updated 2026-11-15

Available in Orbit Zero 1.9.0 and later; it works with a PS4 from Orbit Zero 1.9.1 with Orbit Store for PS4 0.0.2. The supported integration API is separate from Zero's internal browser interface.

Keep Orbit Zero running on the same computer as the other app. In **Settings → Devices → Connected apps**, turn on **Allow other apps**. You can connect in either of these ways:

- **Create a token yourself:** select **Create API token**, enter the app's name, review its access and create the token. Copy it into the other app's API-token setting. Zero shows the token only once; if you lose it, disconnect that entry and create another.
- **Approve a request:** start the connection from the other app, select **Review request** in Zero, check its name and choose **Allow app**. The other app receives its token automatically.

Both methods grant the same access. Each app has its own token, remembered until you disconnect that app or turn app access off. It does not receive your PS4 pairing credentials or provider accounts. Creating a token manually avoids the connection-request step; the other app still needs to reach Zero's local API on the same computer.

Approved apps can search games and add-ons, read available editions/sources/formats, start downloads, pause or resume them, retry another source, send retained computer downloads to the PS4, read progress, and find the files kept on this computer. They can manage the same download list you see in Zero. Installation, arbitrary file actions, file deletion, account settings and PS4 pairing are outside this API.

Downloads appear in Zero's normal Downloads page. Computer-only downloads work without a PS4. PS4 destinations need the paired console online and use the usual space checks. Direct/TorBox choices follow Zero's settings, including **Always use TorBox**. If a provider needs human verification, its ordinary Zero window opens and the start request remains pending until that step completes or fails.

## Developer interface

Base URL: `http://127.0.0.1:34179/api/integrations/v1` (or Zero's configured port). Connect only over IPv4 loopback. Requests with another Host, a non-local peer, or an Origin header are rejected. There is no browser CORS interface. Existing UI cookies, the console's pairing token and `X-Orbit-Zero` are not authentication for this API.

Use `Content-Type: application/json` for POST requests. Do not attach an Origin header. Response errors are `{ "error": { "code": "STABLE_CODE", "message": "Explanation" } }`. Handle the code rather than matching the English message.

### Connect once per app

If your app accepts a manually supplied API token, the user can create one in Zero as described above. Use it directly as `Authorization: Bearer <token>` and skip `/connect`. Store it in the operating system's credential store.

For automatic token delivery with approval in Zero:

1. `POST /connect` with `{ "name": "Your app" }`. The response is HTTP 202 with `requestId`, `requestSecret`, `expiresAt` (Unix milliseconds) and `pollAfterSeconds`.
2. Ask the user to approve in Zero. Poll `POST /connect/status` with `{ "requestId": "…", "requestSecret": "…" }` no faster than the returned interval.
3. A `pending` result needs approval; `denied` means stop. An `approved` result includes `token` and `appId`. Connection requests expire after five minutes.
4. Store the token in your operating system's credential store. Send `Authorization: Bearer <token>` on all other API calls. Never log it, put it in a URL, or reuse Zero's own session cookies.

The app name is supplied by your app; it is not a verified publisher identity. Users should approve only requests they initiated. A 401 response means the token is missing, invalid or revoked. A 403 `API_DISABLED` response means app access is off. Turning app access off revokes existing grants; turning it on again requires new approval.

### Catalogue and destinations

| Request | Result |
| --- | --- |
| `GET /status` | API version, this app's identity, console connection and capabilities |
| `GET /catalogue?q=Example&platform=ps4&limit=50&offset=0` | Matching games and their options; `total`, `offset`, `limit`, `revision` |
| `GET /catalogue?kind=addons&platform=ps4` | Separate add-on results; base-game results remain separate |
| `GET /catalogue?platform=ps4&source=vikingfile` | Filter options by source and format; repeat each query parameter for multiple choices |
| `GET /games/{gameId}` | Game details and all its available options |
| `GET /destinations` | This computer and the paired PS4's available drives, including free space |

Use option `id` values as `releaseId`. Keep a user's exact platform, title ID, edition and format choice. Options contain display and file information, not provider sessions or temporary download URLs. Pagination is by game, not by option; the maximum limit is 100.

### Start a download

`POST /jobs`, with a unique `Idempotency-Key` header:

```json
{
  "releaseId": "an-option-id-from-the-catalogue",
  "destination": { "type": "computer" },
  "delivery": "direct",
  "route": "auto"
}
```

For a PS4 drive, use `"destination": { "type": "ps5", "id": "internal" }` with an ID returned by `/destinations`. The type stays `ps5` for a PS4; see [Using a PS4](https://orbitstore.dev/guides/ps4/orbit-zero-integrations/#using-a-ps4).

`delivery` is optional (`direct` or `torbox`). Omission uses the remembered method; Always use TorBox overrides it. `route` is optional: `auto` follows Zero's download preference, `computer` downloads on the computer and transfers when appropriate, and `ps5` requires a direct download on the console (the PS4). Explicit `ps5` does not silently fall back to the computer and does not support the computer's TorBox connection. These per-request choices do not change the global download preference.

The response is HTTP 202:

```json
{ "requestId": "…", "state": "preparing", "createdAt": 1790000000000 }
```

Poll `GET /requests/{requestId}`. `complete` includes `result.jobId` (for example `computer:…` or `ps5:…`); `failed` includes a structured error. Completion here means that the action was accepted/finished, not that the entire game has downloaded. Read the job to follow its progress. A provider window can keep the start request pending while the user completes verification.

Reuse the **same action key and body** after a lost HTTP response. Concurrent requests with the same key start only once. Reusing a key with another body returns 409 `IDEMPOTENCY_CONFLICT`. Recent completed requests are retained for up to seven days, subject to a 200-request history bound; pending requests are not evicted. Do not reuse old keys for new actions. If Zero restarts during an uncertain start, its request becomes `interrupted` and is not automatically resubmitted. Inspect `/jobs` before issuing a new action key.

### Progress, retry and transfer

| Request | Purpose |
| --- | --- |
| `GET /jobs` | Computer-managed and direct PS4 jobs, current state, byte counts, rates and errors |
| `GET /jobs/{jobId}` | One job with the same fields |
| `GET /cache` | Per-job availability, completion and saved computer path; read-only |
| `POST /jobs/{jobId}/actions` | Pause, resume, retry or send a computer copy |

All action POSTs need a unique `Idempotency-Key` and return a request to poll, just like starting a job. Examples:

```json
{ "action": "pause" }
```

```json
{ "action": "resume" }
```

```json
{ "action": "retry", "releaseId": "another-source-option-id" }
```

```json
{ "action": "send", "destination": { "type": "ps5", "id": "internal" } }
```

A retry without a replacement option resumes the saved job and its normal recovery checks. Your app chooses alternate sources. A replacement must match the original game, platform, title ID and format, and the old job must be paused or failed. Zero pauses the old job and starts a separate download, keeping its files. It never concatenates bytes from two source options or silently changes editions. Completed computer copies can be sent without downloading them again.

Poll about once a second while following active work, and less often while idle. A disconnected PS4 must not be treated as a completed download. If `/jobs` reports a console error, the local jobs remain usable; reconnect through Zero. Cache paths can disappear after the user moves files or clears copies in Zero, so recheck availability before using them. An active or partial path is not a completed game. This API does not expose cache deletion or cancellation that would delete partial files.

## Using a PS4

The API was first made for the PS5, so a few names still say `ps5`. With a PS4 paired they mean the PS4:

- `ps5Connected` in `GET /status` is `true` when the paired PS4 is connected.
- PS4 drives in `/destinations`, jobs and `send` actions have `"type": "ps5"`.
- `"route": "ps5"` asks the PS4 to download directly, and its job IDs start with `ps5:`.

**Ask for PS4 games.** `/catalogue` lists PS4 and PS5 games alike, whichever console is paired. Add `platform=ps4` to every catalogue request. Orbit Zero's own lists show only PS4 games with a PS4 paired, but the API doesn't stop an app from sending a PS5 game to a PS4 drive, and a PS5 game won't install on a PS4.

Installation is outside this API, so Stream & install, which isn't available for PS4 yet, doesn't affect it.

## Compatibility

Clients must ignore unknown fields and handle unknown job states conservatively. Breaking changes require another integration API version.

[Orbit Zero](https://orbitstore.dev/guides/ps4/orbit-zero/) · [Settings](https://orbitstore.dev/guides/ps4/settings/) · [Project home](https://github.com/saawant12/orbit-store-ps4/blob/main/README.md)
