Banxa technical integration: on/off-ramp, HMAC, webhooks

Deposit and withdrawal requests get stuck, and support handles each ticket manually. We integrate the payment service turnkey: we configure scenarios, statuses, and notifications so operations run without manual intervention. Approval and dispute resolution timelines are reduced multiple times.

Blockchain Development Services

Frequently Asked Questions

Latest works

  • Development of a web application for FEEDME
    Development of a web application for FEEDME
    1376
  • Development of an online store for the company FURNORO
    Development of an online store for the company FURNORO
    1350
  • B2B Advance company logo design
    B2B Advance company logo design
    798
  • Development of a web application for Enviok
    Development of a web application for Enviok
    1088
  • AIDER company logo development
    AIDER company logo development
    1034
  • CRM development for Chasseurs
    CRM development for Chasseurs
    1130

Banxa integration: what breaks before launch

Connecting Banxa looks like exchanging keys and a single API call — right up until the first real transactions. Failures surface not at the start: deposit and withdrawal requests hang in an intermediate status, and the event arrives before the response to creating the request.

Status desynchronization rests on two independent update channels. Webhooks arrive with a delay and without guaranteed order, while periodic polling returns a snapshot that is already stale by the time it is processed.

If the code takes the latest incoming event without checking time and state version, the request rolls back and hangs until manual investigation.

Duplicate crediting is almost always a consequence of duplicate delivery: the provider sends the event again if it did not receive confirmation, and the handler credits the balance each time.

The protection is idempotency by operation identifier and a log of processed events with a retention window. Searching for a duplicate by amount and address is not a key — it triggers false positives on matches and misses real duplicates.

A separate category is calls that fail signature verification. HMAC is calculated from the original request body with exact field order and timestamp, so normalizing or rebuilding JSON breaks it and some operations silently drop out.

On withdrawal, limits and recipient address checks are added — the request hangs at the provider, while the interface shows it as successful.

Before launch this looks like a list of agreements; after, it looks like a queue of manual investigations and diverging balances. Below we break down how this is closed: the status model, event handling, and periodic reconciliation with the provider.

What Banxa integration provides: speed, conversion, resilience

Integrating Banxa embeds the purchase and withdrawal of digital assets directly into the product interface: the user does not leave for a third-party site and does not get lost on an unfamiliar storefront.

But the value here is not in the mere fact of connecting the provider, but in how requests behave in production — how many close on their own and what happens when the external service responds slowly or goes silent.

Request processing speed

The provider sends every status change as an event to our handler; we confirm receipt and immediately move the operation to the required state — without an operator or manual reconciliations.

Requests are verified by signature, so a callback cannot be forged and balance cannot be credited from the outside, and false events are filtered out before business logic.

Time from provider response to crediting is reduced to seconds, and the share of requests closed fully automatically reaches nine out of ten. The remainder are real disputed cases: amount mismatch, failed identity verification, refund.

There are fewer of them not because we added a button, but because we removed intermediate manual confirmations from the main path.

Resilience to provider-side failures

The external service may fail to respond, send an event twice, or lose it entirely during a connection drop. Processing is idempotent: a repeated callback does not create a second operation and does not move an already final request backward.

If an event did not arrive, scheduled reconciliation pulls the current status and drives the request to completion.

That removes an entire class of failures — “payment went through, but the dashboard shows pending.” This is exactly the scenario that most often erodes payment conversion: the user sees uncertainty and leaves.

Connection options: ready-made module, custom gateway, hybrid

The choice between connection options determines not the speed of the first transaction, but who owns the status logic.

A ready-made exchange module gives it to the provider, a custom gateway gives it to your team, and a partially ready integration divides responsibility between the parties. Below is when each path is appropriate and what you will have to take on.

Ready-made exchange module

The module is installed next to the dashboard: the user passes identity verification, chooses a payment method, and the system requests a quote and creates an operation through the Banxa interface.

Request signing and webhooks come out of the box, but status transition rules and error texts remain vendor-defined.

Option When it fits Limitations
Ready-made exchange module Deposits and withdrawals are needed within tight deadlines, scenario is standard Status logic and screens are vendor-defined
Custom gateway Non-standard accounting, custom limits, audit of every operation More backend work, support required
Partially ready integration Some flows are covered, some are unique Two sources of statuses, reconciliation mandatory

Custom gateway with full status control

A custom gateway routes funds through your backend: you store the link between the request, the operation, and the on-chain transaction, re-verify the signature of incoming notifications, and recover missed events by log reconciliation.

The mixed scheme takes only withdrawal from here: deposits go through the ready-made module, while payouts remain under your control — up to a “withdrawal-only” mode with manual confirmation.

More expensive to develop, but stuck operations and accounting discrepancies are resolved according to your rules.

Workflow: from scenario audit to support handover

We work in iterations: first we document all deposit and withdrawal scenarios, and only then write code. This way implementation stages do not stretch into rework, and integration acceptance follows a pre-agreed checklist.

  1. Scenario audit — we break down fiat purchase, sale, partial execution, cancellation, and refund, and compare them against limits and verification levels.
  2. Request status model — a finite-state machine: we map external statuses to internal ones, describe transitions and the behavior of “stuck” requests.
  3. Signature and notification handlers — HMAC verification on our side, keys in a secrets vault, idempotency by event identifier.
  4. Fault tolerance — retries with increasing delay, event log, regular reconciliation with the provider.
  5. Acceptance on disputed scenarios — run cancellations, amount mismatches, and failed verification on the test environment.
  6. Support handover — instructions for the on-call shift, alerts on status mismatch, access, and incident investigation.

Duplicate and lost notification checks

Notifications arrive repeatedly and not always in the order in which events occurred. That is why processing is idempotent: an event is applied once by its identifier, and an outdated one cannot roll the request back to a previous status.

Reconciliation runs alongside — a lost notification does not leave the request in an intermediate state; polling pulls it forward.

Acceptance on disputed scenarios

We check not the “happy path” but conflicts: double delivery, cancellation after crediting, amount mismatch due to exchange rate, verification rejection after debit.

We run each scenario on the test environment and on a small volume of real requests, recording the user status and the log entry.

Configurations, status models, and regulations on delivery

Banxa integration is considered delivered not by the amount of code, but by the set of artifacts with which it is operated without the author. We hand over environment configurations, the request state map, key access policies, and support regulations.

  • Configuration files by environment: method endpoints, limits, timeouts, list of currencies and exchange directions.
  • Request signature scheme: where the shared secret is stored, how the signature is generated, and how an incoming webhook is verified.
  • Request status map: provider states, their relationship to internal ones, final transitions, and those requiring manual investigation.
  • Key access policies: separation by environment and scenario, rotation, storage in a secret vault, prohibition of logging.
  • Retry rules: which errors we retry, with what interval, where we stop and hand over to a human.
  • Integration documentation: methods, exchange examples, interaction scheme, acceptance checklist.

First-line support documentation

A separate document answers the on-call shift’s questions: how to find a request’s state by its number, what each status means, which errors are treated by retry, and which are escalated. The first line closes typical requests itself without involving developers.

Disputed operation investigation procedure

It describes the procedure when funds are debited but crediting is not confirmed: how to export the exchange log, match identifiers, request confirmation from the provider, and record the outcome. Each investigated case adds to the knowledge base.

Case: deposits and withdrawals without stuck requests

The Banxa integration case — improving an already live payment flow of the service: deposits and withdrawals worked, but relied on manual control by the on-call engineer.

The problem was not the provider, but the handling of its events on our side — asynchronous statuses, duplicate deliveries, and signature verification after balance changes.

What it was before rework

Up to 18% of requests required manual intervention: signature mismatch, lost status-change event, repeated webhook delivery.

A disputed operation was closed in several hours, and on peak days it rolled over to the next shift — investigation proceeded sequentially, by a single engineer. Duplicate credits were rare, but each meant manual reconciliation and balance correction.

What changed after

We moved processing to idempotent keys: the request and the incoming event each have their own identifier, and repeated delivery is recognized and discarded before writing to the database.

Statuses were consolidated into an explicit transition model with a log, and lost webhooks are picked up by background provider polling with increasing delay. The signature is verified before any balance changes.

Share of requests under manual investigation dropped from 18% to less than 1% — only provider-side disputes remained. Time to close a disputed operation shrank from several hours to 10–15 minutes. No duplicate credits were recorded during the observation period.

How does request signing differ from webhook verification?

These are two different trust contours that are often confused. Request signing confirms that the outgoing request was sent by us and that the body did not change along the way.

Webhook verification solves the reverse task: ensuring that the incoming notification came from Banxa, not from someone who learned the address of our handler.

Signature is calculated on a canonical string: method, path, timestamp, body hash. From it and the secret key, an authentication code (HMAC) is produced, and it goes in the header.

The provider recalculates the value on its side: a mismatch in even one byte of the body or a timestamp outside the allowed window means rejection. The secret itself never leaves the backend.

Incoming notification is verified in mirror fashion: we calculate the same string and the same secret and compare in constant time. A mismatch means we reject it — that is the protection against forgeries.

Order also matters: first we record the event in the log, then respond with success; otherwise the provider will repeat delivery.

Operation idempotency is the third, independent layer. The signature is valid, but the notification may arrive twice: the provider did not wait for a response and repeated.

Therefore we write the event identifier into a table with a unique index — repeated notification delivery is recognized and does not create a second credit or refund. We transition state by the status model, not “as it arrived.”

Bottom line: signature is responsible for authorship and integrity, webhook verification for authenticity, and idempotency for ensuring that a repeat does not turn into a duplicate.

What is clarified before connection: limits, statuses, failures

Before start, we fix the boundaries that Banxa integration most often stumbles over: thresholds for amounts and frequency, undefined statuses during deposits and withdrawals, discrepancies between our log and the provider’s. Below are the technical questions asked at this stage.

What operation limits should be set?

Thresholds are set by the provider, and they depend on the verification level: daily and monthly volume, minimum and maximum per operation, request frequency. We keep them in configuration, not in code — when thresholds change, one file is edited, without a release.

What happens if the provider fails?

A timeout does not equal a failure: the operation may go through while the response does not arrive. Therefore each request goes out with its own identifier, retries are idempotent, and disputed requests go into a reconciliation queue instead of manual investigation.

How are status discrepancies investigated?

We log webhooks and signature verification in full — body, verification result, time. We close a discrepancy by reconciling by order identifier and redelivering missed events.

What if the module is already partially ready?

First an audit: we look at webhook handling, idempotency, key storage, and limit logic. More often the status layer is reworked, less often the entire module; we agree on the scope of changes before start.

Who is responsible after handover?

We hand over the status model, flow documentation, escalation procedure, and access to logs. After that — an agreed response window for failures; new methods and limit changes go as separate tasks.

Let’s discuss the task: what is needed for an estimate and plan

To come back with an estimate and plan rather than general wording, a minimal set of inputs is needed. The more specifically the scenarios and current models are described, the fewer clarification cycles and the more accurate the timeline for Banxa connection.

  • Scenarios. Where the user buys and sells the asset, whether identity verification is required, whether limits, repeat operations, and partial refunds are needed.
  • Current models. How balance accounting is structured, where operations are recorded, which services are already running and how they are connected.
  • Examples of requests and statuses. Real or test sets of operations: success, failure, pending, refund. We use them to check state handling and repeated event delivery.
  • Access. What is already open on the provider’s test environment, which keys and confirming signatures are needed, whom to involve from the partner side for checks.
  • Deadline constraints. Launch dates, ties to releases, windows in which changes are allowed on the production environment.
  • Team on your side. Who is responsible for the backend, payments, and support, who approves requirements and accepts the result.
  • Reconciliation. How often operations are expected to be reconciled, who investigates discrepancies and by what procedure.

Describe the task in free form — that is enough to start. We will discuss it and come back with an estimate and plan: stages, connection timelines, distribution of responsibility, and the points where your decisions are needed.