Skip to main content
Work through the section matching your symptom. If you’re still stuck, contact support with the details listed at the bottom — it turns a back-and-forth into a one-shot answer.

400 — “Request signature does not match”

The X-Signature you sent doesn’t match what Float computed over the body it received. In practice this is almost always one of:
Float verifies against a compact re-serialisation of your payload (key order preserved, whitespace stripped), so a pretty-printed body never matches. Serialise compactly, sign that exact string, and send that same string.The 400 response’s detail field includes the signature Float expected — compare it to yours: if they differ, your body bytes or key are wrong; if they match, you’re mangling the header itself.
It must be HMAC-SHA512, output Base64-encoded (not hex, not URL-safe Base64). A hex digest is 128 characters; the correct Base64 digest is 88 characters ending in =.
Sign with the signing key, not the client secret — and check you’re using the sandbox key against sandbox and the production key against production.
Once Float has accepted one correctly signed request from your integration, unsigned mutating requests are rejected from then on. If you signed in a test script but your app doesn’t sign yet, the app’s requests will 400. Roll signing out everywhere at once. See Authentication.

Callback never arrives

1

Confirm the payment actually finished

Check the checkout with GET /api/checkouts/:id. If it’s still received, the shopper hasn’t completed payment — there’s nothing to deliver yet.
2

Check your endpoint is publicly reachable over HTTPS

curl -X POST https://your-site.com/float/notify -d '{}' -H "Content-Type: application/json" from outside your network. Localhost URLs, VPN-only hosts, and self-signed certificates all fail — TLS errors are a common silent killer, and Float alerts internally on SSL failures to your notify_url.
3

Check your endpoint responds 2xx fast

Non-2xx responses and timeouts are retried up to 18 times over ~3 hours, then delivery stops. WAFs and bot protection (Cloudflare challenges) returning 403 to server-to-server POSTs are a frequent cause.
4

Reconcile via the API

If the retry window has passed, the state is still one GET away — fetch the checkout and process it as you would the callback. Build this reconciliation as a scheduled job, not a manual step; see Accepting payments → Reconcile.

Shopper wasn’t redirected back to my site

  • The redirect uses the checkout’s success_url/cancel_url — or the redirect_url your callback response returned. An empty or malformed redirect_url in your callback response is ignored; a wrong one wins over your configured URLs. Log what your handler returns.
  • If your callback endpoint was down at completion time, Float still redirects the shopper using the URLs from the checkout — but your backend won’t know about the payment until a retry lands or you reconcile. Never gate the “thank you” page on your own database alone; treat success_url hits as a hint and confirm via callback or API.

422 validation errors

The same-day restriction only applies to integrations with automatic refund approval — manual-review integrations can submit immediately.

429 rate limits

The limits are listed per endpoint in the API overview. If you’re hitting them:
  • GET /api/config (5/hour) — cache it. It changes rarely; refresh hourly or on deploy.
  • GET /api/checkouts/:id (5/minute) — you’re polling instead of using callbacks. Poll only the specific orders you’re reconciling.
  • POST /api/refunds (1/second) — queue bulk refunds with a 1s+ spacing.
Honour the Try again in N seconds hint in the 429 body; don’t hammer. The hosted payment session is valid for roughly 30 minutes. If a shopper returns to a stale payment_url, create a new checkout (a fresh client_reference_id per attempt, or dedupe on your side) rather than reusing the old URL.

Getting help

Email support@float.co.za with:
  1. The checkout ID (data.id from create checkout) and your client_reference_id
  2. The environment (sandbox or production) and timestamp (with timezone)
  3. The full request and response (redact your Bearer token)
  4. For callback issues: your notify_url and your endpoint’s response/logs for the window
Float keeps a full audit trail of every callback attempt to your notify_url (request and response), so support can tell you exactly what your endpoint returned and when.