Customers API
These endpoints let a signed-in person find a customer and read everything SpeculaPro knows about them: their profile, accounts, designations, recent transactions, a 90-day activity summary and any suppressions. The Customers screens use them; this page is for scripting and for checking exactly what is returned.
Customers are sent to SpeculaPro by your systems through the ingest API, not created here. See Sending customers.
Before you start
Section titled “Before you start”Who can call them. These endpoints are for signed-in people, not API keys. Every request is
checked against the caller’s permissions, and every view of protected personal data is written to
the audit log. An API key gets 401 sign in required. A person whose account
setup isn’t finished (two-factor enrolment or a forced password change) gets
403 complete account setup first.
Signing in with curl. Sign in once and keep the session cookie in a file, exactly as described in Alerts and cases API: before you start:
export SP=https://speculapro.example.com
curl -s -c ~/.sp-cookies -H 'Content-Type: application/json' \ -d '{"workspace":"acme-pay","email":"[email protected]","password":"<your password>","totp_code":"123456"}' \ "$SP/api/v1/auth/login"Then add -b ~/.sp-cookies to every request below.
Conventions. IDs are UUIDs. Times are RFC 3339 in UTC. Money is an integer in minor units:
495000 is GHS 4,950.00. Amounts named …_base_minor are in your workspace’s base currency.
Endpoints at a glance
Section titled “Endpoints at a glance”| Endpoint | Does | Permission | Success |
|---|---|---|---|
GET /api/v1/customers |
Find customers by reference or name | entities.view |
200 |
GET /api/v1/customers/{id} |
One customer’s full profile | entities.view (+ entities.view_pii for protected fields) |
200 |
Who sees what
Section titled “Who sees what”| Permission | Default roles | What it shows |
|---|---|---|
entities.view |
Analyst, Senior analyst, MLRO, Rule author, Auditor | Names, references, segment, risk rating, accounts (with masked identifiers), designations, transactions, activity, suppressions |
entities.view_pii |
Senior analyst, MLRO | Also the protected fields: phone, email, national ID and date of birth, decrypted |
The protected fields are encrypted in the database (see Data protection).
They are decrypted only for a caller with entities.view_pii, and a profile view with them decrypted
writes a customer.view_pii entry to the audit log, with who looked, when and from where. To keep
the log readable, repeat views of the same customer by the same person within 30 minutes (for
example the page refreshing) don’t add another entry; the next view after that does.
Find customers
Section titled “Find customers”GET /api/v1/customers
Section titled “GET /api/v1/customers”| Query parameter | Meaning |
|---|---|
q |
Up to 128 characters. Matches your customer reference exactly, or part of the name or reference, ignoring capitals. Empty means everyone |
designated |
true returns only customers with an active designation (PEP, sanctioned, high risk, …) |
limit |
1 to 200; default 50 |
Results come in this order: an exact reference match first, then customers rated unacceptable,
then high, then the most recently updated.
Each result:
| Field | Meaning |
|---|---|
id |
SpeculaPro’s ID for the customer. Use it in the other endpoints |
external_id |
Your reference for the customer |
name |
Full name, or your reference if no name was sent |
type |
individual or business |
status |
As sent by your systems, for example active |
segment |
As sent, for example retail; empty if none |
risk_rating |
unrated, low, medium, high or unacceptable |
kyc_level |
KYC tier as sent; left out if none |
designations |
Types of the customer’s active designations, for example ["pep"] |
open_alerts |
Alerts about this customer still open |
active_cases |
Cases about this customer not yet closed |
# By your referencecurl -s -b ~/.sp-cookies "$SP/api/v1/customers?q=CUS-004417"
# Everyone with an active designationcurl -s -b ~/.sp-cookies "$SP/api/v1/customers?designated=true&limit=200"Read a customer’s profile
Section titled “Read a customer’s profile”GET /api/v1/customers/{id}
Section titled “GET /api/v1/customers/{id}”Returns every field from the search result, plus:
| Field | Meaning |
|---|---|
country, nationality, occupation |
As sent; left out if none |
declared_monthly_volume_minor, declared_currency |
The expected monthly volume from onboarding, if sent |
onboarded_at |
When the relationship started, if sent |
attributes |
Your custom attributes, as sent |
pii |
The protected fields; see below |
accounts |
Every account: id, external_id, type, provider, identifier_mask (for example +233•••••••67), currency, status, opened_at |
designation_history |
Every designation, newest first, including revoked and expired ones. See below |
transactions |
The most recent 50 transactions in the last 90 days |
activity_90d |
Totals over the last 90 days of completed transactions |
suppressions |
Suppressions whose subject is this customer, in every state, including counterparty pairs. Fields as in the Suppressions API |
counterparties |
Who the customer dealt with most in the last 90 days, up to 20. See below |
devices |
Devices the customer has used, most recently used first, up to 20. See below |
account_events |
The latest account events from the last 90 days, newest first, up to 30. See below |
last_transaction_at |
The latest completed transaction in the last 90 days; left out if none |
pii
| Field | Meaning |
|---|---|
visible |
true if you have entities.view_pii. When false, the fields below are left out |
phone, email, national_id, national_id_type, date_of_birth |
Decrypted values, left out if not on file. date_of_birth is YYYY-MM-DD |
If a value can’t be decrypted (for example after a key was rotated incorrectly), it reads
[unreadable]. Tell your administrator: see Data protection.
designation_history entries: id, type, pep_class, source (manual today), reason,
valid_from, valid_to, created_by and created_at, evidence (sources, reference and
notes, each left out when empty; see Designations API),
and for revoked ones revoked_at, revoked_by and revoke_reason. active is true while it is not revoked and inside its
validity dates. created_by and revoked_by are display names.
transactions entries: id, external_id, occurred_at, direction (in or out), type,
channel, status, amount_minor and currency as sent, amount_base_minor in your base
currency, counterparty (name or masked identifier, if known) and flagged: true if a live
rule hit this transaction.
counterparties entries, most transactions first: id (use it as counterparty_id in a
counterparty-pair suppression), name (the
counterparty’s name, else its masked identifier, else Unknown counterparty), identifier_mask
and provider when known, count (transactions with them in the last 90 days, in any status),
in_minor and out_minor (money from and to them, in base currency) and last_at (the latest
transaction with them).
devices entries: id (the first 12 characters of the device’s keyed hash, the same for
the same device on every customer), first_seen_at and last_seen_at (this customer’s first and
latest use of it), and customers (how many customers have used it in total, this one included;
more than 1 means a shared device). Devices aren’t limited to the last 90 days. Empty if your
systems don’t send device_fingerprint.
account_events entries: type (such as sim_swap or otp_failed), occurred_at, and when
sent, channel, success and device (the device’s 12-character code, as in devices). The
other fields you send with an event are stored but not returned here.
activity_90d: in_minor and out_minor (completed money in and out, in base currency),
count (completed transactions) and flagged (distinct transactions with a live rule hit on
this customer).
curl -s -b ~/.sp-cookies "$SP/api/v1/customers/0192f3a4-5b6c-7d8e-9f01-23456789abcd"Errors
Section titled “Errors”| Status | Meaning | Example |
|---|---|---|
401 |
Not signed in, or called with an API key | sign in required |
403 |
Missing permission | missing permission entities.view |
404 |
No such customer in your workspace. Another workspace’s customers always look like this | not found |
422 |
Invalid parameters, such as a limit above 200 |
Lists each problem |
How to look into a customer before deciding an alert
Section titled “How to look into a customer before deciding an alert”- Find them. Search by the reference shown on the alert:
GET /api/v1/customers?q=CUS-004417. Note theid. - Read the profile:
GET /api/v1/customers/{id}. - Compare with what you expected. Is
activity_90d.in_minorin line withdeclared_monthly_volume_minor× 3? How many of the recenttransactionsareflagged? - Check the flags. Look at
designation_historyfor active PEP or sanctions flags, and atsuppressionsfor any exception already approved for this customer. - Record what you found as a note on the case. See Working a case.