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_hereAdditionally, 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
| Status | Error Code | Meaning |
|---|---|---|
| 401 | — | Invalid or missing API key |
| 403 | PARTNER_REQUIRED | No active partner profile |
| 403 | — | Partner profile is suspended |
| 429 | — | Rate limit exceeded |
Endpoints
Connected Accounts
| Method | Endpoint | Description |
|---|---|---|
POST | /api/v1/accounts | Create a connected account |
GET | /api/v1/accounts | List connected accounts |
GET | /api/v1/accounts/:id | Get account details + integrations |
PATCH | /api/v1/accounts/:id | Update account |
DELETE | /api/v1/accounts/:id | Delete account (cascades) |
OAuth Connect Sessions
| Method | Endpoint | Description |
|---|---|---|
POST | /api/v1/accounts/:id/connect | Initiate OAuth flow |
GET | /api/v1/accounts/:id/connect/:sessionId | Check session status |
Integrations
| Method | Endpoint | Description |
|---|---|---|
GET | /api/v1/accounts/:id/integrations | List integrations |
DELETE | /api/v1/accounts/:id/integrations/:provider | Disconnect provider |
OAuth Callback (Internal)
| Method | Endpoint | Description |
|---|---|---|
GET | /api/v1/connect/callback | OAuth 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 codestate— CSRF token matching a connect sessionerror— Error code if user denied access
Behavior:
- Validates
stateagainst pending sessions - Checks session is not expired or already used
- Exchanges code for tokens using PKCE verifier
- Encrypts and stores tokens
- Auto-enables services
- Redirects to the session's
redirect_urlwith status parameters
Success redirect:
{redirect_url}?status=success&provider=google&account_id=user-123Error redirect:
{redirect_url}?error=access_deniedMaking 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| Detail | Value |
|---|---|
| Header | X-Account-Id |
| Value | The account's external_id (your user identifier, not the Supyagent UUID) |
| Required | Yes, 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:
| Header | Description |
|---|---|
X-RateLimit-Limit | Monthly API call quota for your tier |
X-RateLimit-Remaining | API calls remaining this month |
X-RateLimit-Minute-Limit | Per-minute request limit for your tier |
X-RateLimit-Minute-Remaining | Requests remaining in the current minute window |
Retry-After | Seconds to wait before retrying (only present when rate limited) |
Tier Limits
| Tier | Monthly Calls | Requests/Minute | Overage |
|---|---|---|---|
| Free | 1,000 | 30 | Hard block — no overage |
| Pro | 100,000 | 300 | $0.50 per 1,000 calls |
| Enterprise | Unlimited | 1,000 | N/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.