---
title: "Read one stored app login and its audit trail (never a secret)."
method: GET
path: "/story-projects/{projectId}/app-connections/{connectionId}"
tags: ["Sources"]
---

# Read one stored app login and its audit trail (never a secret).

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

## Request

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

One connection's metadata, which secrets are saved and which it still needs, and its newest 20 audit rows (`events`: created, updated, secret_saved, secret_removed, test_login, decrypted_for_job, deleted; never a value). 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 connection and its newest audit rows.

- AppConnectionDetail
  - `connection` 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
  - `events` AppConnectionEvent[], required: The newest audit rows, newest first. Never a secret.
    - `id` string, required
    - `action` 'created' | 'updated' | 'secret_saved' | 'secret_removed' | 'test_login' | 'decrypted_for_job' | 'recipe_saved' | 'deleted', required
    - `secretKind` '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.
    - `via` string, required: `app`, `api_key`, `sign_in_key`, `app_sign_in_key`, `oauth`, `worker` or `retention`.
    - `detail` string, nullable, required
    - `createdAt` string, date-time, required

## 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`: No app connection with that id in this project (`app_connection_not_found`), or the project is not yours (`project_not_found`).
- `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)
