Supyagent
Connected Accounts

API Reference

Complete endpoint reference for the Connected Accounts API — authentication, request formats, response shapes, and error codes.

API Reference

Complete reference for all Connected Accounts API endpoints.

Authentication

All endpoints require an API key in the Authorization header:

Authorization: Bearer sk_live_your_key_here

Additionally, your account must have an active partner profile. Requests without a partner profile return a 403 with error code PARTNER_REQUIRED.

Response Format

All responses follow a consistent JSON envelope:

Success (200):

{
  "ok": true,
  "data": { ... }
}

Error (4xx/5xx):

{
  "ok": false,
  "error": "Human-readable error message",
  "error_code": "MACHINE_READABLE_CODE"
}

Common Error Codes

StatusError CodeMeaning
401Invalid or missing API key
403PARTNER_REQUIREDNo active partner profile
403Partner profile is suspended
429Rate limit exceeded

Endpoints

Connected Accounts

MethodEndpointDescription
POST/api/v1/accountsCreate a connected account
GET/api/v1/accountsList connected accounts
GET/api/v1/accounts/:idGet account details + integrations
PATCH/api/v1/accounts/:idUpdate account
DELETE/api/v1/accounts/:idDelete account (cascades)

OAuth Connect Sessions

MethodEndpointDescription
POST/api/v1/accounts/:id/connectInitiate OAuth flow
GET/api/v1/accounts/:id/connect/:sessionIdCheck session status

Integrations

MethodEndpointDescription
GET/api/v1/accounts/:id/integrationsList integrations
DELETE/api/v1/accounts/:id/integrations/:providerDisconnect provider

OAuth Callback (Internal)

MethodEndpointDescription
GET/api/v1/connect/callbackOAuth callback handler (called by providers, not by your app)

POST /api/v1/accounts

Create a connected account.

Request:

{
  "external_id": "string (required, 1-255 chars, unique per partner)",
  "display_name": "string (optional, max 255 chars)",
  "metadata": { "key": "value" }
}

Response (200):

{
  "ok": true,
  "data": {
    "id": "uuid",
    "external_id": "string",
    "display_name": "string | null",
    "metadata": {},
    "created_at": "ISO 8601"
  }
}

Errors: 400 (validation), 409 (duplicate external_id)


GET /api/v1/accounts

List connected accounts with pagination.

Query: ?limit=20&offset=0

Response (200):

{
  "ok": true,
  "data": {
    "accounts": [
      {
        "id": "uuid",
        "external_id": "string",
        "display_name": "string | null",
        "metadata": {},
        "created_at": "ISO 8601"
      }
    ],
    "total": 42,
    "limit": 20,
    "offset": 0
  }
}

GET /api/v1/accounts/:id

Get account details with its integrations.

Response (200):

{
  "ok": true,
  "data": {
    "id": "uuid",
    "external_id": "string",
    "display_name": "string | null",
    "metadata": {},
    "created_at": "ISO 8601",
    "integrations": [
      {
        "id": "uuid",
        "provider": "google",
        "status": "active",
        "connected_at": "ISO 8601"
      }
    ]
  }
}

Errors: 404 (not found)


PATCH /api/v1/accounts/:id

Update account. At least one field required.

Request:

{
  "display_name": "string (optional)",
  "metadata": { "key": "value" }
}

Response (200):

{
  "ok": true,
  "data": {
    "id": "uuid",
    "external_id": "string",
    "display_name": "string | null",
    "metadata": {},
    "created_at": "ISO 8601"
  }
}

Errors: 400 (no fields), 404 (not found)


DELETE /api/v1/accounts/:id

Delete account. Cascades to all integrations and tokens.

Response (200):

{
  "ok": true,
  "data": { "deleted": true }
}

Errors: 404 (not found)


POST /api/v1/accounts/:id/connect

Initiate an OAuth connect session.

Request:

{
  "provider": "google | slack | discord | github | microsoft | linkedin | twitter | notion | hubspot | jira | linear | calendly | salesforce | pipedrive",
  "redirect_url": "https://yourapp.com/callback (required)",
  "scopes": ["optional", "custom", "scopes"]
}

Response (200):

{
  "ok": true,
  "data": {
    "connect_url": "https://provider.com/auth?...",
    "session_id": "uuid",
    "expires_at": "ISO 8601 (30 min from now)"
  }
}

Errors: 400 (invalid provider/URL), 404 (account not found)


GET /api/v1/accounts/:id/connect/:sessionId

Check connect session status.

Response (200):

{
  "ok": true,
  "data": {
    "session_id": "uuid",
    "provider": "string",
    "status": "pending | completed | expired | failed",
    "error": "string (only if failed)",
    "created_at": "ISO 8601",
    "expires_at": "ISO 8601"
  }
}

Errors: 404 (account or session not found)


GET /api/v1/accounts/:id/integrations

List integrations for a connected account.

Response (200):

{
  "ok": true,
  "data": {
    "integrations": [
      {
        "id": "uuid",
        "provider": "string",
        "status": "active | pending | expired | revoked",
        "connected_at": "ISO 8601",
        "enabled_services": [
          { "service_name": "gmail.read", "is_enabled": true }
        ]
      }
    ]
  }
}

Errors: 404 (account not found)


DELETE /api/v1/accounts/:id/integrations/:provider

Disconnect a provider from a connected account.

Response (200):

{
  "ok": true,
  "data": { "deleted": true, "provider": "slack" }
}

Errors: 404 (account not found, or no integration for that provider)


GET /api/v1/connect/callback

Internal endpoint. Called by OAuth providers after user authorization. Do not call this directly.

Query Parameters (from provider):

  • code — Authorization code
  • state — CSRF token matching a connect session
  • error — Error code if user denied access

Behavior:

  1. Validates state against pending sessions
  2. Checks session is not expired or already used
  3. Exchanges code for tokens using PKCE verifier
  4. Encrypts and stores tokens
  5. Auto-enables services
  6. Redirects to the session's redirect_url with status parameters

Success redirect:

{redirect_url}?status=success&provider=google&account_id=user-123

Error redirect:

{redirect_url}?error=access_denied

Making API Calls on Behalf of Accounts

All provider API calls (e.g., /api/v1/google/*, /api/v1/slack/*) require the X-Account-Id header to specify which connected account's tokens to use.

GET /api/v1/google/gmail/messages HTTP/1.1
Host: app.supyagent.com
Authorization: Bearer sk_live_your_key_here
X-Account-Id: user-123
DetailValue
HeaderX-Account-Id
ValueThe account's external_id (your user identifier, not the Supyagent UUID)
RequiredYes, for all /api/v1/{provider}/* endpoints

The header is resolved by looking up the external_id against connected accounts belonging to your partner profile. If no match is found, the API returns:

{
  "ok": false,
  "error": "Connected account \"invalid-id\" not found"
}

See Making API Calls for the full pattern with multi-language examples.


Rate Limits

Rate limit headers are included in every response:

HeaderDescription
X-RateLimit-LimitMonthly API call quota for your tier
X-RateLimit-RemainingAPI calls remaining this month
X-RateLimit-Minute-LimitPer-minute request limit for your tier
X-RateLimit-Minute-RemainingRequests remaining in the current minute window
Retry-AfterSeconds to wait before retrying (only present when rate limited)

Tier Limits

TierMonthly CallsRequests/MinuteOverage
Free1,00030Hard block — no overage
Pro100,000300$0.50 per 1,000 calls
EnterpriseUnlimited1,000N/A

When rate limited, the API returns 429 Too Many Requests with a Retry-After header.

If your payment status is past due, all API requests are blocked regardless of tier until the payment method is updated at Settings > Billing.

See Usage & Billing for full tier details and monitoring.