Payment Instruments
Link and manage payment instruments for users. Our payment instrument tracking system helps detect and prevent:
- Account takeover attempts through unusual payment method additions
- Card stuffing attacks using stolen card information
- Suspicious linking patterns across multiple accounts
- Unusual payment method usage patterns
- Shared instruments across mule networks
Payment instruments can either be created and marked as “linked” or “unlinked” explicitly, otherwise they will be inferred from transaction details.
Link Payment Instrument
Endpoint
PUT /v1/paymentInstrumentRequest Schema
The paymentInstrument object must be a nested object with the appropriate item subfields for the given payment method.
| Field | Type | Required | Description |
|---|---|---|---|
status | enum | Yes | Instrument status: linked, unlinked |
paymentInstrument.id | string | Yes | Unique payment instrument identifier |
paymentInstrument.userId | string | Yes | User identifier |
paymentInstrument.provider | string | No | Provider of specific payment instrument, eg stripe, onafriq |
paymentInstrument.method | enum | No | Payment method type: bank, card, wallet, crypto, vas, ewa, cash |
paymentInstrument.payInMethod | boolean | No | Whether instrument can be used for pay-ins |
paymentInstrument.payOutMethod | boolean | No | Whether instrument can be used for pay-outs |
timestamp | number | No | Unix epoch milliseconds. Must not be in the future. |
updatedAt | number | No | Last update timestamp in milliseconds. Defaults to the current time if omitted |
Payment Method Details
We cover most major payment instrument types such as bank, card, wallet and crypto.
Bank Details Schema
| Field | Type | Description |
|---|---|---|
id | string | Unique identifier for bank instrument |
accountNumber | string | Bank account number |
routingNumber | string | Bank routing number (ACH) |
currency | string | Currency code of the account |
ibanFull | string | Full IBAN number for international payments |
sortCode | string | UK sort code if applicable |
accountType | string | Type of account (checking/savings) |
accountHolderName | string | Name of the account holder |
bankName | string | Name of the bank |
bankBranch | string | Name of the bank branch |
bankBranchCode | string | Code identifying the specific bank branch |
Card Details Schema
We currently cover both physical and digital cards (e.g Apple Pay and Google Pay). If you need additional identifiers for products such as virtual cards and accounts, please contact support@orca-fraud.com
| Field | Type | Description |
|---|---|---|
id | string | Provider-specific identifier |
bin | string | First 6 digits of card |
binCountry | string | Country of card issue |
currency | string | Card currency |
brand | string | Card brand |
last4 | string | Last 4 digits |
isDigitalWallet | boolean | Digital wallet flag |
fingerprint | string | Unique tokenized identifier |
digitalWalletType | string | Type of digital wallet if applicable |
digitalWalletToken | string | Token or identifier from digital wallet if applicable |
Wallet Details Schema
Support for various wallet types, such as:
- PIX (Brazil)
- M-PESA (Kenya)
| Field | Type | Description |
|---|---|---|
tokenBrand | string | Wallet brand (e.g. pix) |
type | string | Wallet type: pix, phone |
phone | string | Associated phone number |
country | string | Country code |
phoneProvider | string | Mobile provider for onafriq |
currency | string | Wallet currency |
pixKey | string | PIX key for dLocal |
taxNumberId | string | Tax ID for dLocal |
Example Request
{
"status": "linked",
"paymentInstrument": {
"id": "pi_123456",
"userId": "user_123",
"provider": "dlocal",
"method": "bank",
"payInMethod": true,
"payOutMethod": true,
"bank": {
"accountNumber": "1234567890",
"accountHolderName": "John Doe",
"bankName": "Test Bank",
"bankBranchCode": "001",
"currency": "USD"
}
},
"timestamp": 1734167723000
}Crypto Details Schema
We also support crypto payment instruments and can offer additional crypto-specific fields on these.
Response
The response is a risk assessment for the payment instrument, in the same shape as the transaction screening response.
| Field | Type | Description |
|---|---|---|
id | string | The payment instrument identifier you submitted |
riskLevel | enum | Risk assessment: low, medium_low, medium, high, very_high, n/a |
recommendedAction | enum | Suggested action: ALLOW, REVIEW, BLOCK, STEP_UP_AUTH, STEP_UP_KYC, STEP_UP_ID, FLAG_FOR_MONITORING, REPORT_SUSPICIOUS, MESSAGE_USER, MESSAGE_MERCHANT |
triggered | array | Rules that triggered, empty if none |
timestamp | number | Unix epoch milliseconds |
walletVerification | object | Wallet ownership verification result. Only present for clients with wallet verification enabled, contact support@orca-fraud.com |
{
"id": "pi_123456",
"riskLevel": "low",
"recommendedAction": "ALLOW",
"triggered": [],
"timestamp": 1734167723000
}Note: Payment instrument rules are enabled per client. Where they are not enabled, the response still returns this shape with
riskLevellow,recommendedActionALLOWand an emptytriggeredarray.
Responses
200: Payment instrument processed400: The payment instrument could not be processed401: Unauthorized500: Internal server error
Get Payment Instrument
Retrieve the current risk assessment for a payment instrument that has already been submitted.
Endpoint
GET /v1/paymentInstrument/{id}Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Payment instrument identifier |
Response
Same shape as the PUT response above. triggered is empty on this endpoint — rules are not
re-evaluated on read.
{
"id": "pi_123456",
"riskLevel": "low",
"recommendedAction": "ALLOW",
"triggered": [],
"timestamp": 1734167723000
}Responses
200: Payment instrument returned400:idis missing or empty401: Unauthorized404: Payment instrument not found500: Internal server error
Error Response Format
See the Error Reference section for a full description of API errors. All API errors follow a consistent JSON structure:
{
"error": {
"type": "ERROR_TYPE",
"message": "Human-readable error description",
"details": ["Additional error details (optional)"]
},
"timestamp": 1755602195137
}In the case of a validation error, the format will be as follows:
{
"error": {
"type": "VALIDATION_ERROR",
"message": "Request validation failed",
"details": [
"/id: Expected string"
]
},
"timestamp": 1755602195137
}