Connections
Operator page
Developers and owners only. Changing anything here affects every payment and every newsletter. If you are not sure, ask.
Where the Stripe accounts, the Opn Payments accounts, Mailchimp and the newsletter archive are wired up. The screen is an overview. Each payment account has its own page for changes.

The overview
Three cards, top to bottom.
| Card | What it holds |
|---|---|
| Payment accounts | Every Stripe and Opn account, one row each, in the order routing tries them. |
| Payment routing | The diagram of where each card brand goes. See Payment routing. |
| Newsletter | The Mailchimp audience and the newsletter archive. See Newsletter. |
The badges under Payment accounts say whether live writes are armed. Live Stripe writes off and Live Opn writes off are normal.
Each row in Payment accounts shows:
| Column | Meaning |
|---|---|
| Account | The name and region. main marks the main Stripe account. Disabled marks a paused one. |
| Provider · mode | Stripe or Opn, then test or live. read-only means FMS writes nothing there. |
| Status | Whether the keys still work, and when FMS last checked. |
| Takes | The card brands routed to this account. |
| Priority | The routing priority. Lower goes first. |
| Webhook | Ready, Secret not stored or No PUBLIC_BASE_URL. |
Press Manage → or the account's name to open its page.
A short coloured line under the name means the account needs a look.
| Line | What to do |
|---|---|
| Key check failed — open it to see why | Open it. The reason is under Summary. |
| Not connected — open it and paste its keys | Open it and fill in Keys. |
| Disabled — takes no new business | Nothing, unless you meant to enable it. |
| No webhook address (PUBLIC_BASE_URL unset) | Ask the technical team to set PUBLIC_BASE_URL. |
| Webhook secret not stored — Omise events are refused | Open it and paste the webhook secret. |
On a phone each account is a small card with the same facts.
Test keys belong in a sandbox
Test keys can only be connected in a sandbox and live keys only in production. If a warning banner appears saying test keys are connected to production, stop and tell Thomas.
Add an account
Press Add account, top right. Choose Stripe account… or Opn Payments account…. A dialog asks for the basics. After Add account you land on the new account's page. Its keys go in there.
Add a Stripe account
- Press Add account, then Stripe account….
- Type a Name and a Region / label, for example Singapore and SG.
- Under Card types this account can charge, tick the brands to route here.
- With no main account yet, tick This is the main account — there is none yet.
- Press Add account.
- On the account's page, fill in Keys.
Add an Opn Payments account
Opn Payments (Omise) Thailand is a second card provider beside Stripe.
You'll need
- A sign-in to the Omise dashboard,
dashboard.omise.co - For testing: a sandbox. Test keys are refused in production.
- Press Add account, then Opn Payments account….
- Type a Name. Leave Region / label as TH.
- Leave Routing priority at 100, then press Add account.
- In the Omise dashboard, switch to test or live mode, top left. Open Keys.
- On the account's page, copy the secret key (
skey_test_…in test mode) into Secret key. - Copy the public key (
pkey_test_…) into Public key. - Choose the Mode that matches the keys, then press Connect.
- Paste the webhook secret.
The status turns Connected. FMS also tells Omise to send this account's events to the Webhook address on the page. A live account starts Read-only. FMS charges nothing through it until the box is unticked.
The live secret key is shown only once
Omise shows the live secret key for 15 minutes after the first live sign-in. After that it must be rolled. The old key stops working an hour later, so connect the new one straight away.
Open an account
Press Manage → on the account's row. ← Connections takes you back.

Each account is completely separate. A card saved in Thailand cannot be charged in Singapore. That is a Stripe rule, not a choice FMS made. It explains most of the routing behaviour.
The page has a Summary card, then one section per job. Every button reports on its own section. A green line means it worked. A red line says why not.
Summary
The account's facts. Nothing here can be typed into.
| Line | Meaning |
|---|---|
| Provider | Stripe, or Opn Payments (Omise). |
| Mode | test or live, and read-only when FMS writes nothing there. |
| Region | The label typed when the account was added. |
| Main account | Stripe only. The main account goes first among equal priorities. |
| Stripe id | Stripe only. The account's id at Stripe, acct_…. |
| New business | Enabled, or Disabled when it takes no new payments. |
| Membership emails | What FMS emails the members who pay by card here, or None from FMS. Change jumps to Membership emails. |
| Routing priority | Lower goes first. Change it under Routing. |
| Last checked | When FMS last asked Stripe or Omise whether the key works. |
| Takes or Cards | The card brands routed here. |
Re-check asks Stripe or Omise again whether the key works. Disable pauses the account. See Disable, Disconnect or Remove. An Opn account also has Reconcile now.
Open in Stripe, top right, opens that account's own Stripe dashboard in a new tab. It opens in the right mode. It helps when you are signed in to several Stripe accounts. You need to be signed in to Stripe. If the button is missing on a connected account, press Re-check once. It appears as soon as FMS has read the account's id from Stripe. On an Opn account the button is Omise dashboard.
What Omise says it can charge
An Opn account's summary has this box. It lists what the key can charge. Re-check reads it again.
| Line | Meaning |
|---|---|
| Cards | The card brands this account takes. Only these are routed to it. |
| Currencies | What it can charge in. It always settles in THB. |
| One charge | The smallest and largest single payment, in THB. ฿20 is the usual minimum. |
| 3-D Secure | Dynamic. The first payment from the card form asks the member's bank to confirm. Renewals are not challenged. |
USD works on Visa and Mastercard only
Plans are priced in USD. Omise charges USD only to Visa and Mastercard. JCB, American Express and UnionPay pay in THB at the account's exchange rate. See Local-currency pricing.
Brands and currencies come from Omise. Press Re-check after Omise changes them.
How 3-D Secure works on Opn
Omise told us on 14 October 2026 how our account works. A payment sent with a return address asks the bank to confirm. A payment sent without one does not.
| Payment | Bank check |
|---|---|
| First payment, from the card form | Yes. The member confirms with their bank. |
| Renewal | No. It goes through without the member. |
A live account works this way only after Omise's risk team approves it. A payment without the bank check is our loss if the member disputes it with their bank.
If Omise ever asks for a bank check on a renewal, the member sees Confirm payment on their account page. Staff get an email saying Omise changed something. Ask Omise support what changed.
Keys
The secret key and the publishable key (Stripe) or public key (Opn).
- Paste the secret key into Secret key.
- Paste the other key into Publishable key or Public key.
- Choose the Mode that matches the keys: test (sandbox) or live.
- Tick or untick Read-only (verification) mode.
- Press Connect. On a connected account the button says Update.
FMS checks the key with Stripe or Omise before it stores anything. The key is then stored encrypted. The field shows stored — paste to replace and never shows the key again.
Paste the secret key again for every change
FMS checks the key on every save. Even a change to Mode or the read-only box needs the secret key pasted again. Without it, the section says so and nothing is saved.
Read-only (verification) mode stops every write FMS would make on this account. Imports and checks keep working. Choosing live ticks it for you. Untick it on purpose when FMS should charge there.
Webhook
Stripe and Omise tell FMS what happened through the account's webhook. The address is in the section, with Copy beside it.
Stripe. FMS creates the endpoint in the Stripe account when you connect the key. Signing secret: stored. means it worked. If that failed, or the endpoint was deleted in Stripe, press Create webhook endpoint. When one already exists the button says Recreate webhook endpoint. It asks first, then Recreate endpoint replaces the stored signing secret. On a read-only account FMS creates nothing.
Creating or recreating the endpoint moves no money, so it works on a live account while the badge says Live Stripe writes off. Nobody needs to arm live writes for it.
Under the signing secret, API version says which version of Stripe's API the account uses by default (checked every few minutes) and which one FMS sends. They should match. When FMS pins a version, a new endpoint gets it too, so an upgrade in the Stripe dashboard changes nothing for FMS. Not pinned means whoever runs the server should set STRIPE_API_VERSION to the version shown.
Opn. FMS refuses Omise's webhooks until it holds the secret that signs them. The API never gives it out.
- In the Omise dashboard, open Webhooks in the same mode.
- Copy the webhook secret. It is a long line of letters ending in
=. - Paste it into Webhook secret on the account's page and press Save.
The line under the field changes to Secret: stored. Test and live mode have different secrets. Clear removes it, after you confirm with Remove secret.
If the address under Webhooks in the Omise dashboard is not the Webhook address on the page, press Set webhook URL on Omise. Omise keeps one address per mode.
Omise never sends a webhook twice
A webhook FMS misses is not sent again. FMS reads Omise's events every 15 minutes instead, so Reconcile now and the automatic check must stay on.
Each environment has its own webhook address. In a sandbox the address ends ?env= and the sandbox's name. Production's has no ending.
| In | Create webhook endpoint |
|---|---|
| Production | Replaces production's endpoint |
| A sandbox | Replaces only that sandbox's endpoint. Production's is never touched |
A sandbox made before 24 October has no endpoint of its own yet. Press Create webhook endpoint once in it. Until then Consolidation lists the account as missing its webhook.
One address per Omise account
An Omise account sends its events to one address only. A copy of production shares production's Omise account, so FMS refuses to point it at the sandbox. Connect a separate Opn test account to the sandbox instead. Consolidation says when an Omise account points at another environment.
Routing
Each account has a Routing priority. Lower goes first. Every account starts at 100. Among equals the main account goes first. Type a number and press Save. The Payment routing diagram changes at once.
Make Opn the first choice
The Routing priority decides who is tried first for a card both can take. Stripe accounts are 100.
| Opn priority | What happens |
|---|---|
| 100 | Stripe first. Opn takes only the cards Stripe cannot. Use this to test. |
| 10 | Opn first for every card it takes. Stripe takes the rest. Check that the account has an exchange rate first: without one, a JCB, American Express or UnionPay card goes to the next account that takes the brand; if none does, the card is refused. |
Local-currency pricing
Plans are priced in USD. On an Opn account, JCB, American Express and UnionPay cards pay in THB. FMS works out the THB price from the USD price, this account's exchange rate and its rounding. The section is on the Opn account's page, under Routing. Developers and owners only.
Members see the THB price before they press Pay on the checkout, gift and donate pages. The rate and the USD list price sit beside it. They are charged only that amount. If the rate moved after the page was opened, FMS catches it and shows the new price. See Pricing and joining.
| Line | Meaning |
|---|---|
| Rate | THB per US dollar, for example ฿34.32 per $1 · from Omise · updated 15 Oct 04:10. |
| Rate source | From Omise (daily): FMS asks Omise once a day. Typed by hand: the number you type, never refreshed. |
| Rounding | THB prices are rounded to the nearest ฿1, ฿10, ฿50 or ฿100. ฿10 to start with. |
| Conversion-fee allowance | Lowers every THB price on this account by a percentage, 0 to 10 %. Off to start with. |
| What a JCB card pays | The cheapest and dearest plans, worked out with the settings above. |
Example: Friend at $120 and a rate of 34.32 is ฿4,118.40, so ฿4,120 to the nearest ฿10.
- Press Refresh now to ask Omise for today's rate.
- To type a rate instead, choose Typed by hand, type the number of baht per dollar, and press Save rate.
- Choose the Rounding. It saves straight away.
If Omise's rate jumps
A new rate more than 5 % away from the current one is not used on its own. The section shows both numbers and Accept new rate. Until you press it, JCB, American Express and UnionPay cannot pay on this account, and their renewals wait. Health shows the account under fx_rate.
The conversion-fee allowance applies to every card in THB
Some members' banks add a fee when they pay in baht. The allowance lowers the price to make up for it. FMS cannot tell before the price is shown whether a card was issued in Thailand: the issuing country is known only after the card is entered. So with the allowance on, every THB charge on this account is lower, cards issued in Thailand included. FMS asks you to confirm before it turns on or changes.
What members pay. Visa and Mastercard pay the USD price. Every other card pays the THB price. Renewals are worked out again each time at the rate of the day, so a member's THB amount can move a little from one period to the next. A Visa or Mastercard renewal stays in USD.
When there is no rate
Omise's rate needs multi-currency switched on for the account. If Refresh now says it failed, type a rate. A rate from Omise older than 72 hours is not used. In both cases only Visa and Mastercard can pay here, and a renewal that needs THB waits for a rate. It is never sent to dunning for this, and its date does not move.
Import existing subscriptions
Brings a Stripe account's live subscriptions into FMS. Used at the cutover, and again whenever a subscription was created in the Stripe dashboard by hand. It only reads from Stripe. The section is on each connected Stripe account's page.

Nothing starts by itself. The section shows the Latest import, or None yet.
- Press Preview import.
- Wait for Preview ready. Nothing has been written yet.
- Under Prices found, pick a plan for each unmapped price and press Map.
- Press Import N subscription(s). It stays grey until every price is mapped.
The job keeps going if you leave the page or close the tab. Come back to the page to see progress. Re-preview counts again with the latest settings.
| Badge | Meaning |
|---|---|
| Preview ready | Counts only. Press Import N subscription(s) to apply. |
| Imported | Done. The counts are what changed. |
| Paused | Stripe or FMS interrupted it. Read the reason, press Resume from page N. It continues from the last finished page. |
| Stalled | No progress for five minutes. Press Resume. |
| Canceled | Someone pressed Cancel import. |
| Failed | It stopped. The red line says why. |
What the counts mean
Past due, in grace counts members whose card was failing in Stripe on the day. They keep access while Stripe retries their card, and Stripe's outcome settles them. Held by FMS rows are already under FMS control and are left as they are. Row errors lists any subscription that could not be imported. The rest still import.
Only a signup adds someone to Mailchimp
The Backfill Mailchimp tags box updates contacts already in the audience. It never adds a contact. See Consolidation.
Membership emails
Which emails FMS sends the members who pay by card on this account. These switches alone decide for them. The ones on Settings → Email are for free access, bank transfer, gifts and team seats.
| Stripe account | Opn account | |
|---|---|---|
| Welcome | Switch here | Switch here |
| Your membership is cancelled | Switch here | Switch here |
| Payment received | Stripe's own | Switch here |
| Your membership renews soon | Stripe's own | Switch here, with Days before the renewal |
| We couldn't charge your card | Stripe's own | Switch here |
- Open the account's page. From Settings → Email, press Manage on its row.
- Scroll to Membership emails.
- Tick each email members on this account should get.
- Opn only: type Days before the renewal, from 1 to 30.
- Press Preview on a row to see the email.
- Press Save changes. A green line means it is saved.
On or Off beside each email is what is saved now. A switch applies from the next email. Nobody is emailed about the past.
Omise sends no emails
Opn (Omise) never emails your members. Without these switches an Opn member gets no receipt, no renewal reminder and no word when their card fails. Switch on Payment received, Your membership renews soon and We couldn't charge your card before Opn takes real members.
On a Stripe account, receipts, renewal reminders and failed payments are Stripe's. Press Stripe email settings to open them in the Stripe Dashboard, under Settings → Emails. FMS refuses to send them for a Stripe account.
Members can get two emails
A member with two memberships, such as a card plan and a team seat, follows both rules. They can get an email from each. Check what the Stripe Dashboard sends before you switch on Welcome or Cancelled here, so members are not told the same thing twice.
A disabled account still emails the members already on it. A newly added account starts with every email off.
In a sandbox
The section shows an amber note in a sandbox. There the emails go to every address in that environment's database, through the same relay as production. A sandbox copied from production starts with every account's emails off.
Disable, Disconnect or Remove
Three ways to stop using an account. Disable is under Summary. Disconnect and Remove are in the Danger zone at the bottom. Each one asks first and lists what follows.
| Disable | Disconnect | Remove | |
|---|---|---|---|
| What it does | Stops new business | Forgets the keys | Deletes the account from FMS |
| New memberships, donations, gifts | Never routed here | Opn: not routed. Stripe: still routed, and they fail. | Gone |
| Members already on it | Keep renewing here | Opn: renewals stop. Stripe: Stripe keeps charging, FMS cannot reach them. | Refused while anyone uses it |
| Webhooks | Keep working | Keep arriving. The secret stays. | Gone |
| Undo | Press Enable | Paste the keys again | Add the account again |
None of the three changes anything in the Stripe or Omise dashboard.
To disable an account:
- Open the account's page.
- Press Disable under Summary.
- Read the dialog, then press Disable connection.
New business turns Disabled. In Payment routing the account turns grey. Each card brand now goes to the next account that takes it. To undo it, press Enable, then Enable connection.
Disabled in more detail:
| Disabled | |
|---|---|
| New memberships, donations, gifts | Never routed here |
| A rescue after a failed renewal | Never moved here |
| A new team invoice or member invoice | Refused, if this is the issuing account |
| Members already on it | Keep renewing here as before |
| Webhooks, cancels, refunds, billing portal | Keep working |
| Health checks and Re-check | Keep working |
| Membership emails | Still sent to the members on it |
One must stay on
FMS refuses to disable the last account that is both enabled and connected. An account without a key does not count. Enable or connect another account first.
A disconnected Stripe account still gets cards
After Disconnect, a Stripe account keeps its ticked card brands. Routing still sends those cards to it, and the payments fail until a key is back. Press Disable as well if cards should go elsewhere.
Cannot be undone
Remove deletes the account and its stored keys from FMS. It is refused while any membership, plan price or charge still uses it. To use the account again, add it and paste its keys again.
The main account
Disabling the main account does not change which account is main. Free and comp memberships still list it as their home. No money moves for those.
Reconcile now
Opn accounts only. FMS asks Omise every few minutes for events the webhook did not deliver. It also looks for charges whose answer was lost. Reconcile now, under Summary, does that at once for this account. The green line says how many events it read. It also says how many the webhook had missed, and any lost charges it found.
Payment routing
A diagram of where each card goes. It changes as soon as you connect a key, tick a brand, change a priority or disable an account.

Each column is one account. Columns run left to right in the order FMS tries them. The card on top shows the account's provider, region, mode, routing priority, active members and the card brands it takes.
Each row is one card brand. Read it from left to right.
| In a cell | Meaning |
|---|---|
| 1 in yellow | The card goes to this account first. |
| 2, 3 | Where the card goes next if the account before cannot take it. |
| — | This account does not take the brand. The card skips it. |
| needs a rate | The Opn account has no exchange rate it can use, so it cannot price this card in THB. The next step takes it until a rate is set on the account's page. |
| Not routable | No enabled account takes this brand. Checkout refuses these cards. |
A greyed-out column marked Disabled is an account you disabled. It has no place in the order and takes no card.
Where the order comes from
An account only appears in a row if it takes that brand. Among those, the lowest routing priority goes first. Among equal priorities the main account goes first, then the others by region. Step 2 is used only when step 1 cannot take the card at all, never because a card was declined.
Opn takes USD on Visa and Mastercard only
Any other brand pays in THB at the account's exchange rate. Without a rate it can use, that card skips the Opn account.
Newsletter
Two rows: Mailchimp audience and Newsletter archive. Each shows a status badge and one line saying what is set up. Press Manage to open the settings in place. Close folds them away. A row that is not set up yet opens by itself.

Mailchimp audience
- Press Manage on the Mailchimp audience row.
- Paste the API key and the Audience (list) ID.
- Press Connect. On a connected audience the button says Update.
Re-check asks Mailchimp again whether the key works. Disconnect asks first, then forgets the key and the audience. Nothing in the Mailchimp audience is changed.
A sandbox may only write to an audience connected inside that sandbox. It will never write to the live audience, even if a key was inherited from a copy of production.
On the live console the row shows a badge. Mailchimp fixes off for the live audience is the normal state: Consolidation's tag fixes refuse the real audience. For the cutover clean-up, the server is restarted with them armed and the badge turns red. Ordinary membership changes always update tags, whatever the badge says.
Empty audience… exists for practice audiences and is refused in production. It lists every contact first. Archive all N contacts then archives them all. Check the list: real members there mean the wrong audience is connected.
Newsletter archive
Tells FMS where the newsletter archive lives, so it can watch it on Health.
- Press Manage on the Newsletter archive row.
- Type the archive's address in Archive address, for example
https://archive.frontiermyanmar.net. - Press Test. The message says how many issues it holds and when it last synced.
- Press Save.
FMS then checks the archive every minute. The row shows the last check, how many issues it holds, its last sync and how many issues fail to fetch.
| Badge | Meaning |
|---|---|
| Healthy | The archive answers and synced within two days. |
| Needs attention | It answers but is stale. The line under the address says why. |
| Unreachable | FMS could not reach it twice in a row. Staff get an alert email. |
| Switched off | Saved, but not checked. Untick Watch it on Health to get here. |
| Not watched | No address saved yet. |
Remove asks first. Stop watching then forgets the address and closes any open archive alert. The archive itself keeps running.
Why Save can refuse
With Watch it on Health ticked, Save first checks that the address answers like the archive. A mistyped address is refused with the reason. To keep an address the archive can't answer from yet, untick the box and save.
When something says "not verified"
Open the account and press Re-check under Summary. For Mailchimp, press Re-check in its row. If it still fails, the key has probably been rotated in Stripe, Omise or Mailchimp. Paste it in again under Keys.