Skip to main content

Idempotency and Retries

Red Cloud send requests are designed to be retried safely, but only if your client uses idempotency correctly.

This page explains how to retry without creating duplicate downstream messages.

Why idempotency matters

POST /api/core/messages/send can fail for several different reasons:

  • the request never reached Red Cloud
  • the request reached Red Cloud but the client timed out waiting for the response
  • the request was accepted, but you lost the response
  • the request was rejected because the payload was invalid

Without idempotency, those cases are difficult to distinguish and can create duplicate sends.

Required header

Every send request must include:

Idempotency-Key

Red Cloud requires that header on POST /api/core/messages/send.

What the key should represent

An idempotency key should represent one business operation, not one network attempt.

Good examples:

  • one outbound notification attempt for one order update
  • one passwordless login code send for one user action
  • one appointment reminder for one scheduled reminder record

Bad examples:

  • a new random key on every retry
  • a timestamp-only key that changes between attempts
  • a key reused across unrelated sends

Actual Red Cloud behavior

Current behavior is:

  • same Idempotency-Key with the same payload:
    • returns the stored accepted response again
  • same Idempotency-Key with a different payload:
    • returns 409 CONFLICT

This means you should treat the idempotency key and the payload as a pair.

Safe retry model

For a send request:

  1. generate one idempotency key for the business operation
  2. persist that key before sending if the send matters operationally
  3. send the request
  4. if the network fails or the response is lost, retry with the same key and the same payload
  5. if the payload must change, generate a new idempotency key and treat it as a new send operation

Retry when:

  • the request failed before you know whether Red Cloud accepted it
  • the HTTP client timed out
  • the connection dropped
  • you received a transient 5xx and the request may be retried safely

Do not blindly retry when:

  • the payload is invalid
  • the recipient is invalid
  • the sendFrom value is not owned by the API client
  • the request is missing Idempotency-Key
  • you changed the payload but kept the same key

Those are usually integration or request-construction defects, not transient failures.

Suggested retry flow

For one send operation:

Create business operation
-> generate idempotency key
-> send request
-> if accepted, persist messageId from results[]
-> if request outcome uncertain, retry with same key and same payload
-> if payload changes, create a new operation and new key

Timeouts and ambiguous outcomes

The most important idempotency use case is an ambiguous outcome.

Example:

  1. your client sends a request
  2. Red Cloud accepts it
  3. your network times out before the response reaches you
  4. your client does not know whether the send was accepted

In that case, retry the same request with the same Idempotency-Key.

That is exactly what idempotency is for.

Multi-recipient sends

Send requests may partially succeed. That means:

  • some recipients can appear in results[]
  • other recipients can appear in errors[]

When you retry a multi-recipient request, use the same payload only if you are retrying the same operation exactly.

If you want to change the recipient list, treat it as a new operation and create a new idempotency key.

Common idempotency mistakes

  • generating a new key on every retry
  • reusing the same key for a changed payload
  • not persisting the key for important operations
  • assuming a transport timeout means the request definitely failed
  • retrying validation failures instead of fixing the payload

At minimum, store:

  • your business operation id
  • the Idempotency-Key
  • the request payload hash or equivalent payload fingerprint
  • any accepted messageId values returned in results[]
  • the send timestamp

That makes retries, support, and reconciliation much easier.