Making API Calls
Route provider API calls to connected accounts using the X-Account-Id header — the core pattern for calling Gmail, Slack, GitHub, and other providers on behalf of your users.
Making API Calls
Once a connected account has an active integration, you can make provider API calls on their behalf. Every provider call uses the same pattern: your API key for authentication, plus the X-Account-Id header to specify which connected account to act as.
The X-Account-Id Header
All provider API calls require the X-Account-Id header to identify 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 name | X-Account-Id |
| Value | The account's external_id (your internal user identifier) |
| Required | Yes, for all /api/v1/{provider}/* endpoints |
Use the account's external_id (e.g., user-123), not the Supyagent UUID. The external_id is the identifier you provided when creating the account.
How It Works
When Supyagent receives a provider API call:
- Validates your API key — checks the
Authorization: Bearerheader - Resolves the connected account — looks up the
X-Account-Idvalue against your partner's accounts - Checks permissions — verifies the account has the required integration and service enabled
- Retrieves tokens — decrypts the stored OAuth tokens for the specified provider
- Auto-refreshes if needed — if the access token is expired, uses the refresh token to get a new one
- Calls the provider API — forwards the request to the provider (Google, Slack, etc.)
- Returns the response — wraps the provider response in the standard Supyagent envelope
Provider Examples
Google Gmail
# List recent messages
curl https://app.supyagent.com/api/v1/google/gmail/messages \
-H "Authorization: Bearer sk_live_your_key_here" \
-H "X-Account-Id: user-123"
# Get a specific message
curl https://app.supyagent.com/api/v1/google/gmail/messages/18e4a2b3c4d5e6f7 \
-H "Authorization: Bearer sk_live_your_key_here" \
-H "X-Account-Id: user-123"
# Send an email
curl -X POST https://app.supyagent.com/api/v1/google/gmail/messages/send \
-H "Authorization: Bearer sk_live_your_key_here" \
-H "X-Account-Id: user-123" \
-H "Content-Type: application/json" \
-d '{
"to": "recipient@example.com",
"subject": "Hello",
"body": "Sent via the Connected Accounts API"
}'const headers = {
"Authorization": "Bearer sk_live_your_key_here",
"X-Account-Id": "user-123",
};
// List recent messages
const messages = await fetch(
"https://app.supyagent.com/api/v1/google/gmail/messages",
{ headers }
).then(r => r.json());
// Send an email
const sent = await fetch(
"https://app.supyagent.com/api/v1/google/gmail/messages/send",
{
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
to: "recipient@example.com",
subject: "Hello",
body: "Sent via the Connected Accounts API",
}),
}
).then(r => r.json());import requests
headers = {
"Authorization": "Bearer sk_live_your_key_here",
"X-Account-Id": "user-123",
}
# List recent messages
messages = requests.get(
"https://app.supyagent.com/api/v1/google/gmail/messages",
headers=headers,
).json()
# Send an email
sent = requests.post(
"https://app.supyagent.com/api/v1/google/gmail/messages/send",
headers={**headers, "Content-Type": "application/json"},
json={
"to": "recipient@example.com",
"subject": "Hello",
"body": "Sent via the Connected Accounts API",
},
).json()Google Calendar
# List upcoming events
curl https://app.supyagent.com/api/v1/google/calendar/events \
-H "Authorization: Bearer sk_live_your_key_here" \
-H "X-Account-Id: user-123"
# Create an event
curl -X POST https://app.supyagent.com/api/v1/google/calendar/events \
-H "Authorization: Bearer sk_live_your_key_here" \
-H "X-Account-Id: user-123" \
-H "Content-Type: application/json" \
-d '{
"summary": "Team Standup",
"start": "2026-03-01T09:00:00Z",
"end": "2026-03-01T09:30:00Z"
}'const headers = {
"Authorization": "Bearer sk_live_your_key_here",
"X-Account-Id": "user-123",
};
// List upcoming events
const events = await fetch(
"https://app.supyagent.com/api/v1/google/calendar/events",
{ headers }
).then(r => r.json());
// Create an event
const created = await fetch(
"https://app.supyagent.com/api/v1/google/calendar/events",
{
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
summary: "Team Standup",
start: "2026-03-01T09:00:00Z",
end: "2026-03-01T09:30:00Z",
}),
}
).then(r => r.json());headers = {
"Authorization": "Bearer sk_live_your_key_here",
"X-Account-Id": "user-123",
}
# List upcoming events
events = requests.get(
"https://app.supyagent.com/api/v1/google/calendar/events",
headers=headers,
).json()
# Create an event
created = requests.post(
"https://app.supyagent.com/api/v1/google/calendar/events",
headers={**headers, "Content-Type": "application/json"},
json={
"summary": "Team Standup",
"start": "2026-03-01T09:00:00Z",
"end": "2026-03-01T09:30:00Z",
},
).json()Slack
# Send a message
curl -X POST https://app.supyagent.com/api/v1/slack/messages \
-H "Authorization: Bearer sk_live_your_key_here" \
-H "X-Account-Id: user-123" \
-H "Content-Type: application/json" \
-d '{
"channel": "general",
"text": "Hello from the API!"
}'
# List channels
curl https://app.supyagent.com/api/v1/slack/channels \
-H "Authorization: Bearer sk_live_your_key_here" \
-H "X-Account-Id: user-123"const headers = {
"Authorization": "Bearer sk_live_your_key_here",
"X-Account-Id": "user-123",
};
// Send a message
const message = await fetch(
"https://app.supyagent.com/api/v1/slack/messages",
{
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
channel: "general",
text: "Hello from the API!",
}),
}
).then(r => r.json());
// List channels
const channels = await fetch(
"https://app.supyagent.com/api/v1/slack/channels",
{ headers }
).then(r => r.json());headers = {
"Authorization": "Bearer sk_live_your_key_here",
"X-Account-Id": "user-123",
}
# Send a message
message = requests.post(
"https://app.supyagent.com/api/v1/slack/messages",
headers={**headers, "Content-Type": "application/json"},
json={"channel": "general", "text": "Hello from the API!"},
).json()
# List channels
channels = requests.get(
"https://app.supyagent.com/api/v1/slack/channels",
headers=headers,
).json()GitHub
# List repositories
curl https://app.supyagent.com/api/v1/github/repos \
-H "Authorization: Bearer sk_live_your_key_here" \
-H "X-Account-Id: user-123"
# List issues for a repository
curl https://app.supyagent.com/api/v1/github/repos/owner/repo/issues \
-H "Authorization: Bearer sk_live_your_key_here" \
-H "X-Account-Id: user-123"const headers = {
"Authorization": "Bearer sk_live_your_key_here",
"X-Account-Id": "user-123",
};
// List repositories
const repos = await fetch(
"https://app.supyagent.com/api/v1/github/repos",
{ headers }
).then(r => r.json());
// List issues
const issues = await fetch(
"https://app.supyagent.com/api/v1/github/repos/owner/repo/issues",
{ headers }
).then(r => r.json());headers = {
"Authorization": "Bearer sk_live_your_key_here",
"X-Account-Id": "user-123",
}
# List repositories
repos = requests.get(
"https://app.supyagent.com/api/v1/github/repos",
headers=headers,
).json()
# List issues
issues = requests.get(
"https://app.supyagent.com/api/v1/github/repos/owner/repo/issues",
headers=headers,
).json()Checking Integration Status
Before making provider calls, verify the account has an active integration:
curl https://app.supyagent.com/api/v1/accounts/550e8400-e29b-41d4-a716-446655440000/integrations \
-H "Authorization: Bearer sk_live_your_key_here"const accountId = "550e8400-e29b-41d4-a716-446655440000";
const { data } = await fetch(
`https://app.supyagent.com/api/v1/accounts/${accountId}/integrations`,
{
headers: { "Authorization": "Bearer sk_live_your_key_here" },
}
).then(r => r.json());
const google = data.integrations.find(
(i: { provider: string }) => i.provider === "google"
);
if (google?.status === "active") {
// Safe to make Google API calls
}account_id = "550e8400-e29b-41d4-a716-446655440000"
response = requests.get(
f"https://app.supyagent.com/api/v1/accounts/{account_id}/integrations",
headers={"Authorization": "Bearer sk_live_your_key_here"},
).json()
google = next(
(i for i in response["data"]["integrations"] if i["provider"] == "google"),
None,
)
if google and google["status"] == "active":
# Safe to make Google API calls
passIntegration statuses:
| Status | Meaning |
|---|---|
active | Tokens are valid — API calls will succeed |
pending | OAuth flow started but not completed |
expired | Tokens expired and auto-refresh failed — user must re-authorize |
revoked | User revoked access from the provider's settings — user must re-authorize |
Error Handling
Account Not Found
If the X-Account-Id value doesn't match any account under your partner profile:
{
"ok": false,
"error": "Connected account \"invalid-id\" not found"
}Fix: Verify the external_id matches what you used when creating the account.
No Active Integration
If the account exists but doesn't have an active integration for the requested provider:
{
"ok": false,
"error": "No active google integration for this account",
"error_code": "INTEGRATION_NOT_FOUND"
}Fix: Initiate a connect session for the missing provider.
Token Errors
If the stored tokens are invalid or the refresh failed:
{
"ok": false,
"error": "Failed to refresh access token",
"error_code": "INTEGRATION_TOKEN_ERROR"
}Fix: The user needs to re-authorize. Create a new connect session for the provider.
Best Practices
- Check integration status first — before making provider calls, verify the integration is
activeto avoid token errors - Handle token errors gracefully — if you get
INTEGRATION_TOKEN_ERROR, prompt the user to re-connect the provider - Use the
external_idconsistently — map your internal user IDs to Supyagent'sexternal_idat account creation time, then use them for all API calls - Don't cache tokens — Supyagent handles token storage, refresh, and encryption. Always go through the API
- Monitor rate limits — check the
X-RateLimit-*headers in responses. See Usage & Billing for tier details