Skip to content
PaalChat Docs

Build and operate

Safe retries

Retry the right failures, the right way.

.md

In a nutshell

Retry 429 and 5xx with exponential backoff, and network failures on sends with the same reference. Never retry other 4xx errors - fix the request instead.

What to retry

Outcome Retry? How
2xx - Done
Timeout / connection reset Yes Same request, same reference
429 rate_limited Yes After the Retry-After seconds
500 server_error Yes Exponential backoff
409 not_connected After the business reconnects Offer a connect link first
422 template_not_approved After approval Wait for a template.status callback
Other 4xx No Fix the request

Backoff

Wait longer after each failure and add jitter, for example 1 s, 2 s, 4 s, 8 s... up to a few minutes, then give up and alert. Run retries in a background queue, never in a user's web request.

// A Laravel job: retried by the queue with backoff; the reference makes it safe.
class SendWhatsAppNotification implements ShouldQueue
{
    public $tries = 6;
    public $backoff = [5, 30, 120, 600, 1800];

    public function handle(): void
    {
        $response = Http::withToken(config('services.paalchat.token'))->acceptJson()->timeout(20)
            ->post("https://whatsapp.paaltech.org/api/v1/businesses/{$this->tenant}/messages", $this->payload);

        if ($response->status() === 429 || $response->serverError()) {
            $this->release((int) $response->header('Retry-After') ?: 60);
            return;
        }

        $response->throw(); // other 4xx: fail and surface the error code
    }
}

Your callback endpoint

PaalChat retries callbacks too. Make your endpoint idempotent (see Idempotency) and answer 2xx only after the event is safely recorded.