Skip to main content
This page takes you from nothing to a working payout widget on your own page, using a sandbox key so no real money moves. Every call below behaves identically with a live key.

Before you start

Connect is off by default. Until SideShift enables it for your company, every call returns 403 EMBED_NOT_ENABLED with the message Embed access is not enabled for this company. Contact support to request access. Check this first rather than last. You also need a payment account on your company before a key can be generated. The console shows a “Payment account required” prompt in place of the key controls until it exists.

API keys

Keys live in the Connect console at app.sideshift.app/connect?tab=widgets, under API Keys. There are two independent modes, each with its own Generate button. A key is the prefix plus 32 characters of base64url, so it can contain - and _. SideShift stores a SHA-256 hash and a short preview, which is why a key is shown exactly once and cannot be recovered. A company can hold several active keys per mode; each has its own id and name and is revoked independently, so rotation is create, deploy, then revoke. Send the key in the x-api-key header on every request, and keep it in an environment variable rather than in code:
The key is a server-side credential with full access to your accounts and transfers. It must never reach a browser or a mobile binary. Widgets authenticate with short-lived tokens instead, which is what lets the key stay on your backend.

Your first integration

1

Create an account for your user

Only email is required. name is trimmed to 100 characters and externalId to 200.Send externalId anyway. SideShift checks it before the email, so the same externalId keeps returning the same account even after the user changes their email address. Without it, one person with two addresses becomes two separately payable accounts.You get 201 on creation and 200 when the account already existed, with the same body either way:
A reused account carries "created": false and "alreadyExists": true. If SideShift had to provision the account under a fallback email, emailModified is true and originalEmail holds what you sent; see account fallback emails.Store data.sideshiftAccountId. It is the handle for everything else.
2

Allow the domain you will embed on

In the console, add the domains the widget is allowed to load on. A pattern matches exactly, or as *.example.com for the base domain and every subdomain.This step is not optional bookkeeping. Every token is bound to one domain when it is minted. The endpoint picks that domain from targetDomain in the body if you send one, otherwise from the request’s Origin header, otherwise from the first entry on your allowlist. A server-side call sends no Origin, so with an empty allowlist there is nothing to bind to and the next step fails with 400 DOMAIN_NOT_ALLOWED.localhost cannot be added to the list (entries need a dot) and does not need to be: a widget loaded from localhost, 127.0.0.1, 0.0.0.0 or ::1 passes the domain check on any port. Add your real domain now and develop on localhost.
3

Mint a widget token

sideshiftAccountId and widgetType are required. widgetType is payout, payin or both.
expiresInSeconds defaults to 3600 and accepts 60 to 86400. A value outside that range is rejected with 400 VALIDATION_ERROR rather than clamped, so range-check it before sending.widgetUrls only contains the widgets you asked for. If you saved a widget theme in the console, the URLs already carry it as query parameters; append your own with &.
The account has to belong to your integration. An id you did not create or link comes back as 404 ACCOUNT_NOT_FOUND, not 403. That is deliberate: a 403 would confirm the account exists, which would turn this endpoint into a way to probe for accounts on other platforms.
Token minting is limited to 100 per hour per company and mode, on top of the general per-minute limit. Mint one token per widget session, not one per page render.
4

Embed the widget

Use widgetUrls from the response directly as the iframe src.
The allow attribute matters. Identity verification uses the camera, and card flows need payment permissions. Without it those steps fail inside the frame.The token sits in the URL path, so anything that logs full URLs logs a live credential. Keep lifetimes short and mint the token on your backend at the moment you render the page.
5

Pay the user

Move money from your company wallet into the user’s account. In sandbox your company wallet is seeded with $10,000 on the first authenticated request, so this works immediately.
idempotencyKey is required and must be at least 8 characters. Sending the same request again returns this same result instead of paying twice. The metadata block is the commercial evidence live integrations must attach; it is optional in sandbox. Full semantics are on Testing and Configuration.
6

Listen for events

Configure a webhook endpoint in the console and verify every delivery’s signature. The event you will want first is transfer.completed.
Deliveries are attempted up to three times, one second then two seconds apart, and are deduplicated by the X-Sideshift-Event-Id header. Every event, header and retry rule is on Webhooks.

Where to go next

Testing

What sandbox covers, test cards, and a step-by-step plan through accounts, transfers, widgets, checkout and webhooks.

Embedding and customization

Sizing, overlays, every theme and label parameter, and the events the widget posts back to your page.

Configuration

Keys, allowed domains, limits and the settings that shape an integration.

Errors

Every code the API returns and what to do about it.