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

# Connect

> Embed payment infrastructure directly into your platform.

Embed payment infrastructure directly into your platform. Create accounts for your users,
transfer funds in any direction, and drop in pre-built payout and pay-in widgets — all
through a single API.

Base URL is `https://app.sideshift.app/api/embed`.

## Setup guide

<Steps>
  <Step title="Generate an API key">
    Go to [Settings → Connect](https://app.sideshift.app/settings?tab=embed) and click
    **Generate API Key**. Copy it immediately — keys are only shown once.

    * `sk_live_*` — production (real money)
    * `sk_test_*` — sandbox (isolated balances, simulated payouts)

    <Warning>
      Never expose your API key in client-side code. All API calls must be made from your
      backend.
    </Warning>
  </Step>

  <Step title="Add allowed domains">
    In Settings → Connect, add the domains where you'll embed widgets.

    | Pattern           | Matches                                 |
    | ----------------- | --------------------------------------- |
    | `app.example.com` | Exact match                             |
    | `*.example.com`   | All subdomains                          |
    | `localhost`       | Any port (auto-allowed for development) |
  </Step>

  <Step title="Create user accounts">
    Every user who needs access to payments needs a SideShift Connect account.

    ```bash theme={null}
    curl -X POST https://app.sideshift.app/api/embed/accounts/create \
      -H "x-api-key: sk_live_YOUR_KEY" \
      -H "Content-Type: application/json" \
      -d '{ "email": "jane@example.com", "name": "Jane Creator", "externalId": "usr_123" }'
    ```

    Store the returned `sideshiftAccountId` — you'll need it for everything else.
  </Step>

  <Step title="Generate a widget token">
    Tokens authenticate embedded widget sessions. Generate them server-side.

    ```bash theme={null}
    curl -X POST https://app.sideshift.app/api/embed/auth/token \
      -H "x-api-key: sk_live_YOUR_KEY" \
      -H "Content-Type: application/json" \
      -d '{ "sideshiftAccountId": "acct_abc123", "widgetType": "both" }'
    ```

    The response includes `widgetUrls.payout` and `widgetUrls.payin` — use these as iframe
    sources or pass them to the SDK.
  </Step>

  <Step title="Embed the widget">
    <Tabs>
      <Tab title="iframe (recommended)">
        ```html theme={null}
        <iframe
          src="WIDGET_URL"
          width="100%" height="500"
          frameborder="0"
          allow="payment; camera; microphone"
          style="border:0; border-radius:12px"
        ></iframe>
        ```

        The iframe is the most reliable method — it works in any framework, needs no build
        tooling, and avoids dependency conflicts. The `allow="payment; camera; microphone"`
        attribute is required for KYC/identity verification inside the widget.
      </Tab>

      <Tab title="npm SDK">
        ```jsx theme={null}
        import { SideShiftPayout } from '@sideshiftapp/connect/react';

        <SideShiftPayout
          token={token}
          theme={{ theme: 'light', primaryColor: '#3D8CFA', borderRadius: 12 }}
          onWithdrawCompleted={(data) => console.log('Withdrew', data.amountCents)}
          onSessionExpired={() => refreshToken()}
        />
        ```

        The SDK is a thin wrapper around the same iframe — you get typed props, auto-resize,
        and event callbacks. Also available as `@sideshiftapp/connect/vanilla`.
      </Tab>

      <Tab title="iOS (SwiftUI)">
        ```swift theme={null}
        SideShiftConnect.configure(apiKey: "sk_live_YOUR_KEY")
        SideShiftPayoutView(accountId: "acct_abc123", currency: "USD")
        ```

        The iOS SDK manages tokens internally — no server-side token generation needed.
      </Tab>
    </Tabs>
  </Step>

  <Step title="Transfer funds">
    Move money between your company and user accounts.

    ```bash theme={null}
    curl -X POST https://app.sideshift.app/api/embed/accounts/transfer \
      -H "x-api-key: sk_live_YOUR_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "toAccountId": "acct_abc123",
        "amountCents": 5000,
        "idempotencyKey": "payout-001",
        "metadata": {
          "obligationType": "creator_agreement",
          "obligationReference": "agreement-001",
          "description": "Approved payment for completed creator deliverable",
          "approvalReference": "approval-001"
        }
      }'
    ```
  </Step>

  <Step title="Set up webhooks">
    Configure a webhook endpoint in Settings → Connect to receive `transfer.completed`,
    `deposit.*`, and `withdrawal.*` events. Always verify the signature.

    ```js theme={null}
    const crypto = require("crypto");
    function verify(payload, timestamp, signature, secret) {
      const expected = crypto.createHmac("sha256", secret).update(`${timestamp}.${payload}`).digest("hex");
      return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
    }
    ```
  </Step>
</Steps>

## Authentication

Include your API key in the `x-api-key` header on every request:

```
x-api-key: sk_live_your_key_here
```

Rotate your key anytime from Settings → Connect. The old key is invalidated immediately.

## Idempotency

Always include an `idempotencyKey` on transfer requests. Replaying a request with the same
key returns the original successful result instead of creating a duplicate.

## Rate limits

| Endpoint         | Limit                 |
| ---------------- | --------------------- |
| Account creation | 100/hour              |
| Token generation | 30/min per account    |
| Transfers        | 60/min (configurable) |
| General          | 100/min               |

Exceeding limits returns `429` with a `Retry-After` header.

## Sandbox

Use `sk_test_*` keys to test without moving real money. Sandbox balances are fully isolated
from live. Webhooks still fire so you can validate your full pipeline. All API endpoints
behave identically — same validation, same error codes, same response shapes.

### Sandbox behavior

* `paymentAccountId` values are prefixed with `sim_biz_*` (simulated)
* Company → User transfers are simulated — no real payout is executed, but the internal
  ledger is updated normally
* User → Company and User → User transfers work identically to production
* Webhook events are delivered to your configured endpoint
* Leaderboard and notification side effects are **not** triggered

### Payout widget in sandbox

When a widget token is generated with a `sk_test_*` key, the payout widget automatically
uses SideShift's sandbox payout environment. No additional configuration is required.

<Warning>
  The payout widget shows "Pending Balance from your platform" instead of the actual balance
  in sandbox mode. This is expected.
</Warning>

When you transfer funds with a `sk_test_*` key, the sandbox wallet is credited correctly on
the internal ledger. However, the payout widget's withdrawal UI cannot display the real
balance because the company ID is simulated (`sim_biz_*`) and the widget relies on the real
payments infrastructure to resolve balances.

* The `passedInBalance` field (if set) appears as a display-only "Pending Balance" label
* The withdrawal flow (bank account linking, payout initiation) is not fully functional in
  sandbox

In production with `sk_live_*` keys, transfers call the real payments API, funds land in the
creator's real wallet, and the balance and withdrawal UI work normally.

To verify sandbox transfers are working, use the balance API — this is the source of truth:

```bash theme={null}
GET /accounts/balance?sideshiftAccountId=ACCOUNT_ID
```

The `balanceCents` and `transactions` in the response accurately reflect all sandbox
transfers.

### Testing checklist

<Steps>
  <Step title="Generate a test key">Create an `sk_test_*` key and store it securely.</Step>
  <Step title="Create accounts">Create at least two sandbox accounts.</Step>
  <Step title="Test every direction">Company→user, user→company, and user→user.</Step>
  <Step title="Verify balances">Check the balance API after each transfer.</Step>
  <Step title="Replay a transfer">Reuse the same `idempotencyKey` and confirm no duplicate.</Step>
  <Step title="Check webhooks">Confirm delivery and that signature verification passes.</Step>
  <Step title="Trigger errors">Insufficient balance, invalid account — verify your handling.</Step>
  <Step title="Embed a widget">Test token generation and embedding.</Step>
</Steps>

### Go-live checklist

Before switching to `sk_live_*`:

1. Store your live API key in a production secrets manager
2. Confirm production domains in Settings → Connect (remove dev wildcards)
3. Verify your webhook endpoint uses HTTPS and validates signatures
4. Add retry handling with idempotency keys in your backend
5. Attach commercial evidence metadata to every transfer
6. Run a small live test (for example a \$0.50 transfer) before full volume

## Reference

<Note>
  This page is ported from the Connect specification's own introduction, so it stays in sync
  with what `app.sideshift.app/docs/connect` shows today.
</Note>

| Area          | What it does                                                                       |
| ------------- | ---------------------------------------------------------------------------------- |
| Accounts      | Create and manage user accounts. Each gets a `sideshiftAccountId` and a wallet     |
| Verifications | Read identity verification status and required actions for an account              |
| Transfers     | Move funds company→user, user→company, and user→user                               |
| Tokens        | Generate short-lived tokens that authenticate embedded widget sessions             |
| Checkout      | Create public hosted checkout links that settle into your SideShift wallet         |
| Webhooks      | Real-time notifications when transfers, deposits, and withdrawals complete or fail |

<Card title="API reference" icon="wallet" href="/connect/reference">
  All 17 operations across the six areas above.
</Card>

### Webhook events

Eight events are available:

`deposit.pending` · `deposit.confirmed` · `deposit.failed` · `transfer.completed` ·
`withdrawal.created` · `withdrawal.updated` · `withdrawal.completed` ·
`account.risk_flagged`

`withdrawal.completed` is a derived alias of `withdrawal.updated` filtered to
`status === "completed"`. Subscribe to it if you only want the terminal success event, or to
`withdrawal.updated` for the full lifecycle:

```
requested → awaiting_payment → in_transit → completed | failed | canceled | denied
```

Every delivery carries `x-sideshift-signature` and `x-sideshift-timestamp` headers.
Non-2xx responses are retried with exponential backoff, up to five attempts. Webhooks fire
in both sandbox and production.
