Skip to content

FSD-11, Interop (send and receive to another operator's or bank's wallet)

1. Purpose and scope

Interop lets a customer send money from the wallet to a beneficiary held at another operator or bank, and receive money pushed in from another institution, across the national interoperability switch. The customer can pay anyone on another Mauritanian wallet (BCI Pay, Bankily, SEDAD, Masrifi, and the other member institutions) the same way they pay inside the wallet.

The switch dialog (the routing between institutions, the secure messaging, the multi-phase settlement) is already implemented by the BMCI interop service. That service is live and talks to the switch today. Comviva does not build, host, or know any of that. Comviva plugs the existing BMCI interop service into the Mobiquity platform so the customer can use interop (send and receive) via Mobiquity. In other words, the heavy integration with the switch is done. The work here is to wire one Mobiquity money service to the BMCI interop endpoint, debit the wallet on send, credit it on receive, and tell the customer.

This rail carries three customer shapes, all served by the same BMCI service.

  1. Send to another wallet or bank. The customer sends from the wallet to a beneficiary at another institution. Money leaves the wallet.
  2. Receive from another wallet or bank. Another institution sends to the customer's wallet. Money enters the wallet, and nothing was selected in advance.
  3. Agent cash-in. An agent at the counter funds a wallet from cash, settled across the switch.

Two related flows will be provided soon and are left out of this version: the merchant payment flow (QR code, where the beneficiary is a merchant rather than a customer, otherwise almost the same as a wallet-to-wallet send), and the agent cash-out flows (cash-out on us and cash-out on partner).

Customer journey

Interop is three sub-flows seen from three points of view. The send flow is the only one the customer drives screen by screen. The receive flow surfaces only as a credit notification. The agent flow runs at the counter.

Send money to another wallet or bank. Ideally a single screen takes the destination number, the amount, and the destination wallet together, since the institution list should be cached and the cache refreshed only once every 10 minutes for performance.

  1. On the wallet home the customer opens a menu named Gimtel, where the interop services reside, and selects Transfer.
  2. The customer picks the destination institution from the member-institution directory (the live list of banks and wallets reachable on the switch, fetched once and cached), enters the beneficiary mobile number, and enters the amount, on one screen where possible.
  3. The customer continues. Behind the screen a pre-authorization request is sent to the switch. The switch resolves the beneficiary and returns the resolved beneficiary name and the unique switch reference (the reconciliation key carried through the rest of the flow), and the charge (a tax that combines the transfer duty and the interchange commission) is computed and added to the amount.
  4. A confirmation screen shows the beneficiary name, the destination institution, the amount, the charge, and the total to be debited (amount plus charge), so the customer sees exactly what will leave the wallet and confirms they are paying the right person before any money moves.
  5. The customer enters the PIN. The wallet is debited for the total (amount plus charge), the funds land in a transit account, and on confirmation the beneficiary is credited at the destination institution while the charge is split to the tax and commission accounts.
  6. The receipt screen shows the unique switch reference (prominent, the reference the customer quotes for support and reconciliation), the date and time, the beneficiary, the destination institution, and the amount with the charge and the total debited (see Transaction detail and receipt). Once the wallet is debited the screen shows the transaction as successful, no pending state is shown to the customer. If the transfer succeeds, the split is posted through the posting API: the transit account is debited and the pool account credited, then the fee account is debited and the GIMTEL commission credited. If it fails, the posting API returns the money to the customer along with the fee, the full debited total.

A scheduled reconciliation checks the status of any transfer left in doubt after the confirmation (a timeout downstream) and either completes it once or, if the debit advice never took on the switch, refunds the customer the full debited total. This is covered in section 3 (the refund branch).

Receive money from another wallet or bank. The customer does nothing in advance. The sending institution drives the transfer on its side. When it completes, the customer's wallet is credited and the customer is told their wallet was credited (push if enabled, otherwise SMS). The receipt is the credit entry on the wallet statement. From the customer's view this is exactly the same as receiving any external credit.

Behind the screen, when a pre-authorization arrives from the other institution, the BMCI service first validates the destination before accepting. It looks up the customer by the destination mobile number, which returns not found if the customer does not exist, and reads the profile, the status, and the account number. BMCI deduces from the profile and the status whether the customer can receive. This needs a Comviva endpoint that returns the customer's profile, status, account number, and name from a phone number. If the customer exists and can receive, the pre-authorization is validated. The credit advice then follows, which means the customer must be credited: the pool account is debited and the beneficiary account is credited through the posting endpoint. The counterparty funds its own side, so there is no compensation or balancing movement on the wallet side, the same money-in template as VISA Direct and the partner-bank inbound credit.

Agent cash-in. At the counter the agent selects cash-in, selects the institution, enters the customer wallet number and the amount, and confirms. The customer wallet is credited (the agent took the cash). The agent who initiated also earns a commission, credited to the agent's commission account as part of the settlement. The customer gets the same credit notification as any wallet movement, and the agent gets the counter receipt.

Behind the screen, for a cash-in on us (another institution depositing through a BMCI agent), once the pre-authorization returns success the agent account is debited and a transit account credited. The credit advice is then sent, and on its success the posting API that Comviva must provide settles the split: debit the transit account and credit the pool account, then debit the pool account and credit the GIMTEL account, then debit the pool account and credit the tax account.

For a cash-in on partner (our customer depositing through another institution's agent), the flow is the inbound shape, the same as a wallet-to-wallet credit coming in. We receive a pre-authorization and verify the customer with the client-details lookup, and once we validate it the credit advice arrives, on which the posting API debits the pool account and credits the customer account.

Agent cash-out. The cash-out flows, cash-out on us and cash-out on partner, will be provided soon and are left out of this version.

2. API contract

2.1 The clean contract, Comviva's side

In reality Comviva's side is minimal. Comviva reads the institution list for the picker (getInstitutionList), makes two calls to the BMCI interop endpoint (the request that starts the send, then the customer-paid call once the wallet is debited), and exposes two endpoints BMCI calls: a customer-details lookup (getCustomerDetails, used to check a customer on an inbound transfer) and one complete posting endpoint. BMCI handles the switch dialog and all the orchestration, and drives every money move through Comviva's posting endpoint. The posting endpoint is the core primitive Comviva must provide.

Endpoint What it does Direction Purpose
getInstitutionList List the member institutions a customer can send to, cached Comviva reads from BMCI the destination picker on the send flow
The request Start the send. The BMCI endpoint resolves the beneficiary, pre-authorises across the switch, and returns the beneficiary name and the charge Comviva calls BMCI fills the confirmation screen
The customer-paid call Signal that the customer confirmed and the wallet was debited Comviva calls BMCI commits the transfer across the switch
getCustomerDetails Return the customer's profile, status, account number, and name from a phone number (not found if the customer does not exist), so BMCI can decide whether to accept an inbound transfer Comviva exposes, BMCI calls validates the inbound pre-auth
The posting endpoint A complete posting endpoint. BMCI drives every money move through it: the debit to transit, the split on confirmation, the inbound receive credit, the refund on failure, and the posting status-query (fetch by id, or search by externalReference which returns all transactions with that reference, date filter optional) Comviva exposes, BMCI drives all the wallet money movement and its reconciliation

2.2 Request and response fields

The fields depend on the case, sending, receiving, or posting.

The references used across the flow. The mhostReference is the sender (host) reference, a unique reference. On a send Masrvi is the host, so it is ours. The switchReference (mswitchReference) is the GIMTEL switch reference. The transactionId (masrviTransactionId) is the Masrvi transaction reference. Each debit or credit posting leg carries its own unique id. The posting externalReference is set to the switchReference, which ties the ledger, the receipt, and the reconciliation to one value.

Sending. What Comviva supplies on the request call and gets back.

Field Mandatory Notes
sourceMsisdn yes the sender wallet MSISDN
destinationInstitution yes the member-institution reference picked from the directory
beneficiaryMsisdn yes the beneficiary mobile number at the destination institution
amount yes numeric, in 929
currency yes 929
mhostReference yes the sender (host) reference, a unique reference for the send. On a send Masrvi is the host
beneficiaryName returned the resolved beneficiary name, shown for confirmation
charge returned the tax plus commission added to the amount, shown before confirm
switchReference returned the unique switch reference (unique across all institutions), carried as the posting external reference, searched by the status-check job, and shown on the receipt
status returned success or failed. No clear answer from the switch is treated as failed, never pending
transactionId on the customer-paid call the Masrvi transaction reference (masrviTransactionId) of the wallet debit, sent once the customer has paid

Receiving. What BMCI sends and gets back on the getCustomerDetails lookup it calls to check a customer before crediting. The lookup returns not found if the customer does not exist. BMCI deduces from the profile and the status whether the customer can receive (a restricted profile or a blocked status may not). The credit itself is a posting (see Posting).

Field Mandatory Notes
msisdn yes (request) the customer mobile number to look up
profile returned the customer profile, BMCI deduces from it whether the customer can receive
status returned the account status, BMCI deduces from it whether the customer can receive
accountNumber returned the customer account number
customerName returned the customer name

Posting. The posting endpoint payload, used for the send split, the inbound credit, and the refund.

Field Mandatory Notes
accounting[] yes the legs, each with srcAccount, dstAccount, type (TRANSFER, FEE), and amount (value in minor units, currency, display)
operation yes the operation code, for example TRANSFERT_INTEROP_FROM_BMCI
externalId yes the switch reference, the reconciliation key
mode yes TRANSACTION to commit, PREAUTH to reserve
externalData optional extra data
ignoreStatus optional bypass the status check
id returned the posting id, fetchable directly or by externalReference with an optional date filter

2.3 Sample payloads

The send request a wallet platform posts.

{
  "sourceMsisdn": "+222 69 85 51 11",
  "destinationInstitution": "BANKILY",
  "beneficiaryMsisdn": "+222 60 00 00 00",
  "amount": 1500.00,
  "currency": "929",
  "mhostReference": "MHOST-INT-0001"
}

The send response, with the resolved beneficiary name for the confirmation screen.

{
  "beneficiaryName": "MOHAMED EL HASSEN",
  "transactionId": "TX-2026-0001",
  "switchReference": "SW-2026-0001-A7",
  "status": "success",
  "mhostReference": "MHOST-INT-0001"
}

A failed pre-authorization. The pre-authorization returns success or failed, never pending. No clear answer from the switch is treated as failed.

{ "status": "failed", "message": "Beneficiary not found" }
{ "status": "failed", "message": "No clear answer from the switch" }

The inbound credit the BMCI service signals for a receive.

{
  "beneficiaryMsisdn": "+222 69 85 51 11",
  "amount": 2000.00,
  "currency": "929",
  "externalReferenceId": "REF-INT-IN-0007",
  "sourceInstitution": "SEDAD"
}

The posting a wallet platform applies, the debit-one-credit-many Comviva must provide. Each leg names the account to debit (srcAccount) and the account to credit (dstAccount), with a type (TRANSFER, FEE). The externalId is the switch reference, the same value shown on the receipt and used by the reconciliation search. The amount carries the integer value in minor units, the currency, and a display value. mode is TRANSACTION for a commit (PREAUTH to reserve).

{
  "accounting": [
    {
      "srcAccount": "00040000804",
      "dstAccount": "70000000060",
      "type":"TRANSFER",
      "amount": {
        "value": 50000,
        "currency": "MRU",
        "display": "5000"
      }
    },
    {
      "srcAccount": "30000000056",
      "dstAccount": "13007163151",
      "type":"FEE",
      "amount": {
        "value": 500,
        "currency": "MRU",
        "display": "5"
      }
    }
  ],
  "operation": "TRANSFERT_INTEROP_FROM_BMCI",
  "externalId": "SWITCH123458",
  "externalData": {},
  "ignoreStatus": false,
  "mode": "TRANSACTION"
}

The two-phase outbound (resolve and reserve, then commit after the debit) is expressed on the wallet side through the platform two-phase lifecycle (txnStatus TP, status PAUSED, plus resume or cancel), the same primitive the reserve-before-debit billers need. How that maps is an open question.

3. Error handling and edge cases

At pre-authorization Comviva sees two outcomes, success or failed. After the wallet is debited the customer always sees success, and any in-doubt transfer is reconciled internally (the pending state) to complete or refund.

Outcome Meaning Handling
success the pre-authorization succeeded (ok to debit), and after the debit the transfer completed return the receipt
failed the pre-authorization did not succeed before any money moved (beneficiary not found, wallet not eligible, insufficient funds, destination blocked, or no clear answer from the switch) surface the reason, no debit stands
pending (internal, post-debit) the wallet was debited but the confirmation is in doubt (a timeout after the debit), the BMCI service reconciles it by reference the customer sees success, the reconciliation completes or refunds, never replay

4. Sequence

The send flow, customer to Mobiquity to the BMCI interop service, with the switch as one opaque downstream box.

sequenceDiagram
  participant Customer
  participant Mobiquity
  participant BMCI as BMCI interop service
  participant Sw as National switch (opaque)
  Note over Mobiquity: institution directory held ready (getInstitutionList, cached)
  Customer->>Mobiquity: pick institution, enter beneficiary and amount (one screen)
  Mobiquity->>BMCI: the request (mhostReference, source, destination institution, beneficiary, amount)
  BMCI->>Sw: pre-auth and resolve across the switch
  Sw-->>BMCI: pre-auth ok, resolved beneficiary, switchReference
  BMCI-->>Mobiquity: beneficiary name, switchReference, charge (ok to debit, else failed)
  Mobiquity->>Customer: confirm beneficiary, amount, charge, total (amount + charge)
  Customer->>Mobiquity: PIN confirm
  Mobiquity->>Mobiquity: debit wallet for total to transit, posting endpoint (externalReference = switchReference)
  Mobiquity->>BMCI: customer-paid call (transactionId)
  BMCI->>Mobiquity: split posting, posting endpoint (transit to pool, fee to GIMTEL commission)
  BMCI->>Sw: complete the transfer
  Sw-->>BMCI: settled
  BMCI-->>Mobiquity: success
  Mobiquity-->>Customer: receipt (switchReference)
  Note over BMCI,Mobiquity: if pending (post-debit), the status-check job reconciles, refund on failure

The receive flow, the BMCI service signals Mobiquity to credit. The customer selected nothing in advance.

sequenceDiagram
  participant Sw as National switch (opaque)
  participant BMCI as BMCI interop service
  participant Mobiquity
  participant Customer
  Sw->>BMCI: inbound pre-authorization for a wallet beneficiary
  BMCI->>Mobiquity: getCustomerDetails (check the customer by number)
  Mobiquity-->>BMCI: profile, status, account number, name (or not found)
  BMCI-->>Sw: pre-auth validated (or failed)
  Sw->>BMCI: credit advice
  BMCI->>Mobiquity: credit posting, posting endpoint (debit pool, credit customer, externalReference = switchReference)
  Mobiquity-->>BMCI: credited
  Mobiquity->>Customer: notify (push if enabled, else SMS)

The agent cash-in flow follows the send spine, the wallet credited before the confirmation to the BMCI service. Cash-out is provided soon.

sequenceDiagram
  participant Agent
  participant Mobiquity
  participant BMCI as BMCI interop service
  Agent->>Mobiquity: select cash-in and institution, enter wallet and amount
  Mobiquity->>BMCI: the request (mhostReference, resolve)
  BMCI-->>Mobiquity: switchReference
  Mobiquity->>Mobiquity: credit target wallet, posting endpoint (externalReference = switchReference)
  Mobiquity->>BMCI: customer-paid call (transactionId)
  BMCI->>Mobiquity: split posting, posting endpoint (incl. agent commission credit)
  BMCI-->>Mobiquity: success
  Mobiquity->>Agent: counter receipt

The reconciliation and refund branch on a send left in doubt. A scheduled status-check reconciles any transfer still pending after the confirmation two ways, it reads the wallet side (the posting status, looked up by the shared external reference) and the switch side (the switch transaction-status endpoint), and the two readings together decide complete, refund, or leave pending.

sequenceDiagram
  participant Job as Status-check job (scheduled)
  participant Mobiquity
  participant BMCI as BMCI interop service
  participant Sw as National switch (opaque)
  participant Customer
  loop every few minutes, over a recent window, capped retries
    Job->>Mobiquity: look up posting status by external reference (our side)
    Mobiquity-->>Job: posting status (posted or not)
    Job->>Sw: query switch transaction-status endpoint (switch side)
    Sw-->>Job: switch status
    alt transfer settled (both sides agree)
      Job->>BMCI: complete the split posting once
    else debit never took (refund)
      Job->>Mobiquity: refund posting, credit customer the full debited total
      Mobiquity->>Customer: notify refund
    else still in doubt
      Job->>Job: leave pending, retry next pass
    end
  end

Notifications

The customer must be told on the flows they did not drive.

  • On send. The customer sees the successful receipt screen once the wallet is debited, no pending state is shown. No separate push or SMS is required beyond the screen, since the customer is in the flow.
  • On receive. The inbound interop credit is not initiated on Comviva, so on the credit the customer must be told their wallet was credited: a push notification if push is enabled, otherwise a fall-back SMS. This is the same completion-notification rule as the partner-bank and VISA inbound credits.
  • On agent cash-in or cash-out. The customer gets the credit or debit notification for the wallet movement, and the agent gets the counter receipt.

Transaction detail and receipt

What the customer sees on the interop transaction detail and the receipt is a first-class deliverable, as important as moving the money correctly. An interop transfer crosses institutions, so the customer needs a single reference they can read back and quote, and a clear picture of who was paid and exactly what left the wallet.

The interop receipt always shows:

  • The switch reference, prominent. This is the unique switch reference (unique across all member institutions), the one the customer quotes for support and the one reconciliation is keyed on. It is the same reference used as the posting external reference on the wallet ledger and searched by the status-check job, so the figure on the receipt, the ledger entry, and the reconciliation key are one value, never three different numbers.
  • The destination wallet or institution, and the beneficiary. The member institution the money went to, and the resolved beneficiary name and number, so the customer can see they paid the right person at the right institution.
  • The amount, the tax (the charge), and the total debited. The principal, the charge that bundles the transfer duty and the interchange commission, and the total taken from the wallet, so the receipt matches the wallet movement exactly.
  • The operation. Which interop operation it was, a send, an agent cash-in (versement), or a cash-out, so the entry is unambiguous on the statement.
  • The status. Completed, refused, or in progress (pending), and on a pending result the customer knows the reconciliation will resolve it.
  • The timestamp. When the movement happened.

Because the switch reference on the receipt is the same reference the status-check job searches by on both sides (the wallet posting lookup and the switch status endpoint), the customer, support, and reconciliation all speak the one reference. On an inbound receive the same applies, the credit entry on the statement carries the reference, the source institution, the amount, and the timestamp.