SolidHooksSolidHooks/ Docs

Retries

How SolidHooks retries a failed delivery, what ends the schedule, and how each kind of response from your endpoint is treated.

When your endpoint does not return a 2xx, SolidHooks retries the same delivery automatically. The retry reuses the delivery row, so it adds attempts to the attempts log rather than creating new deliveries, and it never counts against your delivery quota.

How many attempts you get, and over how long, is set by your plan.

How it works

The first attempt happens immediately. After that, the gaps between attempts follow an exponential schedule:

AttemptWaits before itRoughly after the first attempt
1none0
25 seconds5 s
35 minutes5 min
430 minutes35 min
52 hours2 h 35 min
65 hours7 h 35 min
710 hours17 h 35 min
810 hours27 h 35 min

Each gap carries up to 10% of random jitter so a burst of failures does not retry in lockstep. Two plan entitlements bound the schedule, and whichever runs out first ends it:

  • maxDeliveryAttempts: the total number of attempts, first attempt included.
  • maxRetryHours: a wall-clock ceiling measured from the first attempt.
PlanmaxDeliveryAttemptsmaxRetryHours
Hobby31
Launch836
Scale836
Enterprise836

Both limits are also clamped by the plan's retentionDays, because a retry cannot outlive the delivery record it belongs to. Check your own values with GET /v1/billing/plan; enterprise organisations can have them changed.

While a delivery is still being retried, nextAttemptAt on the delivery tells you when the next attempt is due. null means no further attempts are scheduled.

How your endpoint's response is interpreted

ResponseWhat happens
2xxSuccess.
3xxFailure, retried on the schedule. Redirects are never followed.
410 GoneFailure. Two consecutive 410 responses disable the destination and email the organisation's owners and admins. Any other response in between resets the count.
429, 502, 504Parked, not failed. SolidHooks honours Retry-After (seconds or an HTTP date, capped at 1 hour), the park costs no retry attempt, and a delivery can be parked at most 5 times.
Any other 4xx or 5xxFailure, retried on the schedule.

A parked delivery has status: "throttled" and throttledReason: "destination_busy". It is queued, not lost.

Parking uses no attempt, so the attempt count alone cannot bound it. maxRetryHours does: a park that would wake the delivery after the ceiling is not taken, and the response is treated as an ordinary failure instead.

Why redirects are not followed

A redirect would send the signed payload, and your destination's custom headers, to a URL you never configured. Treating 3xx as a failure keeps deliveries going only where you pointed them. Set the destination URL to the final address.

Timeouts

A request to your endpoint times out after 20 seconds by default. A timeout is a failure and follows the schedule above. To change it, set timeoutMs on the destination to a value between 1000 and 30000.

curl -s -X PATCH "$API/v1/destinations/dest_..." \
  -H "authorization: Bearer $SDHK_KEY" \
  -H 'content-type: application/json' \
  -d '{ "data": { "timeoutMs": 10000 } }'

Manual retries and replays

  • POST /v1/deliveries/{id}/retry retries one delivery. It is free and creates no new delivery. It returns 409 CONFLICT while the delivery is throttled, because it is already queued and will send on its own.
  • POST /v1/events/{id}/replay re-runs an event through its connections and creates new deliveries, which are billable.

Next steps