Verify a Payment
Retrieve a verified receipt for a completed transaction.
Verify a Payment
GET /v1/transactions/:reference/verify
Returns full receipt details for a completed transaction. Use this to confirm payment before fulfilling an order.
Returns 400 if the transaction is not yet completed. Poll
Retrieve first if you need to check status
before verifying.
Request
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/verify \
-H "Authorization: Bearer sk_live_your_key_here"import { Epay, EpayBadRequestError } from '@e-pay/node';
const epay = new Epay({ apiKey: process.env.EPAY_SECRET_KEY });
try {
const receipt = await epay.payments.verify(reference);
// receipt.status === 'completed', plus serviceFee, paymentMethod, customer
await fulfil(receipt.merchantReference!, receipt.amount);
} catch (error) {
// The API rejects anything not yet completed.
if (error instanceof EpayBadRequestError) return 'not settled yet';
throw error;
}
const res = await fetch('https://api.epayethiopia.com/v1/transactions/PAB12CD3420260813/verify', {
headers: { Authorization: `Bearer ${process.env.EPAY_SECRET_KEY}` },
});
if (!res.ok) throw new Error(`ePay ${res.status}: ${await res.text()}`);
const receipt = await res.json();from epay import Epay, EpayBadRequestError
epay = Epay() # reads EPAY_SECRET_KEY
try:
receipt = epay.payments.verify(reference) # receipt["status"] == "completed", plus serviceFee, paymentMethod, customer
fulfil(receipt["merchantReference"], receipt["amount"])
except EpayBadRequestError: # The API rejects anything not yet completed.
return "not settled yet"
import os
import requests
res = requests.get(
"https://api.epayethiopia.com/v1/transactions/PAB12CD3420260813/verify",
headers={"Authorization": f"Bearer {os.environ['EPAY_SECRET_KEY']}"},
timeout=30,
)
res.raise_for_status()
receipt = res.json()use Epay\Epay;
use Epay\Exception\EpayBadRequestException;
$epay = new Epay(); // reads EPAY_SECRET_KEY
try {
$receipt = $epay->payments->verify($reference);
// $receipt['status'] === 'completed', plus serviceFee, paymentMethod, customer
fulfil($receipt['merchantReference'], $receipt['amount']);
} catch (EpayBadRequestException) {
// The API rejects anything not yet completed.
return 'not settled yet';
}
$ch = curl_init('https://api.epayethiopia.com/v1/transactions/PAB12CD3420260813/verify');
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}");
}
$receipt = json_decode($body, true);receipt, err := client.Payments.Verify(ctx, reference)
switch {
case errors.Is(err, epay.ErrBadRequest):
// The API rejects anything not yet completed.
return errNotSettledYet
case err != nil:
return err
}
// receipt.Status == epay.StatusCompleted, plus ServiceFee, PaymentMethod, Customer
return fulfil(receipt.MerchantReference, receipt.Amount)
req, _ := http.NewRequestWithContext(ctx, http.MethodGet, "https://api.epayethiopia.com/v1/transactions/PAB12CD3420260813/verify", 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 receipt struct {
Reference string `json:"reference"`
Status string `json:"status"`
Amount string `json:"amount"`
ServiceFee *string `json:"serviceFee"`
PaymentMethod *string `json:"paymentMethod"`
PaidAt string `json:"paidAt"`
}
if err := json.NewDecoder(res.Body).Decode(&receipt); err != nil {
return err
}Epay epay = Epay.fromEnvironment(); // reads EPAY_SECRET_KEY
try {
VerifiedPayment receipt = epay.payments().verify(reference);
// receipt.status() == COMPLETED, plus serviceFee(), paymentMethod(), customer()
fulfil(receipt.merchantReference(), receipt.amount());
} catch (EpayBadRequestException e) {
// The API rejects anything not yet completed.
return NOT_SETTLED_YET;
}
HttpClient http = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(
URI.create("https://api.epayethiopia.com/v1/transactions/PAB12CD3420260813/verify"))
.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 receipt = response.body();import { ConflictException, Controller, Get, Param } from '@nestjs/common';
import { EpayBadRequestError, EpayService } from '@e-pay/nestjs';
@Controller('payments')
export class PaymentsController {
constructor(private readonly epay: EpayService) {}
@Get(':reference/receipt')
async receipt(@Param('reference') reference: string) {
try {
return await this.epay.payments.verify(reference);
} catch (error) {
// The API rejects anything not yet completed.
if (error instanceof EpayBadRequestError) {
throw new ConflictException('Payment has not completed yet');
}
throw error;
}
}
}
from django.http import JsonResponse
from django.views.decorators.http import require_GET
from epay import EpayBadRequestError
from .clients import epay # Epay(api_key=settings.EPAY_SECRET_KEY)
@require_GET
def receipt(request, reference):
try:
receipt = epay.payments.verify(reference)
except EpayBadRequestError:
# The API rejects anything not yet completed.
return JsonResponse({"detail": "Payment has not completed yet"}, status=409)
return JsonResponse(receipt)from flask import abort, jsonify
from epay import EpayBadRequestError
from app import app, epay # epay = Epay(), one per process
@app.get("/payments/<reference>/receipt")
def receipt(reference):
try:
return jsonify(epay.payments.verify(reference))
except EpayBadRequestError: # The API rejects anything not yet completed.
abort(409, "Payment has not completed yet")
from fastapi import HTTPException
from epay import EpayBadRequestError
from app.main import app, epay # epay = AsyncEpay(), closed in lifespan
@app.get("/payments/{reference}/receipt")
async def receipt(reference: str):
try:
return await epay.payments.verify(reference)
except EpayBadRequestError:
# The API rejects anything not yet completed.
raise HTTPException(409, "Payment has not completed yet")use Epay\Epay;
use Epay\Exception\EpayBadRequestException;
use Illuminate\Http\JsonResponse;
final class PaymentController
{
public function \_\_construct(private readonly Epay $epay) {}
public function receipt(string $reference): JsonResponse
{
try {
return response()->json($this->epay->payments->verify($reference));
} catch (EpayBadRequestException) {
// The API rejects anything not yet completed.
abort(409, 'Payment has not completed yet');
}
}
}
// routes/web.php
// Route::get('/payments/{reference}/receipt', [PaymentController::class, 'receipt']);
@RestController
@RequestMapping("/payments")
class PaymentController {
private final Epay epay;
PaymentController(Epay epay) {
this.epay = epay;
}
@GetMapping("/{reference}/receipt")
VerifiedPayment receipt(@PathVariable String reference) {
try {
return epay.payments().verify(reference);
} catch (EpayBadRequestException e) {
// The API rejects anything not yet completed.
throw new ResponseStatusException(HttpStatus.CONFLICT, "Payment has not completed yet");
}
}
}Response
{
"reference": "PAB12CD3420260813",
"merchantReference": "order_123",
"status": "completed",
"amount": "250.00",
"serviceFee": "7.50",
"currencyCode": "ETB",
"paymentMethod": "telebirr",
"customer": {
"name": "Abebe Bikila",
"email": "abebe@example.com",
"phone": "+251911234567"
},
"paidAt": "2026-08-13T11:47:00.000Z",
"createdAt": "2026-08-13T11:30:00.000Z"
}Path Parameters
Prop
Type
Response
Prop
Type
Errors
| Status | Description |
|---|---|
400 | Transaction is not yet completed (message includes the current status). |
401 | Missing or invalid API key. |
404 | No transaction found for the given reference under your account. |
Next: Cancel a Payment — void a pending session.