Interswitch is the payment rail most West African Acumatica clients I've worked with actually run on for card and bank transfers in Nigeria, and it deserves more attention than it gets in the usual "payment integration" writeups, which are almost entirely written around Stripe and PayPal. The mechanics are different enough, a two-step transaction lifecycle, a distinct hash-based signature scheme, that porting a generic payment gateway pattern onto it without reading Interswitch's own docs closely will produce a broken integration.
Purchase and query: two calls, not one
Interswitch's Web Pay / Quickteller Business flow (I've integrated both, they share the same underlying pattern) is fundamentally a redirect-then-verify model, not a single synchronous charge call. Acumatica initiates a transaction reference, redirects the customer to Interswitch's hosted payment page, and then, critically, must call the Transaction Query API to confirm the actual outcome rather than trusting the redirect's query-string parameters alone:
public async Task<bool> ConfirmPaymentAsync(string transactionRef)
{
var url = $"{_baseUrl}/api/v3/purchases/{transactionRef}/query";
var req = new HttpRequestMessage(HttpMethod.Get, url);
req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await GetAccessTokenAsync());
var resp = await _httpClient.SendAsync(req);
var result = JsonSerializer.Deserialize<InterswitchQueryResponse>(await resp.Content.ReadAsStringAsync());
// ResponseCode "00" is success, anything else, including timeouts,
// must be treated as unconfirmed, never assumed successful
return result.ResponseCode == "00";
}
The customer's browser redirecting back to Acumatica with a "success" query parameter is not proof of payment, it's a hint that you should go verify. A user can close the tab mid-transaction, or the redirect can be manually crafted by anyone who guesses your URL pattern. Every Interswitch integration I've built confirms the transaction status server-side via the Query API before touching the Cash Management or AR side of Acumatica, and I've seen a competitor's integration that skipped this step get exploited on a client's old Magento-adjacent instance before we were brought in to fix it.
OAuth client credentials, with a separate hash for payment initiation
API calls use standard OAuth bearer tokens, but the actual payment initiation request additionally requires a SHA-512 hash of specific fields (amount, transaction reference, merchant code, a shared secret) concatenated in an exact order Interswitch specifies, get the field order or the secret wrong and you get a generic "invalid hash" rejection with no further detail, which makes this the single most common integration bug I've had to debug for clients moving off manual bank transfers onto Interswitch.
string BuildHash(string merchantCode, string payableId, string amount, string secret)
{
// Field order is exact and documented, do not "tidy" it
var raw = $"{merchantCode}{payableId}{amount}{secret}";
using var sha512 = SHA512.Create();
var bytes = sha512.ComputeHash(Encoding.UTF8.GetBytes(raw));
return Convert.ToHexString(bytes).ToLowerInvariant();
}
Where a confirmed payment lands in Acumatica
Once the Query API confirms success, I create a Payment (AR side, applied to the originating invoice) rather than posting directly to a GL account, this keeps the Acumatica-native AR aging and application workflow intact, and means a partial payment or an over-payment scenario still runs through Acumatica's normal application logic instead of a custom bypass. The transaction reference from Interswitch gets stored on the Payment's Extended Reference Number field so a reconciliation report can match Acumatica payments against Interswitch's own settlement statement later.
Settlement lag and fee deduction
Interswitch, like most card processors, settles net of its transaction fee on a T+1 or T+2 cycle depending on the merchant agreement, not the gross amount the customer paid. I book the fee as a separate small AP-side adjustment against a "Payment Processing Fees" expense account rather than netting it against the AR payment itself, which keeps the AR side showing the full invoiced amount as paid while the actual bank-hitting cash figure reconciles separately, this is the same reconciliation shape I use for Pesapal and for card settlements generally, and it's worth building once as a reusable pattern rather than per-gateway.
Wrapping up
An Interswitch integration that survives production is built around the redirect-then-verify model, never trusts a browser callback as proof of payment, gets the SHA-512 hash field order exactly right, and books settlement fees as a separate adjustment rather than netting them silently against the AR payment. Get the verification step right first, everything else is comparatively easy REST plumbing.
Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.