Transactions API
GET /api/v1/transactions searches recent transactions, newest first, and says which live rules
hit each one. The Transactions screen uses it; this page is for
scripting, for example exporting a customer’s activity for a case file.
Transactions are sent to SpeculaPro through the ingest API or a file import. This endpoint only reads them.
Before you start
Section titled “Before you start”Who can call it. A signed-in person with entities.view (by default Analyst, Senior
analyst, MLRO / Compliance officer, Rule author and Auditor). An API key gets
401 sign in required; a person without the permission gets 403 missing permission entities.view.
Signing in with curl. Sign in once and keep the session cookie in a file, as described in
Alerts and cases API: before you start, then add
-b ~/.sp-cookies to the requests below.
GET /api/v1/transactions
Section titled “GET /api/v1/transactions”| Parameter | Default | Meaning |
|---|---|---|
q |
A transaction external_id or a customer external_id (both exact matches), or part of a customer’s name (case-insensitive). Up to 128 characters |
|
flagged |
false |
true returns only transactions a live rule hit |
direction |
in, out or internal |
|
channel |
One channel, such as momo or agent. See channels. An unknown channel simply matches nothing |
|
days |
7 |
How far back to look, from 1 to 90 days before now |
before |
A cursor: only transactions that happened before this time (RFC 3339). Use it to page; see below | |
before_id |
The id of the last row of the previous page. Send it together with before, so rows with the same time are neither skipped nor repeated |
|
limit |
100 |
How many to return, from 1 to 200 |
Results are ordered by when the transaction happened, newest first. Values outside the allowed
ranges are refused with 422.
Response: 200 OK
Section titled “Response: 200 OK”An array of transactions:
[ { "id": "01a12015-7c3e-7a1b-9e2f-5b8d0c4e1a77", "external_id": "demo-00405", "occurred_at": "2026-10-09T04:17:00Z", "direction": "in", "type": "cash_in", "channel": "agent", "status": "completed", "amount_minor": 975000, "currency": "GHS", "amount_base_minor": 975000, "counterparty": "Agent 44 · Kejetia", "flagged": true, "customer_id": "01a12015-02ab-7f10-8c2d-6e4b1a9d3c55", "customer_name": "Kwame Asante", "rules": ["B1"] }]| Field | Meaning |
|---|---|
id |
SpeculaPro’s identifier for the transaction |
external_id |
Your reference for it |
occurred_at |
When it happened, in UTC |
direction, type, channel, status |
As sent. See Transactions |
amount_minor, currency |
The amount in minor units of the transaction’s currency (pesewas for GHS) |
amount_base_minor |
The same amount converted to your workspace’s base currency |
counterparty |
The other side’s name, or their masked identifier if no name was sent. Absent when there is no counterparty |
flagged |
true when at least one live rule version hit it. Shadow-test hits don’t count; hits that didn’t raise an alert (a suppressed hit, or a rule that only records) do |
customer_id |
SpeculaPro’s identifier for the customer, for GET /api/v1/customers/{id}. Absent when the transaction has no customer |
customer_name |
The customer’s name, or their external_id if no name was sent |
rules |
The library keys (or, for custom rules, the keys) of the live rules that hit it. Empty when not flagged |
Paging through more results
Section titled “Paging through more results”To read more than limit transactions, pass the occurred_at and id of the last transaction
you received as before and before_id on the next request, and stop when a page comes back
shorter than limit:
curl -s -b ~/.sp-cookies "$SP/api/v1/transactions?q=C-001&days=90&limit=200"# then, with the last row's occurred_at and id:curl -s -b ~/.sp-cookies --get \ --data-urlencode "before=2026-08-14T10:02:11Z" \ --data-urlencode "before_id=01a12035-7c1e-7d40-9a51-6c0f3e2b8d17" \ "$SP/api/v1/transactions?q=C-001&days=90&limit=200"Transactions that happened at exactly the same time are never skipped or repeated: the cursor is
the pair (occurred_at, id), so always send both values from the last row.
--data-urlencode matters: the + in a time zone offset such as +00:00 would otherwise arrive as
a space.
Errors
Section titled “Errors”| Status | When |
|---|---|
401 |
Not signed in, or an API key |
403 |
Missing entities.view, or account setup not finished |
422 |
A parameter outside its allowed values, such as days=120 or direction=debit |