> ## Documentation Index
> Fetch the complete documentation index at: https://docs.agentcard.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Connect for platforms

> Onboard companies onto Agentcard from your own product and act on their behalf.

Put a **Connect to Agentcard** button in your dashboard. Your customer clicks
it, lands on an Agentcard-hosted flow, signs in (or signs up), picks or creates
their company's organization, and comes straight back to your site. You then
exchange a one-time code for that organization's `client_id` + `client_secret`
— and from there you call the API on their behalf, exactly like the flow
Stripe Connect uses.

Every organization connected this way is attributed to your platform.

<Note>
  Platform connect requires the platform capability on your organization.
  [Contact us](mailto:support@agentcard.sh) to enable it. You also need a
  confidential OAuth client (Organization → Developer → Credentials) with your
  `return_url` registered as a redirect URI — creating sessions and exchanging
  codes only works with client-credentials auth, never with API keys.
</Note>

## Instructions for your agent

Paste this into your coding agent to implement the flow.

```text Instructions for your agent theme={null}
You are adding "Connect to Agentcard" to this platform: our customer (a
company) clicks a button, completes Agentcard's hosted onboarding, returns to
us, and we obtain API credentials to act on their behalf. Implement it
server-side. Never expose secrets or codes to the browser beyond the redirect.

PREREQUISITES
- Our own client_id + client_secret from the Agentcard dashboard
  (Organization -> Developer -> Credentials). Our redirect/return URL must be
  registered as a redirect URI on that client.
- The organization must have the platform capability enabled by Agentcard.
- Base URL https://api.agentcard.sh. All calls are backend-to-backend.

1. PLATFORM TOKEN (cache ~55 min)
POST /api/v2/oauth/token  (x-www-form-urlencoded)
  grant_type=client_credentials & client_id=... & client_secret=...
-> { access_token }. Send `Authorization: Bearer <access_token>` on every call.

2. START A SESSION (when the customer clicks Connect)
POST /api/v2/platform_connect_sessions
  { "return_url": "https://ourapp.com/agentcard/callback", "state": "<random, bound to this customer's browser session>" }
-> 201 { id, url, expires_at, ... }   // store id; redirect the customer to url

3. THE CUSTOMER COMPLETES THE HOSTED FLOW (sign in, pick/create their org).
We receive a redirect: GET <return_url>?code=pcc_...&state=<state>
- Verify state matches what we issued for this browser session (CSRF).

4. EXCHANGE THE CODE (server-side, within 10 minutes; single use)
POST /api/v2/platform_connect_sessions/{id}/exchange   { "code": "<code>" }
-> 200 { organization: { id, name }, client_id, client_secret, test_mode }
Store organization.id + client_id + client_secret encrypted, keyed to our
customer record. The secret is returned ONLY here. The exchange is one-shot:
persist the response before acking — if we lose it, a retry returns
invalid_code and the customer must redo the flow.

5. ACT ON THEIR BEHALF
POST /api/v2/oauth/token with the STORED per-organization credentials
-> an access token scoped to that organization. Use it against /api/v2.
Confirm with GET /api/v2 -> { organization_id } matches organization.id.

STATUS / RECOVERY
- GET /api/v2/platform_connect_sessions/{id} -> { status, connected_organization_id }
  status: pending | bound | completed (code issued, unclaimed) | claimed | expired.
- If the customer abandons the flow (session expires after 60 min), create a
  fresh session next click. If the code expired before exchange, the customer
  re-runs the flow.
- Optional webhook: platform_connect_session.completed fires to our registered
  Agentcard webhook endpoint with { session_id, state, connected_organization_id }
  (never credentials) — treat it as a nudge and still exchange server-side.

ERRORS: { error: { code, message, docs } } — branch on code
(client_credentials_required, platform_not_enabled, invalid_return_url,
invalid_code).
```

## How it works

<Steps>
  <Step title="Create a session">
    When your customer clicks **Connect to Agentcard**, call
    [`POST /api/v2/platform_connect_sessions`](/companies/api/reference/platform-connect-create)
    with your `return_url` and a `state` value bound to their browser session.
    Redirect them to the returned `url`.
  </Step>

  <Step title="The customer connects">
    On the hosted page they sign in (or create an account), then pick an
    existing organization they administer — or create a new one — and confirm
    what your platform gets. No document checks; the whole flow is a minute.
  </Step>

  <Step title="Receive the redirect">
    We send them back to your `return_url` with `?code=…&state=…`. Verify
    `state`, then exchange the code server-side with
    [`POST /api/v2/platform_connect_sessions/{id}/exchange`](/companies/api/reference/platform-connect-exchange).
    Codes are single-use and expire after 10 minutes.
  </Step>

  <Step title="Act on the organization's behalf">
    The exchange returns the organization's own `client_id` + `client_secret`.
    Mint access tokens with
    [`POST /api/v2/oauth/token`](/companies/api/reference/create-access-token)
    and call the API as that organization — issue cards to its users, run
    [user authentication](/companies/api/user-authentication), read
    transactions.
  </Step>
</Steps>

## Security model

* **No secrets in URLs.** The redirect carries only the one-time `code` and
  your `state`; credentials move server-to-server on the exchange.
* **The code is bound to your client.** Only the exact OAuth client that
  created the session can exchange its code — a leaked code is useless to
  anyone else.
* **`state` is your CSRF binding.** Issue a random value per connect attempt
  and verify it on the redirect before exchanging.
* **Revocable by the customer.** The credential you receive appears on the
  organization's Credentials page, named after your platform; its admins can
  rotate or revoke it at any time.

## Test mode

A sandbox client runs the entire flow in test mode: the minted credentials are
sandbox-mode, no live cards or real money, and `http://localhost` return URLs
are allowed. Move to a production client when you go live.
