Getting set up

International Payments — accept foreign cards through a cross-border acquirer

Nigerian card acquirers (Paystack, Flutterwave, Moniepoint) approve foreign cards at very low rates — usually 40-60% of legitimate attempts get declined by the issuer as "cross-border risk". For a Lagos luxury hotel with a large share of overseas guests, that translates into real, lost revenue every week.

A cross-border acquirer (dLocal or Rapyd) sits between your business and the international card networks, presenting the transaction to the guest's issuer with a global merchant footprint. Approval rates jump to what a London or New York hotel would see — typically 90%+ — because the issuer no longer sees a "risky Nigerian merchant".

Both providers use the same Payment Facilitator model: BusinessSensor holds one platform account with the acquirer; each hotel is registered as a sub-merchant under it with their own KYC record and payout bank. Money settles directly to your bank — it never touches BusinessSensor's books.

When to pick which:

  • Rapyd — self-serve sandbox signup (5 minutes on dashboard.rapyd.net). Production requires KYB submission (~30 days). Good for getting started fast.
  • dLocal — sales-led onboarding (4-8 weeks to production contract) but a more polished hosted KYC page and slightly better emerging-market pricing. Good for full production launch.
  • Recommended: start with Rapyd for sandbox testing and early pilot; add dLocal once their contract lands. Our system supports both simultaneously.

You keep 100% of your Naira rate. The foreign guest pays a small International Processing Fee (defaults to 4%) added on top of their bill — shown to them at checkout so there are no surprises.

Before you start

  • You must have Account Master permission.
  • You must be a company administrator — this page binds your business commercially to the acquirer, and the sub-merchant contract carries KYC obligations. Regular staff should not perform this step.
  • Have these ready:
    • Your legal business name exactly as it appears on your CAC certificate.
    • Your trading name (if you operate under a hotel brand different from the legal name).
    • Contact email — the acquirer will send KYC document requests here.
    • Business address and phone number.
    • Optional but recommended: your public website.
  • Later in the KYC flow, the acquirer will ask for scans of: CAC certificate, director's ID, proof of business address, and (for hotels) your hospitality licence. Have these handy — you can start onboarding without them, but you can't collect real money until KYC clears.
  • Your system administrator must have configured the acquirer's platform credentials on this deployment. If they haven't, this page shows a yellow banner and you can't proceed — send it to your IT team.

Steps

  1. Go to Setup → International Payments.
  2. Pick the acquirer you want to use. Today the list is dLocal only — a global cross-border specialist we've integrated. Others (Rapyd, Flutterwave International) may appear later.
  3. Fill in the Legal business name, Contact email, and country / currency (defaults: Nigeria / NGN — leave as-is unless you're onboarding a non-Nigerian tenant).
  4. Add any optional fields you have on hand (trading name, phone, address, website). The more you fill in now, the fewer follow-up emails the acquirer sends you.
  5. Click Register with dLocal. This creates your sub-merchant account with the acquirer and returns a hosted KYC link.
  6. Click Continue KYC on dLocal to open the acquirer's hosted onboarding page in a new tab. Upload your documents there. You can pause and resume from that page at any time using the same link.
  7. Come back to this page and click Refresh status whenever you want to see the acquirer's decision. dLocal typically approves in 2–5 business days.
  8. Once the badge turns green (Approved), the international-payment rails are live. Guests presenting foreign cards will automatically be routed to dLocal instead of your local acquirer, and will see the international-processing fee added to their bill.

Tips

  • The KYC link stays valid for the entire onboarding process — bookmark it if your accountant is uploading documents on their own laptop.
  • You can leave Trading name blank if it's the same as your legal name.
  • If your business operates in multiple countries, register a separate sub-merchant per country — the acquirer treats each as its own KYC file.
  • If you don't yet want to charge guests the international fee (marketing period, VIP promo), talk to your account manager — the surcharge percentage can be lowered (down to 3%) or waived entirely, but the default is 4%.

Sandbox platform-wallet fallback (Rapyd only, sandbox only)

Rapyd's self-serve sandbox accounts sometimes ship WITHOUT the Onboarding / Wallet Creation module enabled. If that's the case, when you click Register with Rapyd, Rapyd's API returns a ROUTE_PERMISSION_ERROR on POST /v1/user.

To keep the demo unblocked, the system automatically detects that specific error and creates a synthetic sub-merchant row with:

  • SubMerchantId = SANDBOX-PLATFORM-WALLET (a marker, not a real Rapyd wallet)
  • KYC = Approved (synthetic — no actual KYC took place)
  • KYC message = "SANDBOX FALLBACK — no real sub-merchant wallet exists. Charges route to the platform wallet."

What this means for charges:

  • Charges still hit real Rapyd sandbox — real HTTP traffic, real hosted checkout page, real webhook lifecycle
  • The only difference: settlement lands on YOUR platform wallet, not a per-tenant sub-merchant
  • Refunds work normally
  • The surcharge still applies (defaults to 4%)

This fallback is safe:

  • It ONLY fires in sandbox mode (sandboxapi.rapyd.net). Production URL never triggers it.
  • The SANDBOX-PLATFORM-WALLET marker is checked before every charge — production code paths reject it.

To move to real PayFac testing, email Rapyd support:

Hi, my sandbox access key is rak_XXX. I get ROUTE_PERMISSION_ERROR on POST /v1/user. Please enable the Onboarding / Wallet Creation module on my sandbox so I can create real sub-merchant wallets.

Turnaround is 1-2 business days. Once enabled, delete the synthetic row (DELETE FROM ProviderSubMerchantAccount WHERE SubMerchantId = 'SANDBOX-PLATFORM-WALLET') and re-run onboarding — this time Rapyd will accept it and issue a real wallet_id.

Currency the guest is charged in (FX display)

Foreign guests don't think in Naira — they think in their card's home currency. The checkout preview supports charging the guest in one currency while your books settle in Naira.

How it works at checkout:

  1. Cashier picks a Rapyd or dLocal payment method.
  2. The International Card — Guest Preview card appears with a currency dropdown — the cashier (or the guest) picks the currency the guest wants to see (USD by default, EUR/GBP/JPY/etc. also available).
  3. The preview shows:
    • Invoice — the base amount in your Naira books.
    • Fee — the international-processing surcharge.
    • Guest pays — the total in the guest's chosen currency (e.g. $156.00 USD), with the Naira equivalent below it as a reference.
  4. Below the totals, a small caption shows the exchange rate used AND the source: green Rapyd live rate means the acquirer gave us a real quote; amber Fallback rate + 2% margin means we used our own interbank feed plus a conservative markup.
  5. Cashier clicks Charge via Rapyd — the guest's card is debited in the currency shown; your Naira wallet receives the settled amount.

When the exchange rate is a "Fallback rate":

  • The acquirer we routed through doesn't expose a live FX endpoint (dLocal today) OR the acquirer's API was temporarily unreachable.
  • We use the shared BusinessSensor rate feed (Fixer.io interbank) with a 2% conservative margin. This margin makes sure the amount we quote the guest is unlikely to under-shoot the actual settle amount.
  • The guest's card is still debited in their chosen currency — the acquirer applies its OWN rate at settlement. Small drift (~1-2%) between what we displayed and what the guest is billed is possible.
  • If this drift matters, prefer Rapyd — its /v1/fx_rates endpoint gives us a real live quote that matches the settle rate.

Sessions remember the last-picked currency: switch tabs or reopen POS and the guest currency stays as USD (or whatever was last chosen). This clears on browser close.

Adjusting the international processing fee

Once your sub-merchant is Approved, the page shows the current international-processing surcharge (default 4%) and a slider that lets you adjust it within a hard-coded 3-5% band.

  • Default 4% is the recommended value — it covers the acquirer's per-transaction take and leaves you keeping essentially 100% of your listed rate in Naira.
  • Below 3% you would be subsidising the acquirer's cut from your own margin on every transaction; the platform doesn't allow this.
  • Above 5% starts feeling predatory to guests. The "small international-processing fee" framing on the checkout page stops being true and you'll see complaints.

Move the slider, click Save. Every subsequent foreign-card payment through this rail computes the fee at the new rate. Existing pending payments are unaffected (they were locked at the rate active when the guest opened the payment page).

Nigerian cards on the international rail

If a Nigerian-issued card (Verve, GTBank Visa, First Bank Mastercard, etc.) somehow ends up on the international rail, our system rejects it BEFORE calling the acquirer. That's on purpose:

  • The acquirer would present the transaction as international to a Nigerian issuer, which almost always declines it as "cross-border risk".
  • You would still pay the acquirer's per-attempt fee.
  • The guest would think the fee was for a transaction that failed.

We use the card's BIN (the first 6 digits of the number) to detect Nigerian issuers. If the guest wants to use a domestic card, direct them back to your regular payment methods (Paystack, Moniepoint, cash, etc.).

What guests see at checkout

Once your dLocal sub-merchant is Approved, every payment surface that lets a cashier pick "Charge via dLocal" will show a preview line before the Charge button:

  • POS Checkout — under each tender row, a single-line "Guest charged ₦156,000 (+ ₦6,000 intl. fee)" caption.
  • Folio → Add Payment — a small card explaining "Invoice + Fee = Guest pays", with the KYC status pinned so cashiers know why Charge is disabled if the sub-merchant is Pending.
  • Check-in Wizard — Step 4 (Receipt) shows the same card in the deposit box.
  • Advance Booking — same card next to the "Amount to Deposit" field.

The card refuses to render for non-cross-border methods (Paystack, Moniepoint, cash), so it's silent when it isn't needed. The card also blocks the Charge button with an inline warning when the sub-merchant KYC isn't yet Approved — no way for a cashier to accidentally kick off a doomed authorisation.

Sandbox smoke test — before going live

Before switching this rail on for real customers, run the sandbox smoke test as a company administrator:

  1. In a browser, hit https://<your-tenant>.suitehub.app/api/international-payments/smoke-test/dlocal (replace the domain with your tenant's).
  2. The response is a JSON document listing 5 checks and their pass/fail status:
    • Platform credentials populated
    • HMAC signing works deterministically
    • Sub-merchant row exists + is Approved
    • Round-trip against dLocal's sandbox succeeds
    • Webhook secret is configured

If all 5 pass, you're clear to enable dLocal on live payment methods. The test refuses to run if the deployment is pointed at production dLocal — you can only smoke against sandbox from this endpoint, by design.

Reconciling at month-end

Once you're processing real foreign-card payments, use Reports → International Payments Reconciliation at month-end to cross-check our books against dLocal's Merchant Dashboard settlement report. See that manual for the full workflow.

Common problems

  • "Not configured" banner on the provider card → your deployment doesn't have the acquirer's platform credentials set. This is an IT / DevOps step (KV secret injection), not something you can fix from this page. Contact your system administrator.
  • KYC stays "Pending" for over 5 business days → the acquirer is usually waiting on a document. Open the KYC link again; you'll see red text explaining what's missing (blurry director's ID, wrong CAC file, etc.).
  • KYC status: Rejected → the acquirer has declined onboarding. The reason appears in the status message on this page. Common causes: mismatched business name (the legal name you typed here doesn't match the CAC scan), sanctions-list hit, wrong document class. Fix the underlying issue, then contact the acquirer's support to reopen the file — you can't just re-submit from our side.
  • KYC status: Suspended → the acquirer has paused your account after go-live. This is usually a chargeback-rate or compliance issue. Reach out to the acquirer's account manager directly; when they lift the suspension, click Refresh status to reactivate the rails.
  • Foreign guest's card was still declined even though status is Approved → the transaction may have hit an issuer-specific rule (velocity, geo mismatch). Try the same card again on a different rail (Paystack) as a fallback, and note the pattern — after a few similar declines, share them with your dLocal account manager so they can tune your merchant profile.
  • I want to change the acquirer later → you can register with a new provider at any time. Existing sub-merchant registrations aren't automatically closed. Contact the old acquirer's support to formally close the old sub-merchant if you no longer want it billed.

See it working on your own business

Start a 45-day free trial — no card needed — and follow this guide in your own practice company.