Skip to main content

Purpose

The endpoint-api delivers conversation events to external HTTP endpoints. When a call starts, ends, or a message is exchanged, assistant-api emits events to endpoint-api via gRPC. This service handles fan-out to all registered webhooks, retry with exponential backoff, HMAC-SHA256 payload signing, and delivery tracking.

Port

9005 — HTTP · gRPC (cmux)

Language

Go 1.25 Gin (REST) + gRPC

Storage

PostgreSQL endpoint_db Redis (retry job queue)

Event Delivery Flow


Core Components

Each webhook is scoped to a project and subscribes to one or more event types.
FieldTypeDescription
namestringHuman-readable label
urlstringDestination HTTPS endpoint
eventsstring[]Subscribed event types
is_activeboolEnable / disable without deleting
secretstringHMAC signing secret
max_retriesintDefault: 5
timeout_msintDefault: 30000
headersJSONCustom headers sent with each delivery
AttemptDelay
1Immediate
25 seconds
325 seconds
42 minutes
510 minutes
Retries trigger on HTTP 408, 429, and 5xx. Status 2xx = success. Status 4xx (except 408, 429) = non-retriable failure.
Every delivery includes an X-Rapida-Signature header:
X-Rapida-Signature: sha256=<hmac-sha256-hex>
Verification (Node.js):
const crypto = require('crypto');

function verifySignature(rawBody, signatureHeader, secret) {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signatureHeader),
    Buffer.from(expected)
  );
}

Event Reference

EventTriggerKey Payload Fields
conversation.startedCall beginsconversation_id, assistant_id, timestamp
conversation.endedCall terminatesconversation_id, duration_ms, messages_count, end_reason
message.sentAssistant speaksconversation_id, message_id, content, role
message.receivedUser speaksconversation_id, message_id, content, role
assistant.updatedConfig changedassistant_id, changes
assistant.deletedAssistant removedassistant_id, timestamp
error.occurredPipeline errorconversation_id, error_code, error_message
Example payload — conversation.ended:
{
  "id": "evt_1234567890abcdef",
  "type": "conversation.ended",
  "timestamp": 1704067200000,
  "data": {
    "conversation_id": "conv_abc123",
    "assistant_id": "asst_def456",
    "duration_ms": 125000,
    "messages_count": 8,
    "end_reason": "user_hangup"
  }
}

API Endpoints

MethodPathDescription
GET/readiness/Readiness probe
GET/healthz/Liveness probe
POST/api/v1/endpoint/webhooksCreate webhook
GET/api/v1/endpoint/webhooksList webhooks
GET/api/v1/endpoint/webhooks/{id}Get webhook
PUT/api/v1/endpoint/webhooks/{id}Update webhook
DELETE/api/v1/endpoint/webhooks/{id}Delete webhook
POST/api/v1/endpoint/webhooks/{id}/testSend test event
GET/api/v1/endpoint/webhooks/{id}/deliveriesList delivery history
POST/api/v1/endpoint/webhooks/{id}/replayReplay a specific event
Create a webhook:
curl -X POST http://localhost:9005/api/v1/endpoint/webhooks \
  -H "Authorization: Bearer <jwt>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "CRM Sync",
    "url": "https://crm.example.com/webhooks/rapida",
    "events": ["conversation.ended", "message.sent"],
    "headers": {"Authorization": "Bearer crm-api-key"},
    "max_retries": 5,
    "timeout_ms": 30000
  }'
Replay a failed event:
curl -X POST http://localhost:9005/api/v1/endpoint/webhooks/{id}/replay \
  -H "Authorization: Bearer <jwt>" \
  -H "Content-Type: application/json" \
  -d '{"event_id": "evt_1234567890abcdef"}'

Running

make up-endpoint

make logs-endpoint

make rebuild-endpoint

Health Endpoints

EndpointPurpose
GET /readiness/Service ready (DB + Redis connected)
GET /healthz/Liveness probe
curl http://localhost:9005/readiness/

Next Steps