Events
A single canonical registry of events flows across all 21 apps. Any app can emit; any app can subscribe.
Count: 101 event types (as of 2026-04-16) Transport: HMAC-SHA256 signed webhooks — see /integration/webhooksTyped payloads: @r-bsoftware/ecosystem-sdk/event-payloads
Shape of an event
ts
{
eventId: string // UUID for idempotency
eventType: string // e.g., "payment.received"
timestamp: string // ISO 8601
source: string // Emitting app slug
organizationId: string // RBS org ID
data: EventDataOf<eventType> // Strongly typed
}Naming convention
<domain>.<verb> — past-tense verb. Examples:
payment.received,payment.failed,payment.refundedsubscription.activated,subscription.cancelled,subscription.trial_expiringcfdi.stamped,cfdi.cancelled,cfdi.failedcustomer.created,customer.updated,customer.linkeddeal.created,deal.updated,deal.billing_chargedbooking.created,booking.cancelled,appointment.completed
Consuming events
ts
import { createWebhookHandler } from '@r-bsoftware/ecosystem-sdk'
import type { EventDataOf } from '@r-bsoftware/ecosystem-sdk/event-payloads'
export const POST = createWebhookHandler({
secret: process.env.WEBHOOK_SECRET!,
handlers: {
'payment.received': async (event) => {
const data = event.data as EventDataOf<'payment.received'>
// data.amountCents, data.currency, data.invoiceId — typed
},
}
})Emitting events
Each emitting app posts to the Camino webhook fan-out or direct-delivers to registered subscribers. The createWebhookSender factory in the SDK handles signing + retries.
Full registry
The complete 101-event registry, with payload shape and emitter app per event, lives at /reference/events.
Source of truth
- Registry JSON:
ecosystem-sdk/packages/mcp-server/src/registry/events.json(canonical; 101 entries) - Typed payloads:
@r-bsoftware/ecosystem-sdk/event-payloads - SDK factories:
webhook-sender.ts,webhook-handler.ts
Gotchas
- Never invent event names locally. Add to the registry first, regen types, then emit. Mancha emitted
appointment_donefor three sprints before we reconciled toappointment.completed. - Payload drift is real. Always cast
event.data as EventDataOf<'<name>'>— don't hand-type. The SDK types are the source of truth. - Unknown event types must be ignored, not rejected with 4xx. The ecosystem grows; older handlers should return 200 for unrecognized types.