Developers
REST API
GuidesErrorsLogin
Get API Keys
API Navigation
  • Overview
  • Quick start
  • Authentication
  • Collect a payment
  • Payment status
  • Refunds
  • Testing
  • Production
  • Security
API reference
  • Create API keys POST
  • List API keys GET
  • Get API key GET
  • Delete API key DEL
  • Collect with MTN POST
  • MTN payment status GET
  • Collect with Airtel POST
    Create and pay
  • Create order POST
  • Order fee POST
  • Pay order with card POST
  • Pay order with bank POST
  • Status and verify
  • Order status POST
  • Verify order POST
  • Cards and tokens
  • Save card POST
  • Tokenize charge GET
  • Refunds
  • Refund order POST
  • Lists and stats
  • List orders GET
  • Get order GET
  • List banks GET
  • Order stats GET
  • List transactions GET
  • Get transaction GET
  • Transaction statuses GET
Errors and limits
  1. Docs
  2. Guides
  3. Payment status

Payment status

Understand payment lifecycle states, status polling patterns, terminal resolutions, and how to verify incoming funds.

Polling Architecture

Ziba Pay uses status API polling for merchant payment verification. Outbound merchant notifications are not implemented for collection routes.

Important: POST/payment/mtn/callback is an internal provider callback used by MTN's servers only. Do not call it from your merchant server or wait for an outbound notification.

Why polling?
Poll the status API with your transactionReferenceId until COMPLETED or FAILED. Do not invent merchant notification endpoints.

Status Polling Endpoints

Depending on the payment channel used during collection, query status using the corresponding endpoint below:

Payment ChannelStatus EndpointHTTP MethodAuthenticationInput Parameter
MTN Mobile Money/payment/mtn/status/:referenceGETAuthorization: Bearer <token>transactionReferenceId in URL path
TransactPay Orders (Status)/payment/zibapay/order/status/:referencePOST (No body)Authorization: Bearer <token>order reference in URL path
TransactPay Orders (Verify)/payment/zibapay/order/verify/:referencePOST (No body)Authorization: Bearer <token>order reference in URL path

Recommended Polling Algorithm

When implementing your polling worker, follow these best practice intervals to balance prompt resolution with rate limit compliance:

  • Initial Delay: Wait 3 to 5 seconds after initiating collection before issuing the first status request.
  • Polling Frequency: Poll every 3 to 5 seconds while status remains PENDING or PROCESSING.
  • Exponential Backoff: If status remains PENDING after 30 seconds, increase the polling interval to 10 seconds.
  • Timeout Threshold: After 180 seconds (3 minutes), conclude polling and treat the session as EXPIRED if no terminal status has been received.
Node.js Polling Worker Implementation
async function pollPaymentStatus(reference, token, maxTimeoutMs = 180000) {
  const startTime = Date.now();
  let intervalMs = 3000;

  // Initial wait for customer USSD prompt
  await new Promise((r) => setTimeout(r, 3000));

  while (Date.now() - startTime < maxTimeoutMs) {
    const res = await fetch(`https://payment-service-mh2d.onrender.com/api/payment/mtn/status/${reference}`, {
      method: "GET",
      headers: { "Authorization": `Bearer ${token}` }
    });

    if (res.ok) {
      const { status } = await res.json();
      console.log(`Current status for ${reference}: ${status}`);

      if (status === "COMPLETED") return { success: true, status };
      if (["FAILED", "CANCELLED", "EXPIRED", "REVERSED"].includes(status)) {
        return { success: false, status };
      }
    }

    // Exponential backoff after 30 seconds
    if (Date.now() - startTime > 30000) {
      intervalMs = Math.min(intervalMs * 1.5, 10000);
    }

    await new Promise((r) => setTimeout(r, intervalMs));
  }

  throw new Error("Payment polling timed out after 3 minutes");
}

Special Edge Case: MTN TIMEOUT Behavior

In cases where the upstream mobile network experiences temporary network latency, MTN may return a TIMEOUT event. Ziba Pay intentionally keeps the local order status as PENDING rather than marking it FAILED.

This ensures that if the customer subsequently enters their PIN and the network confirms settlement, the payment successfully completes instead of being prematurely abandoned.

Order Status & Lifecycle State Machine

7 Lifecycle States

State Transition Flow

PENDING
PROCESSING
COMPLETED
REVERSED
Terminal Failures:FAILEDCANCELLEDEXPIRED
StatusTypeDescriptionMerchant ActionNext States
PENDINGIn-FlightCollection initiated. The USSD prompt or push authorization has been dispatched to the customer's phone.Continue polling with exponential backoff (every 3 to 5 seconds).PROCESSING, COMPLETED, FAILED, EXPIRED, CANCELLED
PROCESSINGIn-FlightThe customer entered their PIN and the transaction is being verified on the telecommunication or bank network.Continue polling. State will resolve to COMPLETED or FAILED within seconds.COMPLETED, FAILED, CANCELLED
COMPLETEDTerminal (Success)Funds successfully debited from customer and credited to merchant account. Final successful state.Fulfill order, deliver digital service, and display success receipt to customer.REVERSED (only if subsequently refunded)
FAILEDTerminal (Failure)Transaction declined by upstream provider due to insufficient balance, invalid PIN, or telecom outage.Stop polling. Inform customer of payment failure and prompt to re-try or change channel.Terminal (no further transitions)
CANCELLEDTerminal (Failure)Transaction rejected explicitly by the customer dismissing the USSD prompt on their handset.Stop polling. Update cart status to cancelled.Terminal (no further transitions)
EXPIREDTerminal (Failure)Customer failed to approve the prompt before the telecom carrier session timeout window elapsed (120–180s).Prompt user to re-initiate a fresh collection request.Terminal (no further transitions)
REVERSEDPost-TerminalA previously COMPLETED order was refunded or reversed by provider intervention or dispute settlement.Revoke goods/license and update your local books.Terminal (no further transitions)

Related

MTN payment statusCollect with MTNOrder status
Was this page helpful?

Let us know how we can make our API documentation better.

PreviousCollect a payment
NextRefunds