Webhooks

Gravity SMS uses two layers of webhooks: RingCentral-to-gateway (inbound SMS delivery) and gateway-to-app (fan-out to your applications). This guide explains the architecture and how to set up reliable webhook handling.

Webhook architecture

Two distinct webhook flows exist in the system:

  1. RingCentral → Gateway — RingCentral sends inbound SMS events to the gateway's webhook endpoint. The gateway handles handshake, verification, and event processing.
  2. Gateway → Your App — After processing an inbound SMS, the gateway fans out the message to every app in the tenant that has a webhookUrl configured.

RingCentral webhook flow

When the gateway connects to RingCentral, it creates a webhook subscription for instant SMS events. RingCentral uses a two-phase verification process:

  1. Handshake — RingCentral sends a request with a Validation-Token header. The gateway echoes this header back in the response to confirm the endpoint.
  2. Event delivery — Subsequent events include a Verification-Token header. The gateway verifies it against the stored token before processing.
RingCentral webhook subscriptions expire after 7 days. The gateway automatically renews them before expiration.

App webhook fan-out

When an inbound SMS is processed, the gateway delivers it to your application:

  • The gateway sends an HTTP POST to each app's webhookUrl with a JSON payload.
  • The request has a 5-second timeout. Return a 2xx response as quickly as possible and process the message asynchronously.
  • If your endpoint is unreachable or times out, the message is not retried to your webhook but remains available via the messages API and WebSocket.

Inbound payload shape

POST to your webhookUrl
{
"type": "sms_inbound",
"messageId": "msg_a1b2c3d4e5f6",
"from": "+15559876543",
"to": "+15551234567",
"body": "Yes, I confirm",
"rcMessageId": "123456789",
"tenantId": "tenant_abc123def456abcd",
"timestamp": "2026-03-01T14:30:00.000Z"
}

Configuring your webhook URL

Set the webhookUrl during app registration or update it afterwards:

Set webhook URL on an existing app
curl -X PUT https://smsgateway-api.onrender.com/v1/apps/app_abc123def456abcd \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "webhookUrl": "https://your-app.example.com/webhooks/sms" }'

To remove the webhook URL and stop receiving webhook deliveries:

Remove webhook URL
curl -X PUT https://smsgateway-api.onrender.com/v1/apps/app_abc123def456abcd \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "webhookUrl": null }'

Webhook URL requirements

RequirementDetails
ProtocolHTTPS required in production. HTTP accepted in non-production environments.
Maximum length2,000 characters.
FormatMust be a valid URL.

Testing webhooks

Use the test-webhook endpoint to send a test payload to your configured URL and verify it responds correctly:

Test webhook
curl -X POST https://smsgateway-api.onrender.com/v1/apps/app_abc123def456abcd/test-webhook \
-H "Authorization: Bearer YOUR_API_KEY"

The response includes the HTTP status code and body returned by your endpoint.

Best practices

  • Respond quickly — Return a 2xx status within 5 seconds. Queue heavy processing for later.
  • Handle duplicates — Use the messageId field to deduplicate messages in your system.
  • Use HTTPS — Always use TLS-secured endpoints in production.
  • Fall back to polling — If webhooks fail, use GET /v1/sms/messages with direction=inbound to retrieve missed messages.

Related docs