Nile PayNile Pay

Error Handling

Result pattern, retries, timeouts, and error best practices

Result Pattern

All SDK methods that make HTTP requests return a Result object from slang-ts:

type Result<T> = 
  | { status: true; data: T }
  | { status: false; message: string };

Always check status before accessing data:

const result = await nile.createInvoice(request);

if (result.status) {
  // Safe to access result.data
  console.log(result.data.invoiceId);
} else {
  // Handle error
  console.error(result.message);
}

Error Handling by Method

collectPayment()

const payment = nile.collectPayment({ /* ... */ });

// PaymentInstance is returned synchronously
// Errors during init throw immediately (validation, missing config)

try {
  const payment = nile.collectPayment({
    amount: 5000,
    customer: { phone: "+256700000000" },
    reference: "invalid-uuid", // Throws: invalid format
  });
} catch (error) {
  // Validation error
  console.error(error.message);
}

// Handle polling/network errors via event
payment.on("error", (err) => {
  if (err.code === "TIMEOUT") {
    // maxPollDuration exceeded
  } else if (err.code === "NETWORK_ERROR") {
    // Connection failed
  }
});

getStatus() and createInvoice()

const result = await nile.getStatus({ reference });

if (!result.status) {
  switch (result.message) {
    case "Transaction not found":
      // Reference not found
      break;
    case "Invalid reference format":
      // Validation error
      break;
    default:
      // Unexpected error
      break;
  }
}

wait()

try {
  const tx = await payment.wait();
} catch (error) {
  if (error.code === "POLL_TIMEOUT") {
    // maxPollDuration exceeded
    // Payment may still succeed - use getStatus() to verify
  } else if (error.code === "NETWORK_ERROR") {
    // Connection failed during polling
  }
}

Retry Behavior

Automatic Retries

The SDK retries failed HTTP requests automatically:

  • Transport retries: Up to maxRetries attempts for network failures
  • Not for business errors: 4xx responses are not retried
const nile = createNilePay({
  maxRetries: 3, // Default
});

Retry Strategy

  1. First attempt
  2. Wait (exponential backoff)
  3. Second attempt
  4. Wait (exponential backoff)
  5. Third attempt
  6. Fail with error

Timeout Behavior

TimeoutConfigDefaultApplies To
Per-requesttimeoutMs30sSingle HTTP request
Poll durationmaxPollDuration5 minwait() total time
Poll attemptsmaxPollAttempts150wait() max polls
const nile = createNilePay({
  timeoutMs: 30000,        // 30 seconds per request
  maxPollDuration: 300000, // 5 minutes total wait
  maxPollAttempts: 150,    // ~2 second intervals
});

Error Codes

CodeDescription
VALIDATION_ERRORInvalid request parameters
NETWORK_ERRORConnection failed
TIMEOUTRequest timed out
POLL_TIMEOUTwait() exceeded max duration
INVALID_SIGNATURERequest signature verification failed
UNAUTHORIZEDInvalid API credentials

Best Practices

Always Use Reference for Idempotency

// Good: Fresh UUID each payment
const reference = crypto.randomUUID();
const payment = nile.collectPayment({ reference, ... });

// Bad: Hardcoded reference
const payment = nile.collectPayment({ reference: "order-1", ... });

Verify After Timeout

const payment = nile.collectPayment({ /* ... */ });

try {
  await payment.wait();
} catch (error) {
  if (error.code === "POLL_TIMEOUT") {
    // Verify actual status
    const result = await nile.getStatus({ reference: payment.reference });
    if (result.status && result.data.status === "successful") {
      // Payment actually succeeded
      fulfillOrder();
    }
  }
}

Chain Error Handlers

payment
  .on("success", handleSuccess)
  .on("failed", handleFailed)
  .on("error", (err) => {
    logger.error("Payment error:", err);
    // Implement alerting/retry here
  });

Never Ignore Errors

// Bad
const result = await nile.getStatus({ reference });
console.log(result.data.status); // TypeError if status is false

// Good
const result = await nile.getStatus({ reference });
if (!result.status) {
  throw new Error(`Status check failed: ${result.message}`);
}

On this page