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:

  1. Entities → Upload your customer data first
  2. Instrument and device links (optional) → The bank accounts, cards and devices each entity holds or uses (references entities)
  3. Transactions → Upload transaction data (references entities)
  4. 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 customer
  • type: 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: completed when every link was written
  • received: The number of items in the request
  • links_written: The number of links stored. Lower than received when 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: The entity_id of the entity holding the instrument or using the device
  • instrument_kind: Either "BANK_ACCOUNT" or "CARD"
  • An instrument link needs a link_source_id, an instrument, or both. Omit instrument for 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 instrument fields must match instrument_kind. Bank-account fields (routing_number, institution_id, account_type, account_subtype, is_joint) are rejected on a CARD link, and card fields (card_brand, card_type, card_bin, card_network) are rejected on a BANK_ACCOUNT link.
  • token_kind applies to BANK_ACCOUNT links 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 (and source_removed_at if 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:

  1. Get a pre-signed upload URL
  2. 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.json

Transaction 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 identifier
  • event_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_addresses or sender_blockchain_addresses is required
  • When specifying currency: Both sent_currency and sent_currency_type must be provided together
  • sender_id and sender_name are mutually exclusive (use one or the other). Use sender_id when you are referencing an entity from prior API calls. Use sender_name when the transaction counterparty is not defined in your system, like a merchant name.
  • receiver_id and receiver_name are mutually exclusive (use one or the other). Use receiver_id when you are referencing an entity from prior API calls. Use receiver_name when 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: true causes 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: Success
  • 400: Bad request (check your parameters)
  • 401: Authentication failed
  • 422: 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

  1. Batch Operations: Use maximum batch sizes to reduce API calls
  2. Error Recovery: Implement retry logic with exponential backoff
  3. Webhooks: Set up webhook endpoints to receive processing notifications
  4. Data Validation: Validate data locally before submission to avoid errors
  5. Idempotency: Use consistent IDs to prevent duplicate submissions

Testing

Start with small data sets to verify your integration:

  1. Upload 2-3 test entities
  2. (Optional) Link 1-2 bank accounts, cards or devices to a test entity
  3. Upload 5-10 test transactions
  4. Create 1-2 test alerts
  5. Verify the investigation results

Did this page help you?