Skip to main content

Transaction Inquiry

Query the status and details of your transactions.

Overview​

The Transaction Inquiry API allows you to check the current status and retrieve details of any transaction using various identifiers.

Endpoint​

GET /payment-service/transaction/{transaction_id}

Authentication​

Requires Bearer token authentication:

Authorization: Bearer YOUR_API_TOKEN

Query Methods​

By Transaction ID​

GET /payment-service/transaction/TXN_123456789

By Reference Number​

GET /payment-service/transaction?reference=GCA_REF_987654321

By External ID​

GET /payment-service/transaction?external_id=YOUR_REF_123

Response Example​

Successful Transaction​

{
"status": "success",
"transaction": {
"id": "TXN_123456789",
"reference": "GCA_REF_987654321",
"external_id": "YOUR_REF_123",
"type": "collection",
"amount": "1000",
"currency": "TZS",
"phone_number": "+255683542710",
"network": "airtel_money",
"status": "SUCCESS",
"created_at": "2024-03-15T10:25:00Z",
"completed_at": "2024-03-15T10:30:00Z",
"merchant_id": "MERCHANT_123",
"fees": {
"merchant_fee": "25.00",
"customer_fee": "0.00",
"total_fee": "25.00"
},
"settlement": {
"net_amount": "975.00",
"settled_at": "2024-03-15T18:00:00Z",
"settlement_batch": "BATCH_20240315"
}
}
}

Failed Transaction​

{
"status": "success",
"transaction": {
"id": "TXN_987654321",
"reference": "GCA_REF_123456789",
"external_id": "FAILED_REF_456",
"type": "disbursement",
"amount": "1000",
"currency": "TZS",
"phone_number": "+255683542710",
"network": "airtel_money",
"status": "FAILED",
"failure_reason": "RECIPIENT_NOT_FOUND",
"created_at": "2024-03-15T11:00:00Z",
"failed_at": "2024-03-15T11:02:00Z",
"merchant_id": "MERCHANT_123"
}
}

Transaction Not Found​

{
"status": "error",
"message": "Transaction not found",
"error_code": "TRANSACTION_NOT_FOUND"
}

Implementation Examples​

JavaScript/Node.js​

const axios = require('axios');

async function getTransactionStatus(transactionId) {
try {
const response = await axios.get(
`https://gcapay.site/api/v1/payment-service/transaction/${transactionId}`,
{
headers: {
'Authorization': 'Bearer YOUR_API_TOKEN'
}
}
);

return response.data.transaction;
} catch (error) {
if (error.response?.status === 404) {
console.log('Transaction not found');
return null;
}
throw error;
}
}

async function getTransactionByReference(reference) {
try {
const response = await axios.get(
'https://gcapay.site/api/v1/payment-service/transaction',
{
params: { reference },
headers: {
'Authorization': 'Bearer YOUR_API_TOKEN'
}
}
);

return response.data.transaction;
} catch (error) {
console.error('Query failed:', error.response?.data);
throw error;
}
}

// Usage examples
async function examples() {
// Get by transaction ID
const txn1 = await getTransactionStatus('TXN_123456789');
console.log('Transaction status:', txn1?.status);

// Get by reference
const txn2 = await getTransactionByReference('GCA_REF_987654321');
console.log('Transaction amount:', txn2?.amount);
}

Python​

import requests

class GCAPayClient:
def __init__(self, api_token):
self.api_token = api_token
self.base_url = "https://gcapay.site/api/v1"
self.headers = {
"Authorization": f"Bearer {api_token}"
}

def get_transaction(self, transaction_id):
"""Get transaction by ID"""
url = f"{self.base_url}/payment-service/transaction/{transaction_id}"

response = requests.get(url, headers=self.headers)

if response.status_code == 404:
return None

response.raise_for_status()
return response.json()['transaction']

def get_transaction_by_reference(self, reference):
"""Get transaction by reference number"""
url = f"{self.base_url}/payment-service/transaction"
params = {"reference": reference}

response = requests.get(url, params=params, headers=self.headers)

if response.status_code == 404:
return None

response.raise_for_status()
return response.json()['transaction']

def get_transaction_by_external_id(self, external_id):
"""Get transaction by your external ID"""
url = f"{self.base_url}/payment-service/transaction"
params = {"external_id": external_id}

response = requests.get(url, params=params, headers=self.headers)

if response.status_code == 404:
return None

response.raise_for_status()
return response.json()['transaction']

# Usage
client = GCAPayClient("YOUR_API_TOKEN")

# Get by transaction ID
transaction = client.get_transaction("TXN_123456789")
if transaction:
print(f"Status: {transaction['status']}")
print(f"Amount: {transaction['amount']} {transaction['currency']}")

# Get by reference
transaction = client.get_transaction_by_reference("GCA_REF_987654321")
if transaction:
print(f"Transaction found: {transaction['id']}")

PHP​

<?php

class GCAPayClient {
private $apiToken;
private $baseUrl = 'https://gcapay.site/api/v1';

public function __construct($apiToken) {
$this->apiToken = $apiToken;
}

private function makeRequest($url, $params = []) {
$headers = [
'Authorization: Bearer ' . $this->apiToken,
'Content-Type: application/json'
];

if (!empty($params)) {
$url .= '?' . http_build_query($params);
}

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($httpCode === 404) {
return null;
}

if ($httpCode !== 200) {
throw new Exception("API request failed with status $httpCode: $response");
}

$data = json_decode($response, true);
return $data['transaction'] ?? null;
}

public function getTransaction($transactionId) {
$url = $this->baseUrl . '/payment-service/transaction/' . $transactionId;
return $this->makeRequest($url);
}

public function getTransactionByReference($reference) {
$url = $this->baseUrl . '/payment-service/transaction';
return $this->makeRequest($url, ['reference' => $reference]);
}

public function getTransactionByExternalId($externalId) {
$url = $this->baseUrl . '/payment-service/transaction';
return $this->makeRequest($url, ['external_id' => $externalId]);
}
}

// Usage
try {
$client = new GCAPayClient('YOUR_API_TOKEN');

// Get by transaction ID
$transaction = $client->getTransaction('TXN_123456789');
if ($transaction) {
echo "Status: " . $transaction['status'] . "\n";
echo "Amount: " . $transaction['amount'] . " " . $transaction['currency'] . "\n";
} else {
echo "Transaction not found\n";
}

// Get by reference
$transaction = $client->getTransactionByReference('GCA_REF_987654321');
if ($transaction) {
echo "Transaction ID: " . $transaction['id'] . "\n";
}

} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
}

?>

Transaction Statuses​

Collection Statuses​

StatusDescriptionFinal
PENDINGCustomer prompted to payNo
SUCCESSPayment completedYes
FAILEDPayment failed/rejectedYes
TIMEOUTPayment request expiredYes

Disbursement Statuses​

StatusDescriptionFinal
PROCESSINGBeing processedNo
SUCCESSMoney sent successfullyYes
FAILEDDisbursement failedYes
INSUFFICIENT_FUNDSNot enough balanceYes

Polling Best Practices​

When polling for transaction status:

Exponential Backoff​

async function waitForTransactionCompletion(transactionId, maxWaitTime = 300000) {
const startTime = Date.now();
let delay = 1000; // Start with 1 second

while (Date.now() - startTime < maxWaitTime) {
const transaction = await getTransactionStatus(transactionId);

if (!transaction) {
throw new Error('Transaction not found');
}

// Check if transaction is in final state
const finalStatuses = ['SUCCESS', 'FAILED', 'TIMEOUT', 'INSUFFICIENT_FUNDS'];
if (finalStatuses.includes(transaction.status)) {
return transaction;
}

// Wait before next poll
await new Promise(resolve => setTimeout(resolve, delay));

// Increase delay for next iteration (exponential backoff)
delay = Math.min(delay * 1.5, 30000); // Max 30 seconds
}

throw new Error('Transaction polling timeout');
}

// Usage
try {
const finalTransaction = await waitForTransactionCompletion('TXN_123456789');
console.log('Final status:', finalTransaction.status);
} catch (error) {
console.error('Polling failed:', error.message);
}

Rate Limiting​

  • Maximum: 60 requests per minute per merchant
  • Recommended: 1 request every 10 seconds for active polling
  • Burst: Short bursts of 10 requests allowed

Transaction History​

Get multiple transactions with pagination:

GET /payment-service/transactions?page=1&limit=50&status=SUCCESS&from=2024-03-01&to=2024-03-31

Query Parameters​

ParameterTypeDescription
pageintegerPage number (default: 1)
limitintegerItems per page (max: 100)
statusstringFilter by status
typestringFilter by type (collection/disbursement)
fromdateStart date (YYYY-MM-DD)
todateEnd date (YYYY-MM-DD)

Response Example​

{
"status": "success",
"transactions": [...],
"pagination": {
"current_page": 1,
"total_pages": 5,
"total_count": 248,
"per_page": 50
}
}

Error Handling​

Common error responses:

{
"status": "error",
"message": "Transaction not found",
"error_code": "TRANSACTION_NOT_FOUND"
}
{
"status": "error",
"message": "Invalid transaction ID format",
"error_code": "INVALID_TRANSACTION_ID"
}
{
"status": "error",
"message": "Rate limit exceeded",
"error_code": "RATE_LIMIT_EXCEEDED",
"retry_after": 60
}

Use Cases​

Order Status Updates​

async function updateOrderStatus(orderId, transactionId) {
const transaction = await getTransactionStatus(transactionId);

if (transaction) {
switch (transaction.status) {
case 'SUCCESS':
await updateOrder(orderId, { status: 'paid', paid_at: transaction.completed_at });
break;
case 'FAILED':
await updateOrder(orderId, { status: 'payment_failed', failure_reason: transaction.failure_reason });
break;
case 'PENDING':
await updateOrder(orderId, { status: 'awaiting_payment' });
break;
}
}
}

Reconciliation​

async function reconcileTransactions(date) {
const transactions = await getTransactionHistory({
from: date,
to: date,
limit: 100
});

for (const transaction of transactions) {
await reconcileTransaction(transaction);
}
}

Next Steps​