Skip to main content
Network failures and timeouts can make it impossible to know whether a request succeeded. Hyparrow uses reference fields to let you retry requests safely — the same reference always maps to the same transaction, so retrying a timed-out request will not create a duplicate charge.

Reference fields by operation

Different operations use different reference fields:
OperationFieldWhere
Bill paymentrequestRefRequest body
Bank transfertransferCodeGenerated by server, returned in response

Bill payments — requestRef

When paying a bill, pass a requestRef in the request body. If the request times out or fails with a network error, retry using the same requestRef. The API and the upstream processor use this value to identify the transaction.
{
  "paymentCode": "10401",
  "customerId": "04150000001",
  "amount": "150000",
  "requestRef": "9182736450123"
}
Always include requestRef in bill payment requests. If omitted, the server auto-generates a reference that cannot be predicted — you will be unable to look up or retry the transaction safely.

Bank transfers — transferCode

For bank transfers, the server generates a transferCode internally using a timestamp and prefix. The transferCode is returned in the response data object:
{
  "success": true,
  "data": {
    "TransferCode": "23191707684123456",
    "TransactionID": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "WalletBalance": 85000
  },
  "message": "Transfer initiated successfully and wallet debited"
}
Use the TransferCode to check the status of the transfer:
GET https://api.hyparrow.com/api/v1/transfers/status?reference=23191707684123456

Generating unique references

A good requestRef is:
  • Unique per transaction — never reuse a reference for a different payment
  • Deterministic for retries — always reuse the same reference when retrying the same failed request
  • 13 digits — matches the format expected by the upstream processor

Timestamp-based

Combine a Unix timestamp in milliseconds with a random suffix for a compact, collision-resistant 13-digit value.

UUID-derived

Take the first 13 digits of a UUID’s numeric representation, or hash a UUID down to 13 digits.
Examples in common languages:
// 13-digit reference: ms timestamp + 3 random digits
function generateRequestRef() {
  const ts = Date.now().toString(); // 13 digits from ~2001 onwards
  return ts;
}

// Or with extra entropy:
function generateRequestRef() {
  const ts = Date.now().toString().slice(0, 10);
  const rand = Math.floor(Math.random() * 1000).toString().padStart(3, '0');
  return ts + rand;
}
Do not generate a new reference on every retry attempt. The reference must stay the same across all retry attempts for a given transaction. Generate it once, store it alongside the pending transaction in your database, and reuse it on every retry until you receive a definitive success or failure response.

Which requests are idempotent

Not all requests are safe to retry unconditionally:
Request typeIdempotent?Notes
POST /api/v1/bills/pay with requestRefYesSame requestRef maps to the same upstream transaction
POST /api/v1/bills/pay without requestRefNoA new unpredictable reference is generated each time
POST /api/v1/transfers/initiateNoThe server generates a new transferCode on each call; always check status before retrying
GET requests (status checks, lookups)YesSafe to retry at any time
POST /api/v1/verify/* (KYC)NoEach call deducts from your balance

Safe retry pattern

1

Generate a reference before the request

Create your requestRef and store it in your database associated with the pending operation before you send the first request.
const requestRef = generateRequestRef();
await db.transactions.create({ requestRef, status: 'pending', ...paymentDetails });
2

Send the request

Include requestRef in the request body.
const response = await fetch('https://api.hyparrow.com/api/v1/bills/pay', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-API-Key': apiKey,
    'X-API-Secret': apiSecret,
  },
  body: JSON.stringify({
    paymentCode: '10401',
    customerId: '04150000001',
    amount: '150000',
    requestRef,
  }),
});
3

Handle the response

If the response is successful (success: true), mark the transaction as complete in your database.If the response is a network error or a 500, retry with the same requestRef. Apply exponential backoff between attempts.If the response is a 400, the request was rejected — do not retry with the same parameters. Fix the input and generate a new requestRef for the corrected request.
4

Check status if outcome is uncertain

If you receive a timeout with no response at all, query the bill status endpoint using your original requestRef before deciding whether to retry:
GET https://api.hyparrow.com/api/v1/bills/status?reference=9182736450123
Only retry the payment if the status check confirms no transaction exists for that reference.

Reference uniqueness across clients

References are scoped to your API credentials. You do not need to coordinate reference namespaces across different API keys. A requestRef used by one client will not conflict with the same value used by a different client.