Skip to content

Records

List transactions in a creation-date window for bulk reconciliation. Results are paged using an opaque cursor so merchants can safely page through large result sets without losing consistency if transactions are created or updated during paging.

Use this endpoint to reconcile your ledger against PayAlo in a single pass. For per-transaction lookups, use Payment Status.


Endpoint

GET /gateway/mmo/v2/records
Header Required Description
X-Api-Key Yes Your API key

When to Use

  • Bulk reconciliation — pull every transaction in a daily/hourly window and diff against your ledger.
  • Backfill — catch up after a callback endpoint outage.
  • Audit — export all transactions created between two points in time.

For near-real-time status checks on a specific transaction, prefer Payment Status.


Query Parameters

Parameter Type Required Default Description
from string (ISO 8601) Yes Start of the creation-date window
to string (ISO 8601) Yes End of the creation-date window
type string No Filter by type: payin, payout, tax
method string No Filter by payment method key (e.g. mpesa-ke, airtel-ug)
status string No Filter by status: pending, success, failed
pageSize integer No 50 Items per page; values outside 1..5000 are clamped to the nearest bound.
page string No Pagination cursor from a previous response (see Pagination). When set, the cursor reuses the original filter values; you should send only the page parameter on follow-up calls.

Constraints

  • to must be strictly greater than from. Equal values return 400 with detail "'to' must be later than 'from'.".
  • String parameters are trimmed; whitespace-only values are treated as absent.
  • type and status are case-insensitive; method is case-sensitive.

Practical limit on window size: there is no hard server-side cap on to − from, but very wide windows degrade response time and consume more pages. Keep the window narrow (a few hours to a day) for routine reconciliation. See Best Practices.

Example Request

GET /gateway/mmo/v2/records?from=2024-06-01T00:00:00Z&to=2024-06-02T00:00:00Z&status=success&pageSize=100 HTTP/1.1
Host: api.payalo.com
X-Api-Key: <your-api-key>

Response

Success — 200 OK

Field Type Description
data array of Mmo Transaction Transactions created within the window that match the filters. Empty array if nothing matched.
pages.next string | null Cursor for the next page; null when there are no more results.
pages.previous string | null Cursor for the previous page; null when on the first page.

Example Response

{
  "data": [
    {
      "status": "success",
      "type": "payin",
      "flow": "direct",
      "gatewayReference": "b2p01j3abcdef0000000000000000a1b2",
      "merchantReference": "dep-20240601-001",
      "reconciliationReference": "INV-2024-001",
      "providerReference": "MPESA-REC-99887766",
      "party": {
        "id": "user-42",
        "msisdn": "+254712345678",
        "firstName": "Jane",
        "lastName": "Doe",
        "email": "[email protected]"
      },
      "method": "mpesa-ke",
      "country": "KE",
      "requestedAmount": { "value": 500.00, "currency": "KES" },
      "finalAmount":     { "value": 500.00, "currency": "KES" },
      "labels": { "orderId": "ORD-2024-001" },
      "createdAt": "2024-06-01T12:34:56.000000Z",
      "completedAt": "2024-06-01T12:36:30.000000Z",
      "completionSource": "webhook",
      "errorCode": null,
      "errorMessage": null,
      "providerData": {
        "name": "mpesa",
        "title": "M-Pesa Kenya",
        "fee": { "value": 10.00, "currency": "KES" },
        "partyData": null,
        "errorCode": null,
        "errorMessage": null
      }
    }
  ],
  "pages": {
    "next": "eyJwYWdlIjoyLCJmcm9tIjoiMjAyNC0wNi0wMVQwMDowMDowMFoiLCJ0byI6IjIwMjQtMDYtMDJUMDA6MDA6MDBaIn0",
    "previous": null
  }
}

Pagination

The endpoint uses opaque cursor-based pagination. Each response returns pages.next and pages.previous cursors; to retrieve another page, send the cursor back as the page query parameter.

GET /gateway/mmo/v2/records?from=...&to=...&page=eyJwYWdlIjoyLC... HTTP/1.1

Cursor Stability

The cursor encodes the original query parameters (from, to, type, method, status, pageSize). When you page through results, those parameters must remain unchanged:

  • Preferred: send only the page parameter on follow-up calls; the cursor carries everything else.
  • If you do resend the filters, they must match the original call byte-for-byte (after trimming/case-folding).
  • Changing any filter invalidates the cursor and returns a 400 Bad Request. Start a new query from page one.

No Results

If the filters match no transactions, the response is:

{
  "data": [],
  "pages": { "next": null, "previous": null }
}

Error Responses

HTTP Status Error Code Scenario
400 validation_failed to ≤ from, unknown type/status value, or cursor mismatch
401 unauthorized API key is missing or invalid

See Error Handling for the full error response structure.

Example — Invalid Window

{
  "type": "https://docs.payalo.com/errors/validation_failed",
  "title": "Validation failed",
  "status": 400,
  "detail": "'to' must be later than 'from'.",
  "errorCode": "validation_failed"
}

Example — Unknown Type

{
  "type": "https://docs.payalo.com/errors/validation_failed",
  "title": "Validation failed",
  "status": 400,
  "detail": "'type' must be one of: payin, payout, tax.",
  "errorCode": "validation_failed"
}

Type Values

Value Description
payin Deposit (funds from end user to merchant)
payout Withdrawal (funds from merchant to end user)
tax Tax authority payout

Status Values

Value Description
pending Transaction is still being processed
success Transaction completed successfully
failed Transaction reached a terminal failure state

Best Practices

  • Page server-side, not client-side. Request what you need per page (pageSize up to 5000) and follow pages.next. Don't client-side filter a large window.
  • Narrow the window. For periodic reconciliation, fetch small windows (e.g. one hour). Wide windows produce more pages, take longer overall, and degrade more sharply on retry.
  • Checkpoint progress. Persist the last from you successfully reconciled so you can resume on failure without re-paging the whole window.
  • Treat the gateway as source of truth. If your ledger and the gateway disagree, update your ledger to match — see Reconciliation.
  • Handle push transactions defensively. Records with flow: "push" (provider-initiated offline deposits) carry merchantReference: null, reconciliationReference: null, and labels: null — there was no merchant request to populate them. Match these to your ledger via gatewayReference or providerReference instead.