Composer for platforms and merchant aggregatorss
Composer can process transactions for every sub-merchant on your platform from a single checkpoint. This guide covers how to structure checkpoints, environments, failover, and 3DS when you process payments on behalf of multiple businesses, each with its own gateway connection.
Who this guide is for
This guide is for platforms and merchant aggregators – marketplaces, reservation and booking platforms, SaaS platforms, and other businesses – that process payments on behalf of sub-merchants. It assumes:
- Each sub-merchant has its own gateway connection in your Spreedly organization (for example, a restaurant, seller, or brand that brings its own gateway), or you route sub-merchants across a set of gateways you manage.
- You already process transactions through the Spreedly API and are adding Composer, or you're building a new Composer integration.
If you process payments only for your own business, start with Building a transaction processing checkpoint instead.
Before you start
You need:
- Gateways connected for your sub-merchants under Connect.
- Payment methods tokenized in the Spreedly Vault. Collect them with Checkout SDK, iFrame, or the API before the checkpoint runs.
- The Composer Server SDK installed on your backend. See Server SDKs.
- An organization-level access secret, if your sub-merchant gateways are in more than one environment.
How your Spreedly setup maps to Composer
| Spreedly concept | Role in Composer |
|---|---|
| Organization | Checkpoints belong to your organization and can serve every sub-merchant in it. |
| Environment | Each checkpoint runs against one globally configured environment by default. You can override it per transaction. |
| Gateway | Each sub-merchant's gateway token is passed in the request, or set on a step for gateways you always use. |
| Payment method token | Passed in the request. The payment method must be in the Vault. |
Recommended structure: Keep sub-merchant gateways in the same environment as your checkpoint where possible. A single environment avoids per-transaction environment overrides and makes testing and reporting simpler.
Process every sub-merchant from one checkpoint
The Authorization, Purchase, Verify, and General Credit steps each have a Gateway Token field:
- Set: The step always uses that gateway. Any
transaction.gatewayTokenin the request is ignored. - Blank: The step uses the
transaction.gatewayTokensent in the request.
To process for all of your sub-merchants from one checkpoint:
- In Checkpoint Studio, add your transaction steps and leave Gateway Token blank on each step that should use the sub-merchant's gateway.
- In your application, look up the sub-merchant's gateway token for the transaction.
- Pass it in the request as
transaction.gatewayToken.
import { Composer } from '@spreedly/composer-sdk-server'
const composer = new Composer(process.env.SPREEDLY_SECRET_KEY)
const checkpointResponse = await composer.checkpoint({
checkpointName: 'MAKE_PAYMENT',
event: {
ip: getIp(req),
data: {
paymentMethod: { token: paymentMethodToken },
transaction: {
amount: 4500,
currency: 'USD',
gatewayToken: subMerchant.gatewayToken
}
}
},
sourceToken: req.headers['x-dodgeball-source-token'],
sessionId: req.session.id,
userId: req.session.userId,
useVerificationId: req.headers['x-dodgeball-verification-id']
})
if (composer.isAllowed(checkpointResponse)) {
// proceed
} else if (composer.isRunning(checkpointResponse)) {
// return the verification to the client for handleVerification()
} else if (composer.isDenied(checkpointResponse)) {
// decline
} else {
// error
}Always send
transaction.currencyexplicitly, especially when sub-merchants transact in different currencies.
Sending the gateway token every time
Expected Data (Trigger node → Expected Data → Copy Schema as JSON) lists transaction.gatewayToken as optional, because it's only used when a step's Gateway Token is blank. If any of your transaction steps leave Gateway Token blank, treat transaction.gatewayToken as required in your integration and send it on every request.
Other steps in your checkpoint add their own required fields. For example, a fraud step may require order, customer, and device data, and a 3DS step requires browser data. Use Copy Schema as JSON to see the full list for your checkpoint.
Apply different logic to different sub-merchants
Some sub-merchants may need different rules – different failover paths, fraud thresholds, or 3DS behavior. To branch on sub-merchant, pass your own identifier in transaction.metadata with each request and use it as a condition in a Decision step. Metadata keys are case sensitive. You can also pass sub-merchant key's in Spreedly transaction step inputs, for example spreedly.purchase.inputs.subMerchantKey. Spreedly attaches the sub-merchant's details to the transaction.
{
"paymentMethod": { "token": "{{payment_method_token}}" },
"transaction": {
"amount": 4500,
"currency": "USD",
"gatewayToken": "{{sub_merchant_gateway_token}}",
"metadata": { "subMerchantId": "{{your_sub_merchant_id}}" }
},
"spreedly": {
"purchase": {
"inputs": {
"subMerchantKey": "{{spreedly_sub_merchant_key}}"
}
}
}
}
You can also route on card data:
- Normalized fields keep step configuration and decision logic the same across branches that use different gateways.
- BIN metadata (card brand, type, issuing country) requires Advanced Vault to be enabled for your organization.
See Routing on BIN metadata & normalized fields.
Failover and merchant of record
Recover retries a soft decline or gateway outage on one or two failover gateways. For platforms, two details matter.
Failover gateways are step settings. The First and Second Failover Gateway Tokens are set on the step, not passed in the request. Every sub-merchant processed by that step fails over to the same gateways.
Coming soon: failover gateways per requestYou'll be able to pass failover gateway tokens in the checkpoint request, so each sub-merchant can use its own failover gateways without configuring them on the step. Until then, use one of the options below.
Failover can change the merchant account. If a sub-merchant's transaction fails over to a gateway on a different merchant account – such as your platform's own account – the charge settles to that account, not the sub-merchant's. Confirm this matches your merchant-of-record, settlement, and contractual arrangements before enabling Recover on a step that processes sub-merchant gateways.
Until per-request failover is available, use one of these patterns:
- Failover only on gateways you own. Enable Recover only on branches that use your platform's gateways, and send sub-merchant transactions down branches without Recover.
- Separate branches per failover path. Use a Decision step to send sub-merchants with different failover arrangements to separate branches, each with its own Recover settings. This works best when many sub-merchants share the same failover gateways.
- Recover through the Spreedly API. Use the checkpoint for fraud, 3DS, and routing decisions, then call the Spreedly Authorize or Purchase API with a
retryobject containing the sub-merchant's failover gateway tokens. See Recover.
Also note:
- Gateway support: Standard mode requires the step's primary gateway to be a Recover-supported gateway. Outage Only mode works with any primary gateway. See Recover.
- Gateway-specific fields: When using Recover, send gateway-specific fields for the primary gateway and every failover gateway.
- Enablement: Recover is an optional paid service and must be enabled by Spreedly for production use. Contact your account manager or [email protected].
3DS for sub-merchants
If sub-merchants use different 3DS providers, pass each sub-merchant's SCA provider key per request instead of building a checkpoint per provider:
- 3DS on a transaction step: Pass the key in the step's inputs, for example
spreedly.purchase.inputs.scaProviderKeyfor a Purchase step. - Separate 3DS steps: Pass the key in
spreedly.scaAuthentication.inputs.scaProviderKey. If you don't pass one, the step falls back to the SCA Provider Key in your Spreedly configuration. See Add 3DS Global as a checkpoint step.
When overriding:
- The SCA provider must match the environment used for the request.
- If you also override the environment, the configured access secret must be an organization-level access secret.
3DS challenges need the shopper's browser. Initialize the Composer Client SDK on pages where a challenge can occur, and handle BLOCKED / PENDING checkpoint responses with handleVerification().
Sub-merchant gateways in multiple environments
By default, every checkpoint runs against a single globally configured environment. If your sub-merchant gateways are in different environments:
- Configure your Spreedly service connection with an organization-level access secret.
- Pass the environment key for the sub-merchant's gateway in the transaction step's inputs, for example
spreedly.purchase.inputs.environmentKeyfor a Purchase step.
{
"paymentMethod": { "token": "{{payment_method_token}}" },
"transaction": {
"amount": 4500,
"currency": "USD",
"gatewayToken": "{{sub_merchant_gateway_token}}"
},
"spreedly": {
"purchase": {
"inputs": {
"environmentKey": "{{sub_merchant_environment_key}}"
}
}
}
}What stays on the Spreedly API
Some platform flows aren't supported inside a checkpoint in this release. Keep these on your existing Spreedly API integration:
| Flow | Why |
|---|---|
| Payment Method Distribution (PMD) to receivers | Not supported from inside a checkpoint in this release. |
| Gateway "processing" responses that need polling | Composer doesn't poll a processing response through to a final outcome. |
Your existing API calls can stay active as a fallback while you move supported flows to Composer.
Testing your setup
There's no separate test mode. The gateway token decides whether a transaction is test or live.
- Create sandbox or test gateways for a representative set of sub-merchants, including at least one per gateway type you support.
- Pass sandbox gateway tokens in the request and confirm each transaction runs against the expected gateway.
- Test a request with a missing gateway token and one with an invalid token, and confirm your application handles the response.
- If you use Recover, test failover with sandbox gateways only. Recover doesn't need to be enabled for sandbox testing, but all gateways in a test transaction must be non-production.
- If you use Decision steps per sub-merchant, test each branch with its own sub-merchant.
- If you override environments, test at least one sub-merchant in each environment.
- Check each transaction in Developer Center > Logs.
Going live
- Publish the checkpoint. Publishing is required before it responds to real requests.
- Start with a small set of sub-merchants or a small share of traffic, keeping your existing API path as a fallback.
- Expand to more sub-merchants once results match your API baseline.
To roll back, select the previous published version from the Version menu and click Export. In Checkpoint Studio, click Import Checkpoint, paste the JSON, and change workflow.name to a new name (uppercase, no spaces or special characters). Validate, import, and publish it, then update checkpointName in your application.
Known limitations
- Recover failover gateways can't be passed per request yet. Coming soon.
- Network Token / PAN Retry configuration isn't available yet.
- PMD isn't supported from inside a checkpoint.
Updated 29 minutes ago

