Rialto

Webhooks

Real-time event notifications with HMAC-SHA256 signatures, automatic retries, and delivery monitoring.

Rialto delivers real-time event notifications to your application via webhooks. Events are sent as HTTP POST requests with JSON payloads, signed with HMAC-SHA256 for verification, and automatically retried on failure.

The webhook API is served by the notifications service (/notifications prefix). The identity service publishes KYC and accreditation events; the primary issuance service publishes subscription and share events.

Setting Up Webhooks

1. Register an Endpoint

curl -X POST https://api.rialto.com/notifications/webhooks \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <rialto_access_token>" \
  -d '{
    "url": "https://yourapp.com/webhooks/rialto",
    "description": "Production webhook endpoint",
    "eventTypes": ["kyc.session.approved", "subscription.created"]
  }'

The response includes a signing_secret. Store it securely -- it is only shown on creation and rotation.

2. Subscribe to Events

Set event types during creation (via eventTypes) or update them later:

curl -X PUT https://api.rialto.com/notifications/webhooks/<endpoint_id>/subscriptions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <rialto_access_token>" \
  -d '{
    "eventTypes": ["kyc.session.approved", "subscription.created", "subscription.funded"]
  }'

Use "*" to subscribe to all event types.

3. Test Your Endpoint

Send a test event to verify connectivity:

curl -X POST https://api.rialto.com/notifications/webhooks/<endpoint_id>/test \
  -H "Authorization: Bearer <rialto_access_token>"

This sends a test.ping event to your endpoint.

Event Types

KYC Events (6)

EventDescription
kyc.session.createdKYC session created for a user
kyc.session.pii_submittedUser submitted identity information
kyc.session.processingIdentity verification in progress
kyc.session.approvedKYC verification passed
kyc.session.deniedKYC verification failed
kyc.session.requires_reviewSession needs manual review

Accreditation Events (6)

EventDescription
accreditation.session.createdAccreditation session created
accreditation.document.uploadedUser uploaded a proof document
accreditation.session.submittedUser submitted for review
accreditation.session.more_info_neededAdditional documentation requested
accreditation.session.approvedAccreditation verified
accreditation.session.deniedAccreditation denied

Subscription Events (10)

EventDescription
subscription.createdNew subscription created
subscription.signedSubscription agreement signed
subscription.fundedPayment received for subscription
subscription.approvedSubscription approved by issuer
subscription.rejectedSubscription rejected
subscription.completedSubscription fully completed
subscription.cancelledSubscription cancelled
subscription.info_requestedAdditional information requested from investor
subscription.voidedSubscription agreement voided
shares.issuedShares issued to investor

You can also call GET /notifications/event-types to retrieve the current list programmatically.

Note: Only events in the supported event types list are delivered to webhooks. Internal-only events are silently filtered out.

Webhook Payload Format

Every webhook delivery is an HTTP POST with this JSON body:

{
  "event_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "event_type": "kyc.session.approved",
  "source": "rialto.identity",
  "org_id": "550e8400-e29b-41d4-a716-446655440000",
  "timestamp": "2026-03-15T10:30:00.000Z",
  "version": "1",
  "data": {
    "session_id": "...",
    "user_id": "...",
    "status": "approved"
  }
}

Delivery Headers

HeaderDescriptionExample
Content-TypeAlways JSONapplication/json
X-Rialto-SignatureHMAC-SHA256 signaturesha256=a1b2c3...
X-Rialto-Event-TypeThe event typekyc.session.approved
X-Rialto-Event-IdUnique event ID (UUID)a1b2c3d4-...
X-Rialto-Delivery-IdUnique delivery ID (UUID)f6e5d4c3-...
X-Rialto-TimestampEvent timestamp (ISO 8601)2026-03-15T10:30:00.000Z
User-AgentRialto webhook agentRialto-Webhooks/1.0

Signature Verification

Every delivery is signed with your endpoint's signing_secret using HMAC-SHA256.

Verification Steps

  1. Read the raw request body (do not parse then re-stringify)
  2. Compute HMAC-SHA256 of the raw body using your signing_secret
  3. Prepend sha256= to the hex digest
  4. Compare with the X-Rialto-Signature header using constant-time comparison

Node.js Example

import crypto from "crypto";

function verifySignature(secret, payload, signature) {
  const expected = "sha256=" + crypto
    .createHmac("sha256", secret)
    .update(payload, "utf8")
    .digest("hex");

  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature)
  );
}

// In your webhook handler:
app.post("/webhooks/rialto", (req, res) => {
  const signature = req.headers["x-rialto-signature"];
  const rawBody = req.rawBody; // ensure your framework preserves the raw body

  if (!verifySignature(SIGNING_SECRET, rawBody, signature)) {
    return res.status(401).send("Invalid signature");
  }

  const event = JSON.parse(rawBody);
  // Process event...
  res.status(200).send("OK");
});

Python Example

import hmac
import hashlib

def verify_signature(secret: str, payload: bytes, signature: str) -> bool:
    expected = "sha256=" + hmac.new(
        secret.encode("utf-8"),
        payload,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

Retry Behavior

Your endpoint must return a 2xx status within 30 seconds. Non-2xx responses or timeouts trigger automatic retries.

Retry Schedule (8 attempts total)

AttemptDelay After Previous
1Immediate
230 seconds
32 minutes
415 minutes
51 hour
64 hours
712 hours
824 hours

After all 8 attempts fail, the delivery is marked exhausted with no further retries.

Delivery Monitoring

Track the status of webhook deliveries:

# List deliveries (filter by endpoint, status, or event type)
curl "https://api.rialto.com/notifications/deliveries?endpoint_id=<id>&status=failed" \
  -H "Authorization: Bearer <rialto_access_token>"

# Get delivery detail with all attempts
curl https://api.rialto.com/notifications/deliveries/<delivery_id> \
  -H "Authorization: Bearer <rialto_access_token>"

# Manually retry a failed delivery
curl -X POST https://api.rialto.com/notifications/deliveries/<delivery_id>/retry \
  -H "Authorization: Bearer <rialto_access_token>"

Delivery Statuses

StatusDescription
pendingDelivery queued, not yet attempted
successEndpoint returned 2xx
failedLast attempt failed, retries remaining
exhaustedAll 8 attempts failed, no more retries

Managing Endpoints

# List your endpoints
GET /notifications/webhooks

# Get endpoint details
GET /notifications/webhooks/:id

# Update endpoint
PATCH /notifications/webhooks/:id
{ "url": "https://new-url.com/webhook", "description": "Updated" }

# Delete endpoint
DELETE /notifications/webhooks/:id

# Rotate signing secret (returns new secret once)
POST /notifications/webhooks/:id/rotate-secret

# Get current subscriptions
GET /notifications/webhooks/:id/subscriptions

Best Practices

  • Respond quickly -- return 200 within a few seconds, then process events asynchronously
  • Verify signatures in production using constant-time comparison
  • Handle duplicates idempotently -- use event_id to deduplicate (the same event may be delivered more than once)
  • Monitor failed deliveries via the deliveries API
  • Rotate signing secrets periodically using the rotate endpoint
  • Subscribe selectively -- only subscribe to event types you need rather than using *

On this page