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-Keywith the same payload:- returns the stored accepted response again
- same
Idempotency-Keywith a different payload:- returns
409 CONFLICT
- returns
This means you should treat the idempotency key and the payload as a pair.
Safe retry model
For a send request:
- generate one idempotency key for the business operation
- persist that key before sending if the send matters operationally
- send the request
- if the network fails or the response is lost, retry with the same key and the same payload
- if the payload must change, generate a new idempotency key and treat it as a new send operation
Recommended client behavior
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
5xxand the request may be retried safely
Do not blindly retry when:
- the payload is invalid
- the recipient is invalid
- the
sendFromvalue 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:
- your client sends a request
- Red Cloud accepts it
- your network times out before the response reaches you
- 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
Recommended storage pattern
At minimum, store:
- your business operation id
- the
Idempotency-Key - the request payload hash or equivalent payload fingerprint
- any accepted
messageIdvalues returned inresults[] - the send timestamp
That makes retries, support, and reconciliation much easier.