Payments

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

raw HTTP
npm install @e-pay/node
npm install @e-pay/nestjs
pip install epay
pip install epay
pip install epay
pip install epay
composer require epay-et/php-sdk
composer require epay-et/php-sdk
implementation("com.epayethiopia:epay-java:0.1.0")
implementation("com.epayethiopia:epay-spring-boot-starter:0.1.0")
go get github.com/epay-et/go-sdk

Nothing 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

StatusDescription
400Transaction is not yet completed (message includes the current status).
401Missing or invalid API key.
404No transaction found for the given reference under your account.

Next: Cancel a Payment — void a pending session.

On this page