# Omnio Suite API documentation

Base URL: `https://omniosuite.com/api/v1` · OpenAPI 3.1: https://omniosuite.com/api/v1/openapi.json · Interactive reference: https://omniosuite.com/docs/api

## Quickstart

_From signup to first send in under 10 minutes._

After signing up you have an empty workspace. On the Developer surface, four steps take you to your first send:

- Connect a provider. Open Connect → Providers, pick a vendor card (MSG91, Twilio, Gupshup, SES, FCM and others), paste your credentials. They are encrypted in the vault. Or switch on the Omnio Suite toggle for that channel to use the managed pool.
- Create a template. Content → Templates → New template → add a version per channel. Liquid variables are extracted automatically.
- Configure routing (optional). Connect → Routing → add a rule mapping channel + category to a credential, with an ordered fallback chain.
- Issue an API key. Build → API keys → name it, and copy the secret once. It is shown only at issuance.

The contact (POST /v1/contacts) and the template must exist before the first send. Then call the API:

```bash
curl -X POST https://omniosuite.com/api/v1/messages \
  -H "Authorization: Bearer sandesh_live_•••" \
  -H "Content-Type: application/json" \
  -d '{"to":{"phone":"+919812345678"},"template":"otp-sms","variables":{"otp":"248901"},"idempotency_key":"otp-user_123-1"}'
```

## Authentication

_Bearer tokens for the REST API; session cookies for the dashboard._

Omnio Suite has two auth surfaces:

- REST API (omniosuite.com/api/v1/*) — secret key from Build → API keys, sent as Authorization: Bearer sandesh_live_…. Keys labelled sandesh_test_… currently behave exactly like live keys: messages are delivered and billed.
- Publishable keys (sandesh_pub_…) — used only by the web SDK and the push widget on public endpoints under /api/v1/sdk/*. They are rejected on the authenticated API.
- Dashboard (omniosuite.com) — session cookies, with optional two-factor authentication.

Keys are scoped to a project and an environment. A key issued on the Engage surface cannot call the Developer-only endpoints (/v1/notify, /v1/whatsapp, /v1/calls, /v1/webhooks). The plaintext is shown once at issuance; only a SHA-256 hash is stored.

## Sending messages

_POST /v1/messages, bulk, routing rules, fallback chains._

### Sending

The send pipeline does the following per request:

- Resolves the template by slug.
- Picks a channel and a provider credential from your routing rules (priority order, first match wins), or the channel default.
- Enforces consent, quiet hours and frequency caps (skippable for transactional categories).
- Enforces DLT for SMS to Indian numbers: the rendered body must hash-match an approved DLT template.
- Renders the template with Liquid variables.
- Writes a delivery_log row in status=queued.
- Dispatches to the provider; on failure, tries the next credential in the fallback chain. One send_attempt row per hop.
- Provider webhooks update the same row with delivered, read or failed transitions. Status only moves forward.

For bulk: POST /v1/messages/bulk with up to 10,000 recipients per request. Each becomes its own delivery_log row. For a one-off send to a raw address without creating a contact, use POST /v1/notify/{channel} with a Developer key.

## Webhooks

_Subscribe URLs to message events with HMAC-SHA256 signatures._

Manage endpoints under Build → Webhooks. Subscribe by channel; each endpoint gets a signing secret you can rotate.

Every delivery sends:

```http
POST /your/endpoint
Content-Type: application/json
X-Omnio-Signature: t=1700000000,v1=<hex_hmac>
X-Omnio-Timestamp: 1700000000
X-Omnio-Event: omnio.message.delivered

{"id": "...", "event": "omnio.message.delivered", "created": 1700000000, "data": {...}}
```

Verify with HMAC-SHA256 over "<ts>.<raw_body>" using your signing secret, compared constant-time against v1. Reject if the timestamp drifts more than 5 minutes (replay protection).

Retry policy: 5 attempts with backoff of 10s, 60s, 5m, 30m and 1h. After that the delivery is marked abandoned and workspace owners are notified.

Inbound webhooks from your own providers can be hosted by Omnio Suite as well (Build → Webhooks-as-a-Service): ordered delivery, retries up to 24 hours and replay.

## DLT compliance (India SMS)

_Entity registration, template approval, pre-send gate._

### DLT compliance

SMS to Indian numbers that does not match an approved DLT template is blocked before it reaches the aggregator. Workflow:

- Register your entity (PE ID) with a TRAI DLT registrar.
- In Omnio Suite: Compliance → DLT → Register entity (PE ID, entity name, type).
- Register each template with the registrar and note the template ID.
- In Omnio Suite: Compliance → DLT → Register template (link to your template, header, template ID, body). On the Engage surface the provider is handled for you.
- Mark approved, or sync from MSG91 and Gupshup automatically.

The registered body is hashed with SHA-256. At send time the rendered SMS body is hashed and matched; a mismatch is blocked with failure_code=dlt_not_cleared.

## Idempotency

_Safely retry a send with idempotency_key._

Send idempotency_key (any opaque string up to 128 characters) in the JSON body of POST /v1/messages. A repeat with the same key returns the original message with idempotent_replay: true and nothing is sent twice. Keys do not expire. POST /v1/events accepts the same field. Other endpoints are not idempotent yet, and there is no Idempotency header.

Use a UUIDv7 or your business ID (for example order:42:otp-resend:3). Retries from network blips are then safe.

## Rate limits

_Per-key buckets and burst headers._

Each API key has its own bucket, 60 requests per minute. Responses include:

```http
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 58
```

A 429 adds Retry-After (seconds) and X-RateLimit-Reset (Unix time). Back off until then. Bulk sends count as one request, so use /v1/messages/bulk for volume. Contact us for a higher limit.
