# List connections

**GET** `/api/connections`

Returns every connection in the workspace, newest first. Never their secrets.

Needs [an API token](https://docs.gorunner.io/api/authentication#scopes) with the **Read** permission for connections (`connection:read`).

## Request

It takes no parameters.

## What a row holds

Who it signs in as (`account`), its `status`, its last error that still stands (`lastError`) and its last use (`lastUse`). No field ever holds the secret you saved, here or anywhere else.

`workspaceId` and `orgId` are all zeros, here and in Get a connection. `createdBy` names who made it, when known. A connection belongs to one workspace, and only that workspace’s workflows can use it.

## Status

- `active`: Saved normally, or the last test passed.
- `pending`: A sign-in connection that hasn’t signed in yet.
- `unverified`: The app has no test; it is checked on first use.
- `error`: The service refused the last test.
- `expired`: The service refused a renewal for good. Sign in again.

## Responses

- 200 OK

  The connections. None answers `[]`.

- 403 `FORBIDDEN`

  The token lacks the **Read** permission for connections.

- 500 `INTERNAL_ERROR`

  The list couldn’t be read. Try again.

Any call can also answer: [`401 UNAUTHORIZED`](https://docs.gorunner.io/errors#UNAUTHORIZED) · [`401 TOKEN_ENDED`](https://docs.gorunner.io/errors#TOKEN_ENDED) · [`403 TOKEN_SURFACE_OFF`](https://docs.gorunner.io/errors#TOKEN_SURFACE_OFF) · [`403 FEATURE_OFF`](https://docs.gorunner.io/errors#FEATURE_OFF) · [`403 EMBED_NOT_ALLOWED`](https://docs.gorunner.io/errors#EMBED_NOT_ALLOWED) · [`403 EMBED_NOT_AVAILABLE`](https://docs.gorunner.io/errors#EMBED_NOT_AVAILABLE) · [`403 ACCOUNT_SUSPENDED`](https://docs.gorunner.io/errors#ACCOUNT_SUSPENDED) · [`429 RATE_LIMITED`](https://docs.gorunner.io/errors#RATE_LIMITED) · [`503 BUSY`](https://docs.gorunner.io/errors#BUSY) · [`503 PAUSED`](https://docs.gorunner.io/errors#PAUSED) · [`503 SERVICE_UNAVAILABLE`](https://docs.gorunner.io/errors#SERVICE_UNAVAILABLE). See [Errors](https://docs.gorunner.io/api/errors#by-status).

Request

**curl**

```bash
GORUNNER="https://api.gorunner.io"
GORUNNER_TOKEN="grt_…"  # needs Read for connections

curl "$GORUNNER/api/connections" \
  -H "Authorization: Bearer $GORUNNER_TOKEN"
```

**JavaScript**

```js
const GORUNNER = "https://api.gorunner.io";
const TOKEN = process.env.GORUNNER_TOKEN;

const res = await fetch(`${GORUNNER}/api/connections`, {
  headers: { Authorization: `Bearer ${TOKEN}` },
});
const { data } = await res.json();
```

**Python**

```python
import os, requests

GORUNNER = "https://api.gorunner.io"
TOKEN = os.environ["GORUNNER_TOKEN"]

res = requests.get(
    f"{GORUNNER}/api/connections",
    headers={"Authorization": f"Bearer {TOKEN}"},
)
data = res.json()["data"]
```

Response · 200 OK, shortened

```json
{
  "data": [
    {
      "id": "0f8b2c7e-4a51-4d3e-9b2a-6c1d2e3f4a5b",
      "pieceId": "postgres",
      "name": "Warehouse database",
      "authType": "custom",
      "status": "active",
      "lastTestedAt": "2026-10-24T16:00:00Z",
      "account": "warehouse@db.bakery.example:5432/orders",
      "workspaceId": "00000000-0000-0000-0000-000000000000",
      "orgId": "00000000-0000-0000-0000-000000000000",
      "createdBy": "5d8e1f3a-0b6c-4e2d-9f7a-1c3b5e8d2a40",
      "createdAt": "2026-10-20T08:00:00Z",
      "updatedAt": "2026-10-24T16:00:00Z",
      "lastUse": {
        "kind": "run",
        "workflowName": "Order intake"
      }
    }
  ]
}
```

**Every field**

It takes no body.

### Response · 200 OK

- `data` · array of objects
  - `id` · UUID: The connection’s id. This is the value a workflow step or trigger carries as `connectionId` to use these credentials.
  - `pieceId` · string: The app these credentials belong to (e.g. `seatable`, `postgres`, `googlesheets`, or the generic `oauth2`). Fixed at creation and not changeable.
  - `name` · string: Human label. Not unique.
  - `authType` · string: Free-text label recording the auth shape. Defaults to `api_key` when not supplied at creation. Conventionally one of the app’s `auth.type` values, but NOT validated against the app — treat it as advisory.
  - `status` · string: The last known verdict on these credentials. `active` = created normally, or the last test passed. `pending` = an OAuth2 connection that has not completed the authorization flow (no access token yet). `unverified` = the last test proved nothing because the app has no connection test; credentials are checked on first real use. `error` = the last test was refused by the provider. `expired` = a refresh was refused for good — the provider rejected the stored grant or the client (revoked, aged out), or the OAuth app that issued the tokens was replaced or removed; signing in again (Re-authorize) mends it. The test endpoint (and `test: true` on create or update), the OAuth2 sign-in and a refused refresh set it; an update that sends `config` resets it to `active` (`pending` for a sign-in with no token); a rename leaves it. One of `active`, `pending`, `unverified`, `error`, `expired`.
  - `lastTestedAt` · time: When the connection was last tested. Absent if never tested.
  - `tokenExpiresAt` · time: OAuth2 access-token expiry, when known. Refresh happens automatically at run time; there is no manual refresh call.
  - `refreshable` · boolean: The stored config carries a refresh token, so `tokenExpiresAt` is when the access token is next RENEWED (on use), not when the connection ends. False for pasted access tokens and API keys. A connection whose refresh the provider refuses for good is marked `status: expired` on the next refresh attempt and needs signing in again.
  - `managedBy` · string: Present only on a connection the installation’s partner manages through the embed API. It is read-only here: update, delete and the OAuth2 sign-in answer 403 `MANAGED_CONNECTION`; test and replace stay open. One of `partner`.
  - `workspaceId` · UUID: Owning workspace. Populated on the create’s answer; the all-zero UUID on the list, the single read and an update’s answer, which read the row the way the list does and do not select it.
  - `orgId` · UUID: Owning organization. Same caveat as `workspaceId`: all-zero except in the create’s answer.
  - `createdBy` · UUID: The user who created it. Absent when no person did (the partner’s, a machine’s, rows from before creators were recorded).
  - `createdAt` · time
  - `updatedAt` · time
  - `account` · string: Who or what the credential is, never a secret: the Google address a test names, `user@host` (with port and database) from a typed credential’s non-secret fields, a SeaTable base’s name and server. Shown to every reader. Absent until known.
  - `createdByName` · string: The creator’s name (else their address), only while they are a member of the organization.
  - `createdByMember` · boolean: False once the creator is no longer a member of the organization. Absent with `createdBy`.
  - `lastError` · object: The last failure that still stands. Written by a failed test, a refused refresh (`expired`), and a run’s or poll’s definite refusal; a run’s 403 is kept as news (`cause: forbidden`) without changing `status`. Cleared by a working test, a sign-in, a config change, and the next run or poll that uses the connection and works.
    - `at` · time
    - `source` · string: One of `test`, `run`, `trigger`, `refresh`, `signin`.
    - `cause` · string: `refused` — the service refused the credential (401, SMTP 535, Postgres 28P01, MySQL 1045, …); `expired` — a refresh was refused for good; `server` — the server could not be reached; `forbidden` — a 403, news only; `other`. One of `refused`, `expired`, `server`, `forbidden`, `other`.
    - `message` · string: The service’s own words, masked of the step’s secrets, at most 1,000 characters.
    - `runId` · UUID
    - `workflowId` · UUID
    - `workflowName` · string: While the workflow exists.
  - `lastUse` · object: The newest use the audit trail records (its `connection.decrypt` rows). Absent when the trail has none.
    - `at` · time
    - `kind` · string: One of `run`, `trigger`, `test`, `editor`, `signin`.
    - `runId` · UUID
    - `workflowId` · UUID
    - `workflowName` · string
    - `byName` · string: The person, for a test, the builder or a sign-in, while a member of the organization.
  - `oauthClient` · string: For a connection that signs in: `managed` — the installation’s app; `byo` — its own client id; `pasted` — an access token with no refresh token, which cannot renew itself. One of `managed`, `byo`, `pasted`.
  - `lastSignInAt` · time: When a sign-in last stored tokens.
  - `expiresAt` · time: When the connection stops working with no way to renew: `tokenExpiresAt` of a connection that is not `refreshable`. Absent for a refreshable one and when unknown.
  - `test` · object: Only on the answer of a create or a change sent with `test: true`: the test that let it be saved.
    - `success` · boolean: Always `true` here: a refused test saves nothing and is a 422.
    - `message` · string: The app’s own words.
    - `unverified` · boolean: Present and true when the app cannot be tested without running a real step: saved, and nothing was proven.

Related: [Get a connection](https://docs.gorunner.io/api/connections/get-connection) · [See which workflows use each connection](https://docs.gorunner.io/api/connections/get-connection-usage) · [Connections](https://docs.gorunner.io/build/connections)

Source: https://docs.gorunner.io/api/connections/list-connections
