Ubyx Platform Settlement AsyncAPI

Ubyx Platform Settlement AsyncAPI

Event-driven API documentation for the Ubyx Clearing Platform.

View AsyncAPI Documentation

Overview

This AsyncAPI specification describes the event-driven architecture for clearing transaction events between the Ubyx Settlement Platform and external partner institutions.

Key Features

Contact: Ubyx Platform Team (platform@ubyx.xyz)
License: Proprietary
External Docs: https://developers.ubyx.xyz


Servers

Environment URL Protocol Description
Sandbox broker-sandbox.ubyx-platform.com:9092 secure-protocol Sandbox Broker Server
Production broker.ubyx-platform.com:9092 secure-protocol Production Broker Server

All servers require mTLS (Mutual TLS) authentication.


Channels

ubyx.outbound — Platform → Partners

Outbound channel for clearing transaction events emitted by the platform.

Consumer Configuration:

Broker Configuration:

Consumed Event: ClearingCloudEvent

CloudEvents v1.0 envelope containing clearing transaction event data.

Event Types Published:


ubyx.inbound — Partners → Platform

Inbound channel for clearing events published by partner institutions.

Producer Configuration:

Supported Inbound Event Types

Event Type Message Description
ubyx.clearing.conversion.conversion-request ConversionRequestCloudEvent New conversion request from institution
ubyx.clearing.conversion.issuer-approval IssuerApprovalCloudEvent Issuer approved the conversion
ubyx.clearing.conversion.issuer-reject IssuerRejectCloudEvent Issuer rejected the conversion
ubyx.clearing.conversion.asset-settler-approval AssetSettlerApprovalCloudEvent Asset settler approved
ubyx.clearing.conversion.cash-settler-approval CashSettlerApprovalCloudEvent Cash settler approved
ubyx.clearing.conversion.asset-settler-confirm AssetSettlerConfirmCloudEvent Asset settler confirmed settlement
ubyx.clearing.conversion.cash-settler-confirm CashSettlerConfirmCloudEvent Cash settler confirmed settlement
ubyx.clearing.conversion.asset-settler-reject-confirm AssetSettlerRejectConfirmCloudEvent Asset settler rejected at confirmation
ubyx.clearing.conversion.cash-settler-reject-confirm CashSettlerRejectConfirmCloudEvent Cash settler rejected at confirmation
ubyx.clearing.conversion.asset-settler-reject-approve AssetSettlerRejectApproveCloudEvent Asset settler rejected at approval
ubyx.clearing.conversion.cash-settler-reject-approve CashSettlerRejectApproveCloudEvent Cash settler rejected at approval

CloudEvents Structure

All events follow the CloudEvents v1.0 specification:

{
  "specversion": "1.0",
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "type": "ubyx.clearing.CONVERSION_CREATED",
  "source": "ubyx-platform-settlement",
  "subject": "workflow-abc123",
  "time": "2024-12-12T10:30:00Z",
  "datacontenttype": "application/json",
  "dataschema": "urn:ubyx:clearing:schema:1.0-beta",
  "data": {
    "clearingTransactionId": "request-conversion-123e4567",
    "institutionId": "123e4567-e89b-12d3-a456-426614174000",
    "workflowId": "settlement-wf-987654321",
    "transactionType": "CONVERSION",
    "status": "INITIATED"
  }
}

CloudEvent Fields

Field Required Description
specversion Yes Always "1.0"
id Yes Unique event identifier (UUID)
type Yes Event type (e.g., ubyx.clearing.CONVERSION_CREATED)
source Yes Source system (e.g., ubyx-platform-settlement)
subject No Correlation ID for tracing (typically workflow ID)
time No ISO 8601 UTC timestamp
datacontenttype No Always application/json
dataschema No URN schema version (e.g., urn:ubyx:clearing:schema:1.0-beta)
data No Business-specific payload

Schemas

Transaction Types

Type Description
CONVERSION Token-to-fiat or fiat-to-token conversion
REDEMPTION Asset redemption within clearing
MINTING Asset minting within clearing
ERROR Error notification for failed transactions

Transaction Statuses

Status Description
INITIATED Transaction initiated
PENDING Awaiting processing
PROCESSING Currently being processed
COMPLETED Successfully completed
FAILED Processing failed
REJECTED Rejected by participant

Integration Examples

JavaScript Consumer (Outbound Events)

const { Kafka } = require('kafkajs');

const kafka = new Kafka({
  clientId: 'your-institution-id',
  brokers: ['broker-sandbox.ubyx-platform.com:9092'],
  ssl: {
    rejectUnauthorized: true,
    cert: fs.readFileSync('./client-cert.pem'),
    key: fs.readFileSync('./client-key.pem'),
    ca: [fs.readFileSync('./ca-cert.pem')]
  }
});

const consumer = kafka.consumer({ groupId: 'your-institution-id' });

await consumer.connect();
await consumer.subscribe({ topic: 'ubyx.outbound', fromBeginning: false });

await consumer.run({
  eachMessage: async ({ topic, partition, message }) => {
    const event = JSON.parse(message.value.toString());
    console.log('Received CloudEvent:', event.type, event.id);
    
    switch (event.type) {
      case 'ubyx.clearing.CONVERSION_CREATED':
        handleConversionCreated(event.data);
        break;
      case 'ubyx.clearing.ISSUER_APPROVED':
        handleIssuerApproved(event.data);
        break;
      case 'ubyx.clearing.CONVERSION_COMPLETED':
        handleSettlementCompleted(event.data);
        break;
    }
  }
});

JavaScript Producer (Inbound Events)

const producer = kafka.producer();
await producer.connect();

// Send a conversion request
const conversionEvent = {
  specversion: '1.0',
  id: crypto.randomUUID(),
  type: 'ubyx.clearing.conversion-request',
  source: 'https://your-institution.example.com',
  subject: `conversion-${Date.now()}`,
  time: new Date().toISOString(),
  datacontenttype: 'application/json',
  data: {
    conversionRequest: {
      conversionType: 'REDEMPTION',
      receivingInstitutionID: 'your-institution-id',
      issuerID: 'issuer-001',
      cashSettlerID: 'settler-cash-001',
      assetSettlerID: 'settler-asset-001',
      assetID: 'USDC',
      quantity: 10000,
      currency: 'USD',
      ownerMeta: {
        fullName: 'John Doe',
        address: '123 Main Street, New York, NY 10001'
      },
      RIaccountNumber: 'US12345678901234'
    }
  }
};

await producer.send({
  topic: 'ubyx.inbound',
  messages: [{ value: JSON.stringify(conversionEvent) }]
});

Event Flow Diagram

sequenceDiagram participant Partner as Partner Institution participant Inbound as ubyx.inbound participant Platform as Ubyx Platform participant Outbound as ubyx.outbound Partner->>Inbound: ConversionRequest Inbound->>Platform: Process request Platform->>Outbound: CONVERSION_CREATED Platform->>Outbound: ISSUER_APPROVAL_REQUESTED Partner->>Inbound: IssuerApproval Platform->>Outbound: ISSUER_APPROVED par Asset Settlement Platform->>Outbound: ASSET_SETTLEMENT_REQUESTED Partner->>Inbound: AssetSettlerApproval Platform->>Outbound: ASSET_SETTLEMENT_APPROVED and Cash Settlement Platform->>Outbound: CASH_SETTLEMENT_REQUESTED Partner->>Inbound: CashSettlerApproval Platform->>Outbound: CASH_SETTLEMENT_APPROVED end par Asset Confirmation Platform->>Outbound: ASSET_SETTLER_CONFIRM_REQUESTED Partner->>Inbound: AssetSettlerConfirm Platform->>Outbound: ASSET_SETTLER_CONFIRMED and Cash Confirmation Platform->>Outbound: CASH_SETTLER_CONFIRM_REQUESTED Partner->>Inbound: CashSettlerConfirm Platform->>Outbound: CASH_SETTLER_CONFIRMED end Platform->>Outbound: CONVERSION_COMPLETED

Best Practices

Event Validation

Always validate incoming CloudEvents:

function validateCloudEvent(event) {
  const required = ['specversion', 'id', 'type', 'source'];
  for (const field of required) {
    if (!event[field]) {
      throw new Error(`Missing required field: ${field}`);
    }
  }
  if (event.specversion !== '1.0') {
    throw new Error('Unsupported CloudEvents version');
  }
  return true;
}

Idempotency

Use the event id field to ensure idempotent processing:

const processedEvents = new Set();

async function processEvent(event) {
  if (processedEvents.has(event.id)) {
    console.log('Duplicate event, skipping:', event.id);
    return;
  }
  
  // Process the event...
  
  processedEvents.add(event.id);
}

Error Handling

Implement robust error handling with retries:

consumer.on('consumer.crash', async ({ error }) => {
  console.error('Consumer crashed:', error);
  // Implement reconnection logic
  await consumer.disconnect();
  await consumer.connect();
});