Supyagent
Connected Accounts

Code Examples

TypeScript, Python, and cURL examples for every Connected Accounts API operation — with reusable helpers and end-to-end integration patterns.

Code Examples

Complete examples for every API operation in TypeScript, Python, and cURL. Start with the helper functions to reduce boilerplate, then see examples for each operation.

Helper Functions

Reusable wrappers that handle authentication, error checking, and the X-Account-Id header pattern.

supyagent.ts
const BASE_URL = "https://app.supyagent.com/api/v1";

class SupyagentClient {
  constructor(private apiKey: string) {}

  private async request<T>(
    path: string,
    options: RequestInit = {},
    accountId?: string
  ): Promise<T> {
    const headers: Record<string, string> = {
      "Authorization": `Bearer ${this.apiKey}`,
      "Content-Type": "application/json",
      ...(options.headers as Record<string, string>),
    };

    if (accountId) {
      headers["X-Account-Id"] = accountId;
    }

    const response = await fetch(`${BASE_URL}${path}`, {
      ...options,
      headers,
    });

    const data = await response.json();

    if (!response.ok || !data.ok) {
      throw new Error(data.error || `Request failed: ${response.status}`);
    }

    return data.data;
  }

  // --- Accounts ---

  async createAccount(params: {
    external_id: string;
    display_name?: string;
    metadata?: Record<string, unknown>;
  }) {
    return this.request("/accounts", {
      method: "POST",
      body: JSON.stringify(params),
    });
  }

  async listAccounts(limit = 20, offset = 0) {
    return this.request(`/accounts?limit=${limit}&offset=${offset}`);
  }

  async getAccount(accountId: string) {
    return this.request(`/accounts/${accountId}`);
  }

  async updateAccount(
    accountId: string,
    params: { display_name?: string; metadata?: Record<string, unknown> }
  ) {
    return this.request(`/accounts/${accountId}`, {
      method: "PATCH",
      body: JSON.stringify(params),
    });
  }

  async deleteAccount(accountId: string) {
    return this.request(`/accounts/${accountId}`, { method: "DELETE" });
  }

  // --- Connect Sessions ---

  async createConnectSession(
    accountId: string,
    params: { provider: string; redirect_url: string; scopes?: string[] }
  ) {
    return this.request(`/accounts/${accountId}/connect`, {
      method: "POST",
      body: JSON.stringify(params),
    });
  }

  async getConnectSession(accountId: string, sessionId: string) {
    return this.request(`/accounts/${accountId}/connect/${sessionId}`);
  }

  // --- Integrations ---

  async listIntegrations(accountId: string) {
    return this.request(`/accounts/${accountId}/integrations`);
  }

  async disconnectProvider(accountId: string, provider: string) {
    return this.request(
      `/accounts/${accountId}/integrations/${provider}`,
      { method: "DELETE" }
    );
  }

  // --- Provider API Calls ---

  async providerGet(path: string, externalId: string) {
    return this.request(path, {}, externalId);
  }

  async providerPost(
    path: string,
    externalId: string,
    body: Record<string, unknown>
  ) {
    return this.request(
      path,
      { method: "POST", body: JSON.stringify(body) },
      externalId
    );
  }
}

// Usage
const client = new SupyagentClient("sk_live_your_key_here");
supyagent.py
import requests

BASE_URL = "https://app.supyagent.com/api/v1"


class SupyagentClient:
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.session = requests.Session()
        self.session.headers.update({
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json",
        })

    def _request(self, method: str, path: str, account_id: str | None = None, **kwargs):
        headers = {}
        if account_id:
            headers["X-Account-Id"] = account_id

        response = self.session.request(
            method, f"{BASE_URL}{path}", headers=headers, **kwargs
        )
        data = response.json()

        if not response.ok or not data.get("ok"):
            raise Exception(data.get("error", f"Request failed: {response.status_code}"))

        return data["data"]

    # --- Accounts ---

    def create_account(self, external_id: str, display_name: str | None = None,
                       metadata: dict | None = None):
        return self._request("POST", "/accounts", json={
            "external_id": external_id,
            "display_name": display_name,
            "metadata": metadata or {},
        })

    def list_accounts(self, limit: int = 20, offset: int = 0):
        return self._request("GET", f"/accounts?limit={limit}&offset={offset}")

    def get_account(self, account_id: str):
        return self._request("GET", f"/accounts/{account_id}")

    def update_account(self, account_id: str, **kwargs):
        return self._request("PATCH", f"/accounts/{account_id}", json=kwargs)

    def delete_account(self, account_id: str):
        return self._request("DELETE", f"/accounts/{account_id}")

    # --- Connect Sessions ---

    def create_connect_session(self, account_id: str, provider: str,
                               redirect_url: str, scopes: list[str] | None = None):
        return self._request("POST", f"/accounts/{account_id}/connect", json={
            "provider": provider,
            "redirect_url": redirect_url,
            **({"scopes": scopes} if scopes else {}),
        })

    def get_connect_session(self, account_id: str, session_id: str):
        return self._request("GET", f"/accounts/{account_id}/connect/{session_id}")

    # --- Integrations ---

    def list_integrations(self, account_id: str):
        return self._request("GET", f"/accounts/{account_id}/integrations")

    def disconnect_provider(self, account_id: str, provider: str):
        return self._request("DELETE", f"/accounts/{account_id}/integrations/{provider}")

    # --- Provider API Calls ---

    def provider_get(self, path: str, external_id: str):
        return self._request("GET", path, account_id=external_id)

    def provider_post(self, path: str, external_id: str, body: dict):
        return self._request("POST", path, account_id=external_id, json=body)


# Usage
client = SupyagentClient("sk_live_your_key_here")

Account Management

Create an Account

curl -X POST https://app.supyagent.com/api/v1/accounts \
  -H "Authorization: Bearer sk_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "external_id": "user-123",
    "display_name": "Jane Smith",
    "metadata": { "plan": "pro", "company": "Acme Corp" }
  }'
const account = await client.createAccount({
  external_id: "user-123",
  display_name: "Jane Smith",
  metadata: { plan: "pro", company: "Acme Corp" },
});

console.log(account.id);          // "550e8400-..."
console.log(account.external_id); // "user-123"
account = client.create_account(
    external_id="user-123",
    display_name="Jane Smith",
    metadata={"plan": "pro", "company": "Acme Corp"},
)

print(account["id"])          # "550e8400-..."
print(account["external_id"]) # "user-123"

List Accounts

# Default pagination (limit=20, offset=0)
curl https://app.supyagent.com/api/v1/accounts \
  -H "Authorization: Bearer sk_live_your_key_here"

# Custom pagination
curl "https://app.supyagent.com/api/v1/accounts?limit=50&offset=100" \
  -H "Authorization: Bearer sk_live_your_key_here"
const { accounts, total } = await client.listAccounts(50, 0);

console.log(`${total} accounts total`);
for (const account of accounts) {
  console.log(`${account.external_id}: ${account.display_name}`);
}
result = client.list_accounts(limit=50, offset=0)

print(f"{result['total']} accounts total")
for account in result["accounts"]:
    print(f"{account['external_id']}: {account['display_name']}")

Get Account Details

curl https://app.supyagent.com/api/v1/accounts/550e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer sk_live_your_key_here"
const account = await client.getAccount("550e8400-e29b-41d4-a716-446655440000");

console.log(account.display_name);
console.log(account.integrations); // List of connected providers
account = client.get_account("550e8400-e29b-41d4-a716-446655440000")

print(account["display_name"])
print(account["integrations"])  # List of connected providers

Update an Account

curl -X PATCH https://app.supyagent.com/api/v1/accounts/550e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer sk_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "display_name": "Jane Doe",
    "metadata": { "plan": "enterprise" }
  }'
const updated = await client.updateAccount(
  "550e8400-e29b-41d4-a716-446655440000",
  {
    display_name: "Jane Doe",
    metadata: { plan: "enterprise" },
  }
);
updated = client.update_account(
    "550e8400-e29b-41d4-a716-446655440000",
    display_name="Jane Doe",
    metadata={"plan": "enterprise"},
)

Delete an Account

Deleting an account cascades to all integrations and stored tokens. This cannot be undone.

curl -X DELETE https://app.supyagent.com/api/v1/accounts/550e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer sk_live_your_key_here"
await client.deleteAccount("550e8400-e29b-41d4-a716-446655440000");
client.delete_account("550e8400-e29b-41d4-a716-446655440000")

OAuth Connect Sessions

Start a Connect Session

curl -X POST https://app.supyagent.com/api/v1/accounts/550e8400-e29b-41d4-a716-446655440000/connect \
  -H "Authorization: Bearer sk_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "google",
    "redirect_url": "https://yourapp.com/callback"
  }'
const session = await client.createConnectSession(
  "550e8400-e29b-41d4-a716-446655440000",
  {
    provider: "google",
    redirect_url: "https://yourapp.com/callback",
  }
);

// Redirect the user to session.connect_url
console.log(session.connect_url);
console.log(session.session_id);
console.log(session.expires_at);
session = client.create_connect_session(
    "550e8400-e29b-41d4-a716-446655440000",
    provider="google",
    redirect_url="https://yourapp.com/callback",
)

# Redirect the user to session["connect_url"]
print(session["connect_url"])
print(session["session_id"])
print(session["expires_at"])

Check Session Status

curl https://app.supyagent.com/api/v1/accounts/550e8400-e29b-41d4-a716-446655440000/connect/660e8400-e29b-41d4-a716-446655440001 \
  -H "Authorization: Bearer sk_live_your_key_here"
const session = await client.getConnectSession(
  "550e8400-e29b-41d4-a716-446655440000",
  "660e8400-e29b-41d4-a716-446655440001"
);

if (session.status === "completed") {
  console.log(`${session.provider} connected successfully`);
}
session = client.get_connect_session(
    "550e8400-e29b-41d4-a716-446655440000",
    "660e8400-e29b-41d4-a716-446655440001",
)

if session["status"] == "completed":
    print(f"{session['provider']} connected successfully")

Integration Management

List Integrations

curl https://app.supyagent.com/api/v1/accounts/550e8400-e29b-41d4-a716-446655440000/integrations \
  -H "Authorization: Bearer sk_live_your_key_here"
const { integrations } = await client.listIntegrations(
  "550e8400-e29b-41d4-a716-446655440000"
);

for (const integration of integrations) {
  console.log(`${integration.provider}: ${integration.status}`);
}
result = client.list_integrations("550e8400-e29b-41d4-a716-446655440000")

for integration in result["integrations"]:
    print(f"{integration['provider']}: {integration['status']}")

Disconnect a Provider

curl -X DELETE https://app.supyagent.com/api/v1/accounts/550e8400-e29b-41d4-a716-446655440000/integrations/slack \
  -H "Authorization: Bearer sk_live_your_key_here"
await client.disconnectProvider(
  "550e8400-e29b-41d4-a716-446655440000",
  "slack"
);
client.disconnect_provider("550e8400-e29b-41d4-a716-446655440000", "slack")

Provider API Calls

All provider calls use the X-Account-Id header with the account's external_id. See Making API Calls for the full pattern.

If you're using the Node.js SDK, the client.asAccount() method handles the X-Account-Id header automatically:

import { supyagent } from '@supyagent/sdk';

const client = supyagent({ apiKey: process.env.SUPYAGENT_API_KEY! });
const userClient = client.asAccount('user-123');

// Fetch all tools scoped to this user's integrations
const tools = await userClient.tools({ cache: 300 });

// Or use skills for a more token-efficient approach
const { systemPrompt, tools: skillTools } = await userClient.skills({ cache: 300 });

See the SDK Partner Guide for full end-to-end examples.

Gmail — List 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"
const messages = await client.providerGet(
  "/google/gmail/messages",
  "user-123"
);
messages = client.provider_get("/google/gmail/messages", "user-123")

Gmail — Send 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 from Supyagent",
    "body": "This email was sent via the Connected Accounts API."
  }'
const result = await client.providerPost(
  "/google/gmail/messages/send",
  "user-123",
  {
    to: "recipient@example.com",
    subject: "Hello from Supyagent",
    body: "This email was sent via the Connected Accounts API.",
  }
);
result = client.provider_post(
    "/google/gmail/messages/send",
    "user-123",
    {
        "to": "recipient@example.com",
        "subject": "Hello from Supyagent",
        "body": "This email was sent via the Connected Accounts API.",
    },
)

Slack — Send 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 Supyagent!" }'
const result = await client.providerPost(
  "/slack/messages",
  "user-123",
  { channel: "general", text: "Hello from Supyagent!" }
);
result = client.provider_post(
    "/slack/messages",
    "user-123",
    {"channel": "general", "text": "Hello from Supyagent!"},
)

End-to-End Examples

Next.js API Route

A complete Next.js App Router API route that connects a user's Google account:

app/api/integrations/connect/route.ts
import { NextRequest, NextResponse } from "next/server";

const SUPYAGENT_API_KEY = process.env.SUPYAGENT_API_KEY!;
const BASE_URL = "https://app.supyagent.com/api/v1";

export async function POST(request: NextRequest) {
  const { userId, provider } = await request.json();

  // 1. Create or look up the connected account
  const accountRes = await fetch(`${BASE_URL}/accounts`, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${SUPYAGENT_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      external_id: userId,
      display_name: userId,
    }),
  });

  const accountData = await accountRes.json();

  // Handle duplicate — account already exists
  const accountId = accountRes.status === 409
    ? (await fetch(`${BASE_URL}/accounts?limit=1&offset=0`, {
        headers: { "Authorization": `Bearer ${SUPYAGENT_API_KEY}` },
      }).then(r => r.json())).data.accounts.find(
        (a: { external_id: string }) => a.external_id === userId
      )?.id
    : accountData.data.id;

  // 2. Create a connect session
  const connectRes = await fetch(`${BASE_URL}/accounts/${accountId}/connect`, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${SUPYAGENT_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      provider,
      redirect_url: `${process.env.NEXT_PUBLIC_APP_URL}/integrations/callback`,
    }),
  });

  const { data } = await connectRes.json();

  return NextResponse.json({ connect_url: data.connect_url });
}

Express Server

server.ts
import express from "express";

const app = express();
app.use(express.json());

const SUPYAGENT_API_KEY = process.env.SUPYAGENT_API_KEY!;
const BASE_URL = "https://app.supyagent.com/api/v1";

// Proxy provider calls through your server
app.get("/api/gmail/messages", async (req, res) => {
  const userId = req.headers["x-user-id"] as string; // Your auth

  const response = await fetch(`${BASE_URL}/google/gmail/messages`, {
    headers: {
      "Authorization": `Bearer ${SUPYAGENT_API_KEY}`,
      "X-Account-Id": userId,
    },
  });

  const data = await response.json();
  res.json(data);
});

app.listen(3000);

Python Flask

app.py
import os
from flask import Flask, request, jsonify
import requests

app = Flask(__name__)

SUPYAGENT_API_KEY = os.environ["SUPYAGENT_API_KEY"]
BASE_URL = "https://app.supyagent.com/api/v1"


@app.route("/api/gmail/messages")
def gmail_messages():
    user_id = request.headers.get("X-User-Id")  # Your auth

    response = requests.get(
        f"{BASE_URL}/google/gmail/messages",
        headers={
            "Authorization": f"Bearer {SUPYAGENT_API_KEY}",
            "X-Account-Id": user_id,
        },
    )

    return jsonify(response.json())


if __name__ == "__main__":
    app.run(port=3000)