WebSockets

The WebSocket API allows you to receive real-time updates about invoice status changes and payment events.

Connecting to the WebSocket

To connect to the WebSocket for a specific invoice, use the following URL:

wss://api.splitroute.com/api/v1/ws/invoices/{invoice_id}

Replace {invoice_id} with the ID of the invoice you want to monitor.

Message Format

Messages sent through the WebSocket are in JSON format with a standardized structure:

JSON
1{
2 "timestamp": "2025-03-31T09:18:11.897603+00:00",
3 "message_type": "invoice",
4 "category": "updated",
5 "payload": {
6 "id": "INV_2025_03_62fcb6bc256f6fad7622",
7 "timestamp": "2025-03-31T09:18:11.890364+00:00",
8 "event_type": "invoice.paid",
9 "unit_amount": "2000000000000000000000000",
10 "formatted_amount": "0.000002",
11 "nominal_amount": "0.000002",
12 "is_paid": true,
13 "is_expired": false,
14 "currency": "EUR",
15 "exchange_rate": "0.8221560000"
16 }
17}

Top-Level Fields

FieldTypeDescription
timestampstringISO format timestamp when the message was sent (includes timezone information)
message_typestringEither "invoice" or "payment"
categorystringEvent category: "updated", "completed", "failed", or "payment"
payloadobjectContains event-specific data

Payload Fields

The payload contains a set of fields that vary depending on the event type. All events share these common fields:

FieldTypeDescription
idstringInvoice ID (format: INV_YYYY_MM_[alphanumeric string])
timestampstringISO format timestamp for the event (includes timezone information)
event_typestringOriginal event type (e.g., "invoice.paid")
unit_amountstringRaw amount in nano units (meaning depends on event type)
formatted_amountstringHuman-readable amount in nano (meaning depends on event type)

Event Types and Categories

The WebSocket API sends events in the following categories:

CategoryDescription
updatedInvoice has been updated
completedInvoice processing is complete
failedInvoice has failed or expired
paymentPayment has been confirmed

Available Event Types

The following specific event types can be received through the WebSocket:

EventDescription
invoice.createdInvoice has been created
invoice.paidPayment has been received
invoice.expiredInvoice has expired without payment
invoice.forwardedFunds have been forwarded (if using forward_account)
invoice.doneInvoice processing is complete
payment.confirmedA payment transaction has been confirmed

Event Types and Their Specific Fields

The table below shows all available fields for each event type:

Fieldinvoice.paidinvoice.forwardedinvoice.doneinvoice.expiredpayment.confirmed
Categoryupdatedupdatedcompletedfailedpayment
Message Typeinvoiceinvoiceinvoiceinvoicepayment
id
timestamp
event_type
unit_amount✓ (received)✓ (forwarded)✓ (received)✓ (usually 0)✓ (payment)
formatted_amount✓ (received)✓ (forwarded)✓ (received)✓ (usually 0)✓ (payment)
is_paid✓ (true)✓ (true)✓ (true)✓ (false)-
is_expired✓ (false)✓ (false)✓ (false)✓ (true)-
is_overpaid-✓ (varies)---
currency-
exchange_rate-
nominal_amount-
transaction_id----

Notes:

  • ✓ indicates the field is present in the payload
  • Fields with fixed values show the value in parentheses, e.g., ✓ (true)
  • The meaning of the amount fields changes based on the event type (shown in parentheses)
  • "-" indicates the field is not present in this event type

Field Descriptions

FieldDescription
idInvoice or payment identifier
timestampISO-formatted timestamp of the event (with timezone information)
event_typeThe specific event type (e.g., "invoice.paid")
unit_amountRaw amount in nano units
formatted_amountHuman-readable amount in nano
is_paidWhether the invoice has been paid
is_expiredWhether the invoice has expired
is_overpaidWhether the payment amount exceeded the required amount
currencyFiat currency code (e.g., "EUR", "USD")
exchange_rateThe exchange rate used for conversion
nominal_amountOriginal amount in the invoice's fiat currency
transaction_idBlockchain transaction hash/identifier

Amount Field Context

The amount fields have different meanings depending on the event type:

Event TypeMeaning of Amount Fields
invoice.paidTotal amount received
invoice.forwardedAmount forwarded to destination
invoice.doneFinal received amount
invoice.expiredAmount received before expiry (usually 0)
payment.confirmedPayment amount (can be partial payment)

Example Usage

Here's an example of how to connect to the WebSocket using JavaScript:

JAVASCRIPT
1const invoiceId = 'INV_2025_03_62fcb6bc256f6fad7622';
2const socket = new WebSocket(`wss://api.splitroute.com/api/v1/ws/invoices/${invoiceId}`);
3
4socket.onopen = function(e) {
5 console.log('Connected to WebSocket');
6};
7
8socket.onmessage = function(event) {
9 const message = JSON.parse(event.data);
10 console.log(`Received message type: ${message.message_type}, category: ${message.category}`);
11
12 // Check for invoice payment
13 if (message.payload.event_type === 'invoice.paid') {
14 console.log('Invoice has been paid!');
15 console.log(`Received amount (formatted): ${message.payload.formatted_amount}`);
16 console.log(`Received amount (raw): ${message.payload.unit_amount}`);
17 // Update your UI or take other actions
18 }
19
20 // Check for invoice completion
21 if (message.category === 'completed') {
22 console.log('Invoice processing completed');
23
24 // Close the connection as we're done
25 socket.close();
26 }
27};
28
29socket.onclose = function(event) {
30 if (event.wasClean) {
31 console.log(`Connection closed cleanly, code=${event.code} reason=${event.reason}`);
32 } else {
33 console.log('Connection died');
34 }
35};
36
37socket.onerror = function(error) {
38 console.log(`WebSocket error: ${error.message}`);
39};

Real-World Message Examples

JSON
1{
2 "timestamp": "2025-03-31T09:18:04.221064+00:00",
3 "message_type": "payment",
4 "category": "payment",
5 "payload": {
6 "id": "INV_2025_03_62fcb6bc256f6fad7622",
7 "timestamp": "2025-03-31T09:18:04.211013+00:00",
8 "event_type": "payment.confirmed",
9 "unit_amount": "1000000000000000000000000",
10 "formatted_amount": "0.000001",
11 "transaction_id": "2C561F447FA7F0D986B2671FBDB42925F83FE3D4732FB69B400ED0488EA98622"
12 }
13}
JSON
1{
2 "timestamp": "2025-03-31T09:18:11.897603+00:00",
3 "message_type": "invoice",
4 "category": "updated",
5 "payload": {
6 "id": "INV_2025_03_62fcb6bc256f6fad7622",
7 "timestamp": "2025-03-31T09:18:11.890364+00:00",
8 "event_type": "invoice.paid",
9 "unit_amount": "2000000000000000000000000",
10 "formatted_amount": "0.000002",
11 "nominal_amount": "0.000002",
12 "is_paid": true,
13 "is_expired": false,
14 "currency": "EUR",
15 "exchange_rate": "0.8221560000"
16 }
17}
JSON
1{
2 "timestamp": "2025-03-31T09:18:13.595621+00:00",
3 "message_type": "invoice",
4 "category": "updated",
5 "payload": {
6 "id": "INV_2025_03_62fcb6bc256f6fad7622",
7 "timestamp": "2025-03-31T09:18:13.585571+00:00",
8 "event_type": "invoice.forwarded",
9 "unit_amount": "2000000000000000000000000",
10 "formatted_amount": "0.000002",
11 "nominal_amount": "0.000002",
12 "is_paid": true,
13 "is_expired": false,
14 "is_overpaid": false,
15 "currency": "EUR",
16 "exchange_rate": "0.8221560000"
17 }
18}
JSON
1{
2 "timestamp": "2025-03-31T09:18:13.596625+00:00",
3 "message_type": "invoice",
4 "category": "completed",
5 "payload": {
6 "id": "INV_2025_03_62fcb6bc256f6fad7622",
7 "timestamp": "2025-03-31T09:18:13.592363+00:00",
8 "event_type": "invoice.done",
9 "unit_amount": "2000000000000000000000000",
10 "formatted_amount": "0.000002",
11 "nominal_amount": "0.000002",
12 "is_paid": true,
13 "is_expired": false,
14 "currency": "EUR",
15 "exchange_rate": "0.8221560000"
16 }
17}

Python Example

Python
1import websocket
2import json
3import threading
4import time
5
6def on_message(ws, message):
7 data = json.loads(message)
8 print(f"Received event: {data['payload']['event_type']}")
9
10 if data['payload']['event_type'] == 'invoice.paid':
11 print(f"Amount (formatted): {data['payload']['formatted_amount']}")
12 print(f"Amount (raw): {data['payload']['unit_amount']}")
13
14 if data['category'] == 'completed':
15 print("Invoice processing completed")
16 ws.close()
17
18def on_error(ws, error):
19 print(f"Error: {error}")
20
21def on_close(ws, close_status_code, close_reason):
22 print(f"Connection closed: {close_reason}")
23
24def on_open(ws):
25 print("Connection established")
26
27if __name__ == "__main__":
28 invoice_id = "INV_2025_03_62fcb6bc256f6fad7622"
29 ws_url = f"wss://api.splitroute.com/api/v1/ws/invoices/{invoice_id}"
30
31 ws = websocket.WebSocketApp(ws_url,
32 on_open=on_open,
33 on_message=on_message,
34 on_error=on_error,
35 on_close=on_close)
36
37 wst = threading.Thread(target=ws.run_forever)
38 wst.daemon = True
39 wst.start()
40
41 # Keep the main thread running
42 try:
43 while True:
44 time.sleep(1)
45 except KeyboardInterrupt:
46 ws.close()

Connection Limits

  • Each invoice can have up to 5 simultaneous WebSocket connections
  • Connections will be automatically closed after 15 minutes (900 seconds) of inactivity
  • If an invoice is marked as done or expired, all connections will be closed after a 5-minute grace period