Skip to content
Scalekit Docs
Talk to an EngineerDashboard

Manage connected accounts

Check status, list, delete, and update credentials for connected accounts across all connector auth types.

A connected account is the per-user record that holds a user’s credentials and tracks their authorization state for a specific connection. Scalekit creates one automatically when a user completes authentication.

StateMeaning
ACTIVECredentials valid, ready for tool calls
EXPIREDAccess token expired and needs refresh or re-authentication
PENDING_AUTHUser hasn’t completed authentication, or re-authentication is in progress
PENDING_VERIFICATIONOAuth complete; user identity verification still required before activation
DISCONNECTEDAccount was manually disconnected

See Troubleshoot connection errors for what to do in each state.

Use get_or_create_connected_account as the safe default when a user may be connecting for the first time. Use get_connected_account only when you know the account already exists and you need to inspect or return its stored auth details.

response = actions.get_or_create_connected_account(
connection_name="gmail",
identifier="user_123"
)
connected_account = response.connected_account
print(f"Status: {connected_account.status}")

When a connected account isn’t ACTIVE, generate a new authorization link and send it to the user.

The link opens a Hosted Page, a Scalekit-hosted UI that adapts automatically based on the connection’s auth type:

  • OAuth connectors: presents the provider’s OAuth consent screen
  • API key, basic auth, or other connectors: presents a form to collect the required credentials

Your code is the same regardless of connector type. Scalekit determines the right flow based on the connection configuration.

if connected_account.status != "ACTIVE":
link_response = actions.get_authorization_link(
connection_name="gmail",
identifier="user_123"
)
# Redirect or send link_response.link to the user

A connected account can leave the ACTIVE state on its own, with no action from you or the user. When that happens, the next tool call fails until the user re-authorizes. To catch it early, subscribe to the connected_account.status_updated webhook instead of waiting for a failed call.

OAuth connected accounts most often move to EXPIRED for reasons outside Scalekit’s control:

  • The provider revoked the refresh token. A password change, an admin-initiated token revocation, or a provider security policy invalidates the refresh token, so Scalekit can no longer obtain new access tokens.
  • The refresh token expired. Providers cap refresh-token lifetimes (for example, 30 or 180 days), and the expiry is rarely surfaced in advance.
  • No refresh token was issued. When the connection’s scopes don’t request offline access, the provider returns only a short-lived access token and no refresh token to renew it.
  • The provider hit a per-user token limit. Some providers keep only a fixed number of refresh tokens per user and app, and silently drop the oldest ones when a user reconnects repeatedly.

The first two cases require the user to re-authenticate; there is no server-side workaround. The last two are configuration issues you fix on the connection by requesting offline access scopes.

The connected_account.status_updated event fires on every status transition and carries both the new and previous status:

connected_account.status_updated
{
"spec_version": "1",
"id": "evt_101652975398683158",
"type": "connected_account.status_updated",
"occurred_at": "2025-12-02T06:31:34.895815554Z",
"environment_id": "env_88640229614813449",
"object": "ConnectedAccount",
"data": {
"id": "ca_133400349586228019",
"identifier": "john@acmecorp.com",
"connection_id": "conn_133400101014995480",
"connection_name": "gmail",
"provider": "GMAIL",
"authorization_type": "OAUTH",
"status": "EXPIRED",
"old_status": "ACTIVE"
}
}

Because the event covers every transition, filter on the change you care about. To alert users only when an active account needs re-authorization, act on old_status ACTIVE moving to status EXPIRED:

// The event fires for all transitions (for example, PENDING_AUTH to ACTIVE).
// Filter to the one that requires user action, or you will notify on noise.
if (event.data.old_status === 'ACTIVE' && event.data.status === 'EXPIRED') {
// Generate a fresh authorization link and notify the user
}

When you receive this event, generate a new authorization link and prompt the user to reconnect. See the full payload for the connected_account.status_updated event in the API reference.

const listResponse = await actions.listConnectedAccounts({
connectionName: 'gmail',
});
console.log('Connected accounts:', listResponse);

Deleting a connected account removes the user’s credentials and authorization state. The user must re-authenticate to reconnect.

await actions.deleteConnectedAccount({
connectionName: 'gmail',
identifier: 'user_123',
});

Scopes apply to OAuth connectors only. For non-OAuth connectors (API key, basic auth, and similar), generate a new authorization link and the hosted page will collect updated credentials.

To request additional OAuth scopes from an existing connected account:

  1. Update the connection’s scopes in AgentKit > Connections > Edit.
  2. Generate a new authorization link for the user.
  3. The user completes the OAuth consent screen, approving the updated scopes.
  4. Scalekit updates the connected account with the new token set.