---
name: send-omnichannel-with-failover
description: Use the Messages API to send one payload across channels with an ordered failover chain,
  and read a single normalized delivery report.
api: openapi/infobip-messages-api-openapi.json
operations:
- validate-messages-api-message
- send-messages-api-message
- get-messages-api-delivery-reports
- get-messages-api-inbound-messages
- send-messages-api-events
provider: Infobip
generated: '2026-07-25'
method: generated
source: Grounded in operationIds verified in openapi/infobip-messages-api-openapi.json plus conventions/infobip-conventions.yml,
  errors/infobip-error-codes.yml and rate-limits/infobip-rate-limits.yml
---

# Send omnichannel with failover

Use the Messages API to send one payload across channels with an ordered failover chain, and read a single normalized delivery report.

## Ground rules for every Infobip call

- Base URL: `https://api.infobip.com` (an account may also be issued a personalized `https://{subdomain}.api.infobip.com` host shown in the web portal — either works).
- Auth header: `Authorization: App {API_KEY}`. Basic auth is only for the API-key-management endpoints. Every endpoint additionally requires at least one API scope (see `scopes/infobip-scopes.yml`).
- There is **no idempotency key**. Never blind-retry a send on a timeout or 5xx — re-read the outcome with the reports/logs operation for the returned `bulkId`/`messageId` first (`conventions/infobip-conventions.yml`).
- On `429` back off exponentially and honour `Retry-After`. Per-operation limits are published in the spec as `x-throttling-info` and collected in `rate-limits/infobip-rate-limits.yml`.
- HTTP errors use the Infobip `requestError.serviceException {messageId, text, validationErrors}` envelope (not RFC 9457) — see `errors/infobip-problem-types.yml`.
- A `200` does **not** mean delivered. Message outcome lives in the `status {groupId, groupName, id, name}` and `error {groupId, groupName, id, name, permanent}` objects; resolve them against `errors/infobip-error-codes.yml`. `permanent: true` means a retry can never succeed.
- Listing endpoints page with `page`/`size` (max 100) and return `{page, size, totalPages, totalResults}`; newer endpoints support `cursor`/`useCursor`.

## Steps
1. **Validate first** — `validate-messages-api-message` (`POST /messages-api/1/messages/validate`) checks the payload without sending. Cheap insurance against `REJECTED_VALIDATION_FAILED`.
2. **Send** — `send-messages-api-message` (`POST /messages-api/1/messages`). One request carries `messages[].channel` content plus an ordered failover chain, so a WhatsApp attempt can fall back to SMS or Viber without you orchestrating it. The response returns `messageId` per message.
3. **Read one report shape for every channel** — `get-messages-api-delivery-reports` (`GET /messages-api/1/reports`), or the corresponding webhook. Channel-specific `error.name` values still surface, so resolve them against `errors/infobip-error-codes.yml`.
4. **Inbound** — `get-messages-api-inbound-messages` (`GET /messages-api/1/inbound`) pulls replies across channels; `send-messages-api-events` reports read/typing events back.
5. If you need channel-native features the unified payload does not expose (WhatsApp flows, RCS carousels, voice IVR), drop to the channel API and keep the omni-failover chain in `openapi/infobip-omni-failover-openapi.json`.
