Skip to main content
Concepts

Connect Links

Hosted OAuth flow that lets your end users connect their own Stripe, Mercado Pago, Shopify, and other provider accounts — without you building or maintaining a connection UI.

1 min read · updated

Connect Links

@codespar/sdkv0.3.0

A Connect Link is a hosted page that runs the entire OAuth dance for an end user: provider consent, callback handling, token exchange, encrypted storage, and scope checks. Your agent sends the link, the user clicks, and on the next tool call CodeSpar uses the stored credentials automatically.

You never touch raw provider tokens. You never build a connection UI. You never write the refresh logic.

Connect Links are for end-user authentication — your customers connecting their own Stripe / Mercado Pago / Shopify accounts. For your credentials (the platform's own provider keys shared across all users), use Service Auth instead.

Lifecycle

A connection moves through a small state machine:

     start              authorize            token exchange
  ┌────────┐  link    ┌──────────┐  code   ┌──────────────┐
  │ CLIENT │ ───────▶│ HOSTED   │ ──────▶│ CODESPAR      │
  │        │         │ PAGE     │         │ VAULT         │
  └────────┘         └──────────┘         └──────────────┘
      │                                          │
      │            tools execute                 │
      │ ◀────────────────────────────────────────┘
      │            using stored credential
StatusMeaning
pendingA Connect Link was issued. User has not authorized yet.
connectedToken stored in vault, scoped to userId. Tools will run.
expiredRefresh token is dead (user revoked on the provider side, or token TTL elapsed without activity). Re-issue a Connect Link.
revokedYour application called /v1/connections/:id/revoke. Stored credentials were deleted.

Credentials are scoped to the userId you passed to codespar.create(). User A never reaches user B's Stripe account — tenant isolation is enforced in the vault, not at the application layer.

Two integration patterns

Pick the pattern that matches when the user connects.

Pattern 1 — in-chat

The user is already in a conversation with your agent. The agent tries a tool, CodeSpar notices no connection exists, and the tool result returns a Connect Link that the agent surfaces in the chat.

const session = await codespar.create("user_abc", {
  servers: ["stripe"],
  manageConnections: { waitForConnections: false },
});

const result = await session.execute("codespar_checkout", {
  amount: 14900,
  currency: "BRL",
});

if (result.error === "needs_connection") {
  // result.data.connect_url is the hosted page
  // Send it to the user in the conversation
  await chat.send(`Connect your Stripe account to continue: ${result.data.connect_url}`);
}

Use when: chat-first products where interrupting the flow for an onboarding page hurts conversion. WhatsApp commerce agents, embedded support assistants, in-app copilots.

Pattern 2 — manual (pre-onboarding)

You want users connected before they chat. Your onboarding screen or settings page calls session.authorize() and redirects to the Connect Link.

const session = await codespar.create("user_abc", {
  servers: ["stripe"],
});

const { connected, redirectUrl } = await session.authorize("stripe");

if (!connected && redirectUrl) {
  window.location.href = redirectUrl;
}

After the user authorizes, your configured success redirect URL is called. On subsequent agent runs, any session created with the same userId picks up the stored credential automatically.

Use when: dashboards, settings pages, multi-tenant SaaS products where "connect your accounts" is part of onboarding.

session.authorize()

The SDK entry point for issuing a Connect Link.

const result = await session.authorize("stripe", {
  redirectUrl: "https://app.example.com/onboarding/done",
  scopes: ["read_write"], // override defaults
});

Returns:

interface AuthResult {
  connected: boolean;      // true if already connected — skip redirect
  redirectUrl?: string;    // hosted Connect Link URL
  error?: string;          // if the server does not support this auth type
}

If connected: true you can skip the redirect entirely — the stored credential is still valid.

Backend shape

The SDK wraps three HTTP endpoints. You can call them directly from any language.

MethodEndpointPurpose
POST/v1/connections/startIssue a Connect Link for a user + server
GET/v1/connectionsList this user's connections and statuses
POST/v1/connections/:id/revokeDelete the stored credential (end-user opt-out)

POST /v1/connections/start

curl -X POST https://api.codespar.dev/v1/connections/start \
  -H "Authorization: Bearer csk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "user_id": "user_abc",
    "server_id": "stripe",
    "redirect_url": "https://app.example.com/onboarding/done"
  }'

Response:

{
  "link_token": "clt_abc123...",
  "authorize_url": "https://codespar.dev/connect/stripe?token=clt_abc123",
  "expires_at": "2026-04-17T16:00:00Z"
}

The authorize_url is the Connect Link. link_token expires after 15 minutes; re-issue if the user takes longer.

GET /v1/connections

curl https://api.codespar.dev/v1/connections?user_id=user_abc \
  -H "Authorization: Bearer csk_live_..."

Response:

{
  "data": [
    {
      "id": "conn_abc123",
      "server_id": "stripe",
      "user_id": "user_abc",
      "auth_type": "oauth",
      "status": "connected",
      "display_name": "acme-store.myshopify.com",
      "connected_at": "2026-04-17T15:30:00Z",
      "expires_at": "2027-04-17T15:30:00Z"
    }
  ]
}

Customizing the hosted page

Connect Links inherit your org's branding. Configure once in Settings:

SettingEffect
LogoShown at the top of the hosted page
Accent colorPrimary button and links
Custom domainServe from connect.yourdomain.com instead of codespar.dev/connect/* (requires CNAME + certificate)
Success redirectDefault URL after authorization if redirect_url is omitted
Legal footerPrivacy policy and ToS links shown beside provider consent

The Connect Link page is static HTML + CSS — no third-party scripts, no analytics pixels. It's designed to pass enterprise security reviews on the first pass.

Troubleshooting

The user authorized but status is still pending. Wait up to 10 seconds — the callback is asynchronous. If it still hasn't flipped, check the triggers event stream: a failed token exchange fires connection.failed with an error_code explaining why (scope rejected, redirect URI mismatch, etc.).

"redirect_uri_mismatch" from the provider. Your provider's app config must whitelist https://codespar.dev/oauth/callback (or your custom domain's equivalent). See the provider page for the exact URI.

The Connect Link works in test but 404s in production. Live keys issue live Connect Links; test keys issue test Connect Links. You cannot hand a csk_test_-issued link to a user authenticating against a real Stripe account.

Expired token after months of inactivity. Providers revoke refresh tokens when a user hasn't used your app for a provider-defined period (Stripe: 13 months, Shopify: 24 hours of inactivity on some scopes). CodeSpar fires connection.expired via a trigger — re-issue a Connect Link when you receive it.

Next steps

Last updated on