Getting started
This guide takes you from an empty account to a routed test order: two shops, one rule, one payment that Shop A sells and Shop B charges. Budget about twenty minutes. Everything happens in the test environment, so no real card and no real money is involved.
Before you start
- Two stores you control, on WooCommerce or Magento 2, both reachable over HTTPS from the public internet. One can be a staging store; both can be on the same server.
- PHP 8.1 or newer on both stores, with the
sodiumextension (WordPress bundles a compatibility layer, Magento needs the extension or the same fallback). - A GatewayChanger account. Create one — the sandbox is free and does not expire.
- Optional: a Stripe account in test mode, if you want the charger shop to use Stripe instead of the built-in test processor. You can do the whole walkthrough without it.
The two shops do not have to belong to the same company for the software to work — but they do have to belong to a legitimate, disclosed arrangement. Read what the card schemes require before you route live traffic.
1. Create your organization
Sign up, verify your email, and you land in your organization's test environment. Every organization has exactly two environments, test and live, and they never mix: a test shop can only route to another test shop, and a test key is refused by a live shop.
2. Register your first two shops
In the dashboard, add a shop for each store:
| Field | What it means |
|---|---|
| Name | Internal label, shown in decisions and the ledger. |
| Legal name | The company name the customer sees in the consent sentence and on the receipt. Get this right. |
| Platform | WooCommerce, Magento 2, Shopify or custom. |
| Base URL | The store's public HTTPS address, without a trailing slash. |
| Roles | Seller, charger, or both. |
Give Shop A the seller role and Shop B the charger role (a shop may have both; it is common for every store in a group to be able to do either). When you enable the charger role you are asked to accept the card-scheme attestation — read it, because it is the part of this product that has real-world consequences.
3. Copy the shop key
Each shop gets its own API key, prefixed shk_test_ in the test environment. It identifies the shop, its organization
and its environment. Copy it now; you will paste it into the plugin in a moment. Keys can be rotated at any time and
the old key keeps working for 24 hours.
4. Install the plugin
- WooCommerce — install, activate, then WooCommerce → Settings → Payments → GatewayChanger.
- Magento 2 — install the module, enable it, then Stores → Configuration → Sales → Payment Methods → GatewayChanger.
- Shopify — offsite app, not yet available; use a redirect-mode charger in the meantime.
5. Connect the shop
Paste the shop key into the plugin's Connection section and press Connect. The plugin:
- generates an Ed25519 key pair and keeps the private key in the store;
- sends its platform, version, base URL, API base, roles, capabilities and public key to
POST /api/v1/shops/self/activate; - receives the environment, our public keys and the consent template.
We then call your store back on GET {api_base}/capabilities to confirm that the shop really is where it says it is
and really holds that key. Until that probe succeeds the shop stays pending_verification and cannot be used as a
charger. The plugin shows the status; press Re-verify after fixing anything.
6. Give the charger a processor
In Shop B's plugin settings, enable the charger role and switch on a processor:
- Test processor — no credentials, deterministic outcomes, the fastest way to get a green checkout.
- Stripe — paste the test-mode publishable key (
pk_test_…), secret key (sk_test_…) and, once you add the webhook, its signing secret. The keys stay in your store; GatewayChanger never sees them.
Save. The plugin sends a heartbeat immediately, and every five minutes after that, telling us which processors and currencies it can handle right now.
7. Write one rule
Rules are an ordered list, evaluated top to bottom; the first match wins. Start with a catch-all:
Rule: "Everything → Shop B"
Conditions: none (matches every order)
Candidates:
1. Shop B · test processor
2. Shop A charges itself · test processor ← fallback
The second candidate matters: it is what happens when Shop B is offline. A rule with no available candidate returns
no_route, and the plugin then hides the payment method or shows an error, depending on how you configured it.
8. Place a test order
Put something in Shop A's cart and check out with the GatewayChanger payment method. You should see:
- the consent checkbox naming Shop B Ltd and the amount;
- a card form that is served by Shop B inside an iframe;
- card
4111 1111 1111 1111, any future expiry, any CVC → captured.
Other numbers give other outcomes — the test cards page lists all of them, including a decline, an insufficient-funds decline, a simulated 3-D Secure challenge and a technical failure that triggers failover.
9. Read what happened
Three places now tell the same story:
- Shop A's order — an order note with the charger, the processor, the reference and the decision id.
- Shop B's mirror order — a new order with one line naming the seller and its order number.
- The GatewayChanger dashboard — the decision with its full trace (which rule matched, which candidates were skipped and why), and the transaction with status, amount, brand, last four and the processor reference.
Next steps
- How routing works — conditions, candidates, caps, strategies and the trace.
- Consent and shop terms — what your checkout and your terms have to say.
- API reference — if you are integrating a platform we do not have a plugin for.
- Then repeat this in the live environment: new keys, verified shops, the attestation, and real processor credentials in the charger.
Troubleshooting
The shop stays "pending verification." Our probe could not reach {base_url}/wp-json/gwc/v1/capabilities (or the
Magento equivalent), or the shop_id and public key it returned did not match. Check that the store is reachable from
the public internet, that no firewall, security plugin or basic-auth prompt blocks the REST API, and that the URL in the
shop record matches the store's real address.
no_route at checkout. No candidate was available. The trace on the decision names the reason for each one:
offline, cap reached, currency unsupported, processor disabled, shop not verified, or the shop excluded by a previous
failover attempt in the same order.
The shop shows as offline. Heartbeats stop when the store's scheduler stops. On WooCommerce that is usually Action Scheduler, on Magento the cron. Fifteen minutes without a heartbeat takes the shop out of routing.
The iframe stays empty. The charger's embed page sets Content-Security-Policy: frame-ancestors <seller origin>.
If the seller's origin in the session does not match the page the customer is on — www versus apex, http versus https —
the browser blocks the frame. Check both stores' configured base URLs.