Platform Connect
Let merchants connect their Moosyl account to your platform in a few clicks. You receive their API keys and a webhook, so you can take payments on their behalf.
Platform Connect is for platforms that take payments for other businesses: store builders, booking tools, marketplaces, POS apps. Instead of asking each merchant to copy API keys into your settings page, you send them to Moosyl, they approve the connection, and your server receives their credentials.
If you only take payments for your own business, you don't need Connect. Use your own API keys.
Get platform credentials
Platform credentials are issued by Moosyl. Contact us with your platform's name, and you'll receive:
- a platform ID: public, used in the connect link
- a platform secret: private, used only by your server
The platform secret is shown once. Store it like a password, in your server's secret store, never in frontend or mobile code.
How it works
Send the merchant to Moosyl
Redirect the merchant to the connect page:
https://moosyl.com/connect
?platform_id=YOUR_PLATFORM_ID
&redirect_uri=https://yourplatform.com/moosyl/callback
&state=RANDOM_STATE
&environment=production| Parameter | Required | Description |
|---|---|---|
platform_id | Yes | Your platform ID. |
redirect_uri | Yes | Where Moosyl sends the merchant back. Must be an http or https URL. |
state | No | A random value you generate per request. Moosyl returns it unchanged; check it on the callback. |
environment | No | sandbox (default) or production: which of the merchant's environments to connect. |
If the merchant isn't signed in, Moosyl asks them to sign in first, then continues.
The merchant approves
Moosyl shows your platform's name and what it will be able to do: use the merchant's publishable and secret API keys for that environment, receive payment notifications at your webhook endpoint, and create payments on their behalf. The merchant can approve or deny.
Handle the callback
Moosyl redirects the merchant to your redirect_uri:
- Approved:
https://yourplatform.com/moosyl/callback?code=AUTHORIZATION_CODE&state=RANDOM_STATE - Denied:
https://yourplatform.com/moosyl/callback?error=access_denied&state=RANDOM_STATE
Check that state matches the value you sent before doing anything else. The code is valid for 5 minutes and can be used once.
Exchange the code for credentials
From your server, exchange the code:
const res = await fetch("https://api.moosyl.com/connect/exchange", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
platform_id: process.env.MOOSYL_PLATFORM_ID,
platform_secret: process.env.MOOSYL_PLATFORM_SECRET,
code,
// Receives both payment-created and payment-updated events
webhook_payment_created_endpoint: "https://yourplatform.com/moosyl/webhooks",
}),
});
const { data } = await res.json();
// data.connectionId, data.publishableKey, data.secretKey, data.webhookSecretThis endpoint doesn't use an Authorization header: your platform ID and secret authenticate the request.
The response:
{
"data": {
"connectionId": "7d2f0c1e-4b8a-4e59-9a6d-3c1b2e5f8a90",
"publishableKey": "…",
"secretKey": "…",
"webhookSecret": "…"
}
}webhook_payment_updated_endpoint from earlier versions is still accepted but ignored: both events go to webhook_payment_created_endpoint. Route them on the x-webhook-event header or the event field.
What the merchant's connection gives you
connectionId: identifies this connection. Store it: you need it to disconnect.publishableKeyandsecretKey: API keys created for your platform in the merchant's connected environment. The merchant sees them in their dashboard as "Connect: your platform name". Use them exactly like your own keys (see API keys and the Quickstart); every payment you create lands in the merchant's account.- A webhook in the merchant's environment, subscribed to
payment-createdandpayment-updated, signed withwebhookSecret. Verify it as described in Webhooks, using thiswebhookSecret.
Store these values per merchant, encrypted, on your server. The secretKey and webhookSecret must never reach a browser or mobile app.
Sandbox and production
A connection covers one environment. Connect with environment=sandbox while you build and test, then send the merchant through the flow again with environment=production when they go live. Each environment returns its own keys and webhook secret.
Reconnect a merchant
Sending a merchant through the flow again for the same environment keeps the same connectionId and webhook. The exchange returns new keys and a new webhook secret, and the previous keys stop working, so replace what you stored.
Disconnect a merchant
When a merchant leaves your platform, revoke the connection from your server:
await fetch("https://api.moosyl.com/connect/revoke", {
method: "POST", // DELETE also works
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
platform_id: process.env.MOOSYL_PLATFORM_ID,
platform_secret: process.env.MOOSYL_PLATFORM_SECRET,
connection_id: connectionId,
}),
});
// { "success": true }Revoking deletes the connection's keys and webhook, so your platform loses access right away. Merchants can also disconnect your platform from Connected Apps in their dashboard, with the same effect. After that, the stored keys return 401 Invalid API key: treat that as a disconnected merchant.
Errors
Exchange and revoke fail with one of these:
| Status | Message | What to do |
|---|---|---|
404 | Platform app not found | Check your platform_id, or contact us if your platform was deactivated. |
403 | Invalid platform credentials | Check your platform_secret. |
404 | Invalid authorization code | The code is wrong or belongs to another platform. Start the flow again. |
400 | Authorization code has already been used | Codes are single-use. Start the flow again. |
400 | Authorization code has expired | Exchange codes within 5 minutes. Start the flow again. |
404 | Connection not found | Revoke: the connection_id is wrong or belongs to another platform. |
Security checklist
- Generate a fresh, unguessable
statefor every connect link and reject callbacks where it doesn't match. - Exchange the code on your server only; the platform secret never leaves it.
- Encrypt stored merchant credentials at rest and scope access to them per merchant.
- Verify every webhook signature with that merchant's
webhookSecretbefore trusting the event.