Transactions
Retrieve a Transaction
Fetch the current status and details of a transaction using its ePay reference.
Retrieve a Transaction
GET /v1/transactions/:reference
Returns the current state of a transaction. Use this to poll for status updates or reconcile payments against your records.
Request
raw HTTP
npm install @e-pay/nodenpm install @e-pay/nestjspip install epaypip install epaypip install epaypip install epaycomposer require epay-et/php-sdkcomposer require epay-et/php-sdkimplementation("com.epayethiopia:epay-java:0.1.0")implementation("com.epayethiopia:epay-spring-boot-starter:0.1.0")go get github.com/epay-et/go-sdkNothing NestJS-specific here — this is the same Node.js client call.
Nothing Django-specific here — this is the same Python client call.
Nothing Flask-specific here — this is the same Python client call.
Nothing FastAPI-specific here — this is the same Python client call.
Nothing Laravel-specific here — this is the same PHP client call.
Nothing Spring Boot-specific here — this is the same Java client call.
curl https://api.epayethiopia.com/v1/transactions/PAB12CD3420260813 \
-H "Authorization: Bearer sk_live_your_key_here"import { Epay } from '@e-pay/node';
const epay = new Epay({ apiKey: process.env.EPAY_SECRET_KEY });
const transaction = await epay.transactions.retrieve(reference);
if (transaction.status === 'completed') {
const receipt = await epay.payments.verify(reference);
await fulfil(receipt);
}
const res = await fetch('https://api.epayethiopia.com/v1/transactions/PAB12CD3420260813', {
headers: { Authorization: `Bearer ${process.env.EPAY_SECRET_KEY}` },
});
if (!res.ok) throw new Error(`ePay ${res.status}: ${await res.text()}`);
const transaction = await res.json();from epay import Epay
epay = Epay() # reads EPAY_SECRET_KEY
transaction = epay.transactions.retrieve(reference)
if transaction["status"] == "completed":
receipt = epay.payments.verify(reference)
fulfil(receipt)
import os
import requests
res = requests.get(
"https://api.epayethiopia.com/v1/transactions/PAB12CD3420260813",
headers={"Authorization": f"Bearer {os.environ['EPAY_SECRET_KEY']}"},
timeout=30,
)
res.raise_for_status()
transaction = res.json()use Epay\Epay;
$epay = new Epay(); // reads EPAY_SECRET_KEY
$transaction = $epay->transactions->retrieve($reference);
if ($transaction['status'] === 'completed') {
$receipt = $epay->payments->verify($reference);
fulfil($receipt);
}
$ch = curl_init('https://api.epayethiopia.com/v1/transactions/PAB12CD3420260813');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('EPAY_SECRET_KEY')],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
if ($status >= 400) {
throw new RuntimeException("ePay {$status}: {$body}");
}
$transaction = json_decode($body, true);transaction, err := client.Transactions.Retrieve(ctx, reference)
if err != nil {
return err
}
// Nullable fields are pointers, so "absent" stays distinct from "empty".
if transaction.PaidAt != nil {
log.Println("paid at", \*transaction.PaidAt)
}
if transaction.Status == epay.StatusCompleted {
receipt, err := client.Payments.Verify(ctx, reference)
if err != nil {
return err
}
return fulfil(receipt)
}
req, _ := http.NewRequestWithContext(ctx, http.MethodGet, "https://api.epayethiopia.com/v1/transactions/PAB12CD3420260813", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("EPAY_SECRET_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
if res.StatusCode >= 400 {
return fmt.Errorf("ePay %d", res.StatusCode)
}
var transaction struct {
Reference string `json:"reference"`
Status string `json:"status"`
Amount string `json:"amount"`
CurrencyCode string `json:"currencyCode"`
PaidAt *string `json:"paidAt"`
CreatedAt string `json:"createdAt"`
}
if err := json.NewDecoder(res.Body).Decode(&transaction); err != nil {
return err
}Epay epay = Epay.fromEnvironment(); // reads EPAY_SECRET_KEY
Transaction transaction = epay.transactions().retrieve(reference);
// Nullable fields stay null, so "not paid yet" is distinct from anything else.
if (transaction.paidAt() != null) {
System.out.println("paid at " + transaction.paidAt());
}
if (transaction.status() == TransactionStatus.COMPLETED) {
VerifiedPayment receipt = epay.payments().verify(reference);
fulfil(receipt);
}
HttpClient http = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(
URI.create("https://api.epayethiopia.com/v1/transactions/PAB12CD3420260813"))
.header("Authorization", "Bearer " + System.getenv("EPAY_SECRET_KEY"))
.GET()
.build();
HttpResponse<String> response = http.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() >= 400) {
throw new IllegalStateException("ePay " + response.statusCode() + ": " + response.body());
}
// Parse with Jackson, Gson, or your JSON library of choice.
String transaction = response.body();import { Controller, Get, NotFoundException, Param } from '@nestjs/common';
import { EpayNotFoundError, EpayService } from '@e-pay/nestjs';
@Controller('payments')
export class PaymentsController {
constructor(private readonly epay: EpayService) {}
@Get(':reference')
async status(@Param('reference') reference: string) {
try {
return await this.epay.transactions.retrieve(reference);
} catch (error) {
if (error instanceof EpayNotFoundError) throw new NotFoundException();
throw error;
}
}
}
from django.http import Http404, JsonResponse
from django.views.decorators.http import require_GET
from epay import EpayNotFoundError
from .clients import epay # Epay(api_key=settings.EPAY_SECRET_KEY)
@require_GET
def payment_status(request, reference):
try:
return JsonResponse(epay.transactions.retrieve(reference))
except EpayNotFoundError:
raise Http404from flask import abort, jsonify
from epay import EpayNotFoundError
from app import app, epay # epay = Epay(), one per process
@app.get("/payments/<reference>")
def payment_status(reference):
try:
return jsonify(epay.transactions.retrieve(reference))
except EpayNotFoundError:
abort(404)
from fastapi import HTTPException
from epay import EpayNotFoundError
from app.main import app, epay # epay = AsyncEpay(), closed in lifespan
@app.get("/payments/{reference}")
async def payment_status(reference: str):
try:
return await epay.transactions.retrieve(reference)
except EpayNotFoundError:
raise HTTPException(404)use Epay\Epay;
use Epay\Exception\EpayNotFoundException;
use Illuminate\Http\JsonResponse;
final class PaymentController
{
public function \_\_construct(private readonly Epay $epay) {}
public function show(string $reference): JsonResponse
{
try {
return response()->json($this->epay->transactions->retrieve($reference));
} catch (EpayNotFoundException) {
abort(404);
}
}
}
// routes/web.php
// Route::get('/payments/{reference}', [PaymentController::class, 'show']);
@RestController
@RequestMapping("/payments")
class PaymentController {
private final Epay epay;
PaymentController(Epay epay) {
this.epay = epay;
}
@GetMapping("/{reference}")
Transaction status(@PathVariable String reference) {
try {
return epay.transactions().retrieve(reference);
} catch (EpayNotFoundException e) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND);
}
}
}Response
{
"reference": "PAB12CD3420260813",
"merchantReference": "order_123",
"status": "completed",
"amount": "250.00",
"currencyCode": "ETB",
"paidAt": "2026-08-13T11:47:00.000Z",
"createdAt": "2026-08-13T11:30:00.000Z"
}Path Parameters
Prop
Type
Response
Prop
Type
Transaction statuses
| Status | Description |
|---|---|
pending | Session created; customer has not yet interacted with the checkout. |
processing | Customer is actively on the checkout page. |
completed | Payment was successful. |
failed | Payment attempt failed. |
cancelled | Transaction was cancelled via the API or by the customer. |
Errors
| Status | Description |
|---|---|
401 | Missing or invalid API key. |
404 | No transaction found for the given reference under your account. |
Next: Transaction Timeline — see every event recorded against this transaction.