POST request.
Register an endpoint and choose its events in Console > Webhooks.
Delivery
Return200 within 10 seconds; any other response is a failure. Respond first, then do slow work.
Flatpeak retries a failed delivery after 30 seconds, 1 hour, 6 hours, 12 hours and 24 hours, each counted from the previous attempt. After the last retry, resend it from Console > Webhooks > Logs.
Verify signatures
Flatpeak signs every delivery, so verify the signature before you act on the event. The signed message is{Flatpeak-Timestamp}.{raw request body}. The algorithm is RSA-PSS with SHA-256 (PS256): RSA-2048 key, MGF1-SHA256, salt length 32 bytes. Live and test mode use separate keys.
- Read the raw request body bytes before any JSON parsing.
- Build the message: the timestamp, a literal
., then the raw body. - Fetch the JWKS and pick the key whose
kidequalsFlatpeak-Key-ID. Cache it, and refetch on an unknownkid, because keys rotate. - Strip
v1=, base64url-decode the signature, and verify it with RSA-PSS SHA-256. - Reject a timestamp more than 5 minutes from your clock.
express.raw({ type: 'application/json' }) (Express), a raw contentTypeParser (Fastify), request.get_data() (Flask), await request.body() (FastAPI), request.body (Django), io.ReadAll(r.Body) (Go).
Debug a failing signature
Debug a failing signature
Reproduce the check with OpenSSL. Save the raw body as
raw_body.json and the JWKS as jwks.json. Copy the header values from Console > Webhooks > Logs.Verified OK means success. On Verification failure, check the body bytes, the key ID and the signature decode.
