---
title: "List the project's stored app logins (never a secret)."
method: GET
path: "/story-projects/{projectId}/app-connections"
tags: ["Sources"]
---

# List the project's stored app logins (never a secret).

`GET /story-projects/{projectId}/app-connections`

## Request

- Base URL: `https://docs.sleeperhit.studio/api/v1`
- URL: `https://docs.sleeperhit.studio/api/v1/story-projects/{projectId}/app-connections`
- Auth: HTTP bearer

The project's app connections, newest first: origin, extra origins, sign-in page and method, header kind, what proves it is signed in, what it blurs, the username masked, status, when it was last tested and used, which secrets are saved and which it still needs; and `connectUrl`, the project page's form for connecting another. Each secret is sealed the moment it is saved: the website and the Story API can save or replace one but never read it back, MCP and Slug never take one, and no read returns one (only which kinds are saved). Only the machines that record a capture can open it, to sign in to your app; a saved session's cookies for your app (never a password) may also go to Cloudflare's hosted browser, which only reads a light app's screens to learn its features. Reads only.

## Response `200`

The project's app connections.

- AppConnectionList
  - `projectId` string, required
  - `connections` AppConnection[], required
    - `id` string, required
    - `projectId` string, required
    - `label` string, nullable, required
    - `origin` string, required: The app's https origin: the only site a secret is typed into or a header sent to (with `extraOrigins`).
    - `extraOrigins` string[], required
    - `loginUrl` string, nullable, required
    - `loginMethod` 'form' | 'storageState' | 'provider' | 'none', required
    - `providerEndpoint` string, nullable, required: `provider` only: the app's sleeper.capture/1 API. The saved grant is sent there, in the Authorization header, and nowhere else.
    - `loggedInWhen` object[], nullable, required: Capture preconditions that hold once signed in.
    - `headerKind` 'none' | 'cloudflareAccess' | 'vercelBypass', required
    - `maskSelectors` string[], required
    - `usernameHint` string, nullable, required: The username masked when it was saved ("de•••@example.com").
    - `status` 'untested' | 'verified' | 'failed', required
    - `lastVerifiedAt` string, date-time, nullable, required
    - `lastUsedAt` string, date-time, nullable, required
    - `lastTestRequestedAt` string, date-time, nullable, required
    - `lastTest` AppConnectionTest, required: One test sign-in check, including checks that could not reach the app. `failed` means the check ended without a successful sign-in; it does not by itself mean the app rejected the login. `not_ready` means setup is incomplete; `unavailable`, `runner`, `runner_busy` and `recipe_unavailable` mean the check is unavailable. `credentials_refused` reports that the app refused the username and password. `needs_field` and `sso_only` stop before anything is typed: the sign-in asks for something the saved login does not have; `recipe_failed` means a sign-in step stopped even after one repair. Never a secret.
      - `id` string, required
      - `status` 'running' | 'passed' | 'failed', required: `running`, `passed` or `failed`. A test still running long after it was asked for reads as failed (`runner`).
      - `requestedAt` string, date-time, required
      - `finishedAt` string, date-time, nullable, required
      - `reason` 'not_https' | 'off_origin' | 'captcha' | 'form_not_found' | 'credentials_refused' | 'mfa_required' | 'totp_refused' | 'not_signed_in' | 'redeem_refused' | 'password_in_session' | 'timeout' | 'browser' | 'provider_refused' | 'unreachable' | 'not_ready' | 'unavailable' | 'runner' | 'runner_busy' | 'needs_field' | 'sso_only' | 'recipe_unavailable' | 'recipe_failed', nullable, required: Why it failed: given for an app whose origin is verified as yours, and for reasons on Sleeper's side (`not_ready`, `unavailable`, `runner`, `runner_busy`); null otherwise (a test is not a way to check logins for apps that are not yours). A running test can wait up to five minutes for a requested one-time code, entered only in that test on Connected apps. Story API, CLI, MCP and Slug never accept that code. `mfa_required` means that attempt ended without completing its second sign-in step. For an interactive retry, enter a requested code only in the running sign-in's temporary field. For unattended sign-in, save an authenticator setup key if the app accepts its codes, or use a saved session or capture grant. Sleeper cannot read email or texts, follow sign-in links, approve push requests, or use a passkey.
      - `message` string, nullable, required: What happened, in plain words.
      - `landedUrl` string, nullable, required: Where the browser was when it finished (no query or fragment); only for an app whose origin is verified as yours.
      - `hasScreenshot` boolean, required: Whether a picture of what the browser saw was kept. Only the owner's own reads link to it.
    - `retentionDays` integer, nullable, required
    - `secrets` object[], required: Which secrets are saved, and when. Never a value.
      - `kind` 'username' | 'password' | 'totpSeed' | 'workspace' | 'cfAccessClientId' | 'cfAccessClientSecret' | 'vercelBypass' | 'storageState' | 'providerGrant', required: One sealed secret of a stored app login. Reads name the kinds saved, never a value.
      - `savedAt` string, date-time, required
    - `missingSecrets` AppConnectionSecretKind[], required: The secrets its sign-in method and header still need, and a `workspace` when its sign-in steps ask for one.
    - `signInRecipe` AppConnectionSignInRecipe, required: THE SIGN-IN STEPS of a form sign-in (BL-2623): found by reading the signed-out app (no login is ever shown to what reads it), checked against the saved secrets before anything is typed, followed by every test, recording and walk, repaired once when a step no longer matches, and kept versioned. A secret is typed only into a field inside the form a step names. The sign-in page a person set wins (`loginUrlPinned`).
      - `version` integer, required
      - `source` 'scout' | 'repair', required
      - `foundAt` string, date-time, required
      - `lastPassedAt` string, date-time, nullable, required
      - `loginUrl` string, required: The sign-in page a run opens.
      - `loginUrlPinned` boolean, required: The person set the sign-in page.
      - `steps` object[], required
        - `fields` object[], required
          - `role` 'email' | 'username' | 'password' | 'workspace' | 'totp' | 'other', required
          - `label` string, required
      - `sso` object, required
        - `providers` string[], required
        - `only` boolean, required
      - `notes` string[], required
      - `summary` string, required: One sentence: "Signs in at /login · Email, then Password".
    - `createdAt` string, date-time, required
    - `updatedAt` string, date-time, required
  - `total` integer, required
  - `projectKind` 'story' | 'product', required: The project's kind. App connections are for `product` projects: a `story` project's list still reads and its rows can still be deleted, but creating, changing, saving a login and a test sign-in are refused with 409 `project_not_product`.
  - `connectUrl` string, uri, required: The authorized public project route for Connected apps. A named secure-login action adds connectApp=1 and the exact saved connectionId; the general workspace link does not automatically open a login. On a story project it is the project's Overview, which has no Connected apps tab.

## Other responses

- `401`: Missing, malformed, revoked, or expired API key.
- `403`: API key is valid but lacks the scope, is blocked by IP allowlist, or the account is disabled.
- `404`: The named project or source does not exist or is owned by another account.
- `429`: Rate limit for this API key + IP + route family was exceeded.
- `500`: The API failed unexpectedly. Safe to retry with the same Idempotency-Key.

---

[API](https://skmtc.dev/sleeperhit/apis/sleeper-hit-studio-story-api.md) · [All operations](https://skmtc.dev/sleeperhit/apis/sleeper-hit-studio-story-api/llms.txt) · [OpenAPI document](https://skmtc.dev/sleeperhit/apis/sleeper-hit-studio-story-api/revisions/4534f5d25540?raw)
