Getting Started with Rose API
This page will help you get started with the Axle API for Rose, our transaction monitoring agent. You'll upload entities, transactions and alerts for Rose to analyze, plus, optionally, the bank accounts, cards and devices your customers use.
Getting Started
Base URL
https://public.api.axleruns.com/api/v1/
Authentication
Obtain API Key
Please obtain an API key and set it in the X-API-Key header.
Go to the Settings menu, and navigate to the API KEYS tab, and click on the "Generate Key" Button.
Include your API key in the request header:
X-API-Key: your-api-key-here
Content Type
All requests must use application/json
Core Concepts
Data Relationships
The system works with these interconnected data types:
- Entities: Your customers (individuals or businesses)
- Instrument links: The bank accounts and cards your customers hold
- Device links: The devices your customers use
- Transactions: Financial activities
- Alerts: Suspicious activity flags referencing transactions and entities
The detailed data model is described in API Reference.
Here's how they connect:
- Each transaction must reference at least one entity (sender, receiver, or both)
- Alerts reference one or more transactions and the entities involved
- Entities can appear across multiple transactions and alerts
- Each instrument link or device link belongs to one entity. When several entities share the same bank account, card or device, Rose uses that sharing in its investigations.
Upload Sequence
Upload data in this order:
- Entities → Upload your customer data first
- Instrument and device links (optional) → The bank accounts, cards and devices each entity holds or uses (references entities)
- Transactions → Upload transaction data (references entities)
- Alerts → Upload alerts last, after all other data (references both transactions and entities)
Each step refers to data from the steps before it. An alert is checked against the entities you've already uploaded and is rejected if any are missing.
Instrument and device links are the exception. A link naming an entity that hasn't arrived yet is stored and reported back in unresolved_entity_source_ids, and attaches once the entity is uploaded. Rose can't use it until then, so upload entities first anyway.
Instrument and device links are optional. Send them if you have them, since they let Rose see when entities share an account, card or device.
Working with Entities
Upload Entities
Upload your customer data directly via API. Maximum 500 entities per request.
Endpoint: POST /api/v1/transaction-monitoring/entities
Request Body:
{
"entities": [
{
"entity_id": "cust-12345",
"type": "INDIVIDUAL",
"name": "John Smith"
}
]
}Response:
{
"success": true,
"processed": 1,
"errors": []
}Entity Requirements
entity_id: Your unique identifier for this customertype: Either "INDIVIDUAL" or "BUSINESS"- Additional fields as per your data model
Working with Instruments and Devices
If you have bank account, card or device data for your customers, tell Axle which accounts and cards each entity holds and which devices it uses. These uploads are optional; send whichever you have. Each item is one entity's link to one instrument or device. Sending a link again updates it instead of creating a duplicate. Instrument links are matched on link_source_id, or without one, on the instrument and entity. Device links are matched on the entity and device_external_id. Maximum 1,000 links per request.
Upload Instrument Links
Endpoint: POST /api/v1/transaction-monitoring/instrument-links
Request Body:
{
"instrument_links": [
{
"entity_source_id": "cust-12345",
"instrument_kind": "BANK_ACCOUNT",
"link_source_id": "link-789",
"instrument": {
"instrument_value": "ptok_8f2c41",
"last4": "4242",
"institution_id": "ins_109508"
},
"first_seen_at": "2026-09-01T10:00:00Z",
"token_kind": "PERSISTENT_ACCOUNT_TOKEN",
"observed_in": "LINK"
}
]
}Upload Device Links
Endpoint: POST /api/v1/transaction-monitoring/device-links
Request Body:
{
"device_links": [
{
"entity_source_id": "cust-12345",
"device_external_id": "device-a1b2c3",
"platform": "iOS",
"first_seen_at": "2026-09-01T10:00:00Z",
"last_seen_at": "2026-10-01T08:30:00Z"
}
]
}Response (both endpoints):
{
"status": "completed",
"received": 1,
"links_written": 1,
"unresolved_entity_source_ids": []
}status:completedwhen every link was writtenreceived: The number of items in the requestlinks_written: The number of links stored. Lower thanreceivedwhen a request sends the same link more than once, since only the last copy is kept.unresolved_entity_source_ids: Entities named by a link that haven't been uploaded yet. Those links are stored and attach once the entity arrives.
Each request is all-or-nothing. A 422 (validation error, naming the field) or a 500 means nothing was stored, so fix the problem and resend the whole request.
Instrument and Device Requirements
entity_source_id: Theentity_idof the entity holding the instrument or using the deviceinstrument_kind: Either "BANK_ACCOUNT" or "CARD"- An instrument link needs a
link_source_id, aninstrument, or both. Omitinstrumentfor a link whose account or card token you don't have. instrument.instrument_value: The token identifying the account or card. Use the same value for the same real account or card across all entities, so Axle can see it is shared.- The
instrumentfields must matchinstrument_kind. Bank-account fields (routing_number,institution_id,account_type,account_subtype,is_joint) are rejected on aCARDlink, and card fields (card_brand,card_type,card_bin,card_network) are rejected on aBANK_ACCOUNTlink. token_kindapplies toBANK_ACCOUNTlinks only and is rejected on cards.device_external_id: Your id for the device. Use the same value for the same physical device across all entities.- Leaving a link out of an upload does not remove it. To mark an instrument link removed, send it again with
source_removed: true(andsource_removed_atif you know when). - Datetimes without a timezone are read as UTC.
- Unknown fields are rejected, so a misspelled field name returns an error instead of being dropped
Working with Transactions
Upload Process
Transactions follow a two-step process due to potentially large data volumes:
- Get a pre-signed upload URL
- Upload your transaction file to that URL
Step 1: Get Upload URL
Endpoint: POST /api/v1/transaction-monitoring/transactions/upload-via-url
Request:
{
"format":"json"
}Response:
{
"upload_uri": "https://...",
"session_id": "ed9feaca-d877-4dcd-ab6e-dcda2a8e7f07",
"expires_at": "2028-09-15T10:00:00Z"
}Step 2: Upload File
See full reference example here uploading-transaction-payloads-to-gcs
curl -X PUT \
"your-upload-url-here" \
-H "Content-Type: application/json" \
-d @transactions.jsonTransaction Data Format
Your transaction file should contain an array of transaction objects:
[
{
"transaction_id": "txn-001",
"type": "DEPOSIT",
"event_time": "2024-01-10T14:30:00Z",
"amount": "1500.00",
"amount_currency": "USD",
"sender": {
"entity_id": "cust-12345",
"asset_out": {
"amount": "1500.00",
"currency_id": 840,
"currency_type": "fiat",
}
},
"receiver": {
"entity_id": "cust-67890"
}
}
]Key Transaction Fields
Required:
transaction_id: Your unique transaction identifierevent_time: ISO8601 datetime (YYYY-MM-DDTHH:MM:SS or YYYY-MM-DDTHH:MM:SSZ)amount: Transaction value as decimal string (e.g., "1234.56")amount_currency: Currency code (see currency reference endpoints)
Conditional Requirements:
- For crypto deposits:
receiver_blockchain_addressesorsender_blockchain_addressesis required - When specifying currency: Both
sent_currencyandsent_currency_typemust be provided together sender_idandsender_nameare mutually exclusive (use one or the other). Usesender_idwhen you are referencing an entity from prior API calls. Usesender_namewhen the transaction counterparty is not defined in your system, like a merchant name.receiver_idandreceiver_nameare mutually exclusive (use one or the other). Usereceiver_idwhen you are referencing an entity from prior API calls. Usereceiver_namewhen the transaction counterparty is not defined in your system, like a merchant name.
Currency Handling
You'll need to use our numeric currency codes. Get the full list from:
- Crypto:
GET /api/v1/crypto/crypto-assets - Fiat:
GET /api/v1/crypto/fiat-currencies - Chains:
GET /api/v1/crypto/crypto-chains
Example response:
{
"items": [
{"id": 840, "symbol": "USD", "name": "US Dollar"},
{"id": 978, "symbol": "EUR", "name": "Euro"}
],
"total": 150,
"page": 1
}Working with Alerts
Upload Alerts
Submit alerts with optional execution trigger. Maximum 100 alerts per request.
Endpoint: POST /api/v1/transaction-monitoring/alerts
Request:
{
"alerts": [
{
"alert_id": "alert-001",
"entity_id_list": ["cust-12345"],
"flagged_transaction_id_list": ["txn-001", "txn-002"],
"created_at": "2024-01-10T15:00:00Z"
}
],
"trigger_execution": true
}Response:
{
"success": true,
"processed": 1,
"execution_triggered": true
}Alert Requirements
- Must reference valid entity IDs and transaction IDs
- At least one transaction must be flagged
- Setting
trigger_execution: truecauses alerts to be processed immediately. If set to false, alerts can be triggered via the UI or the API (see next section). Ask Axle personnel if you need further assistance.
Trigger Alert Investigation
Initiate Rose investigation for specified alert IDs. Maximum 1000 alerts per request.
Endpoint: POST api/v1/transaction-monitoring/alerts/investigate
Request:
{
"alert_ids": ["ALERT-17145", "ALERT-17146"]
}An optional run_at field may be supplied which will cause Rose to run the investigation(s) at that time in the future rather than immediately. This field is formatted as RFC 3339 / ISO 8601 with a UTC offset.
Retrieving Results
Get Investigation Details
After processing, retrieve detailed risk assessments:
Endpoint: GET /api/v1/transaction-monitoring/investigation/{investigation_id}
Response:
{
"rose_investigation_id": "inv-12345",
"processing_status": "completed",
"risk_score": 0.75,
"disposition": "escalate"
}Submit Feedback
Provide feedback on investigation outcomes:
Endpoint: POST /api/v1/transaction-monitoring/rose-alert-feedback/
Request:
{
"investigation_feedback_items": [
{
"investigation_id": "inv-12345",
"status": "ESCALATED"
}
]
}Error Handling
The API uses standard HTTP status codes:
200: Success400: Bad request (check your parameters)401: Authentication failed422: Validation error (check data format)500: Server error (retry with exponential backoff)
Error responses include details:
{
"error": "validation_error",
"message": "Invalid entity_id format",
"details": {
"field": "entity_id",
"value": "invalid-id"
}
}Best Practices
- Batch Operations: Use maximum batch sizes to reduce API calls
- Error Recovery: Implement retry logic with exponential backoff
- Webhooks: Set up webhook endpoints to receive processing notifications
- Data Validation: Validate data locally before submission to avoid errors
- Idempotency: Use consistent IDs to prevent duplicate submissions
Testing
Start with small data sets to verify your integration:
- Upload 2-3 test entities
- (Optional) Link 1-2 bank accounts, cards or devices to a test entity
- Upload 5-10 test transactions
- Create 1-2 test alerts
- Verify the investigation results
Updated 14 days ago
