Skip to main content
SideShift Connect puts a wallet inside your own product. You create a Connect account for each of your users, move money between your company and those accounts over one REST API, and drop in pre-built payout and pay-in widgets so your users never leave your page. A hosted checkout, a webhook feed and a full sandbox come with it. Base URL is https://app.sideshift.app/api/embed. Every request carries your key in the x-api-key header, and every response is wrapped in the same envelope.

What you can build

Accounts

One Connect account per user, keyed by your own externalId. Each account has a SideShift wallet and a withdrawal-ready balance.

Transfers

Company to user, user to company, and user to user. Idempotent, with atomic batches of up to 200.

Widgets

Payout and pay-in widgets as iframes, authenticated with short-lived tokens and restyled with URL parameters.

Hosted checkout

A public checkout link or embedded checkout that settles into a SideShift wallet.

Webhooks

Nine signed events covering deposits, transfers, withdrawals and risk flags, with logs, replay and a test endpoint.

Sandbox

sk_test_ keys, isolated wallets seeded with $10,000, provider test cards, and a separate sandbox webhook.

How the pieces fit

1

Your backend creates an account

POST /accounts/create with the user’s email and your stable externalId. Store the returned sideshiftAccountId.
2

Your backend moves money

POST /accounts/transfer pays the user from your company wallet, or pulls funds back. Each call carries an idempotencyKey so retries are safe.
3

Your backend mints a widget token

POST /auth/token returns a short-lived token bound to one domain, plus ready-made widget URLs.
4

Your frontend embeds the widget

The payout widget shows the balance, handles identity verification and lets the user withdraw. The pay-in widget lets them add funds.
5

SideShift tells you what happened

Webhooks report deposits, completed transfers and every withdrawal status change, signed with HMAC-SHA256.

Concepts

Accounts

A Connect account is a SideShift user created through your integration. It is identified everywhere by sideshiftAccountId. Send your own user id as externalId when you create it: SideShift checks externalId before the email, so the same user keeps resolving to the same account even after they change their email address. An account is either created by your integration (full access, including transfers out and widget withdrawals) or merely linked to it (readable and payable, but the payout widget sends the user to the SideShift app to withdraw).

Where the money sits

A managed account has one balance that matters: its withdrawable balance, held at the payment provider. That is what the payout widget shows, what the user can withdraw, and what a user_to_company transfer pulls back from. GET /accounts/balance reports it as withdrawableBalanceCents (alias balanceCents). The account also has an internal SideShift wallet, reported as walletBalanceCents. Money lands there only when it is paid in through the pay-in widget or an invoice, or when a transfer is sent with the deprecated destinationBalance: "wallet". Funds in the internal wallet are not withdrawable until POST /accounts/withdrawal-balance moves them across, which is why new integrations should leave destinationBalance at its default. totalBalanceCents is the sum of the two.

Transfer directions

Transfers out of a user account (user_to_company, user_to_user) are only permitted from accounts your integration created.

Environments

The key prefix is the whole switch. sk_live_ keys move real money. sk_test_ keys run against isolated sandbox wallets, a separate sandbox webhook configuration, and the payment provider’s official sandbox. Paths, bodies, response shapes, validation and error codes are the same in both. See Testing for exactly what sandbox does and does not cover.

Conventions

Envelope. A successful response is { "success": true, "data": … }. A failure is { "success": false, "error": { "code", "message", "details"? } }. Account creation returns 201 when it creates and 200 when it reuses an existing account; everything else returns 200 on success. Amounts are integer cents in USD. amountCents: 5000 is $50.00. Non-integers are rejected. Idempotency. Every transfer requires an idempotencyKey of at least 8 characters. Keys are permanent, scoped to your integration and environment, and replaying one returns the original result instead of moving money again. Metadata on transfers is a flat object of string keys and string values: at most 50 keys, keys up to 40 characters, values up to 500 characters. It is stored, returned on reads, searchable on GET /transfers, and echoed in transfer.completed webhooks. Rate limits. 100 requests per minute and 100 widget tokens per hour per company, counted separately for live and sandbox, and 1,000 transfers per UTC day. Details are on Configuration.

Where to go next

Getting started

Get a key, create an account, mint a token and embed your first widget.

Testing

The sandbox, a complete test plan, and the go-live checklist.

Webhooks

Every event with a full payload, signature verification, retries and replay.

Errors

Every error code, what triggers it, and what to do.

Guides

Escrow, hosted checkout, withdrawal fee markups, white-label domains.

Status

Live component health, 90-day uptime and incidents, as a page and as JSON.

Reference

The generated reference for each operation is in the sidebar under Reference, and the OpenAPI document is at app.sideshift.app/openapi/sideshift-connect.yaml.