Developer docs

Build reliable webhook integrations with the contracts RawNak actually serves.

Every limit and route below is based on the current Flask implementation.

Quick start

Create a workspace, copy its generated company endpoint, send one JSON request, then inspect the event and delivery attempt in the dashboard.

  • Create an account from Start free trial.
  • Create or select a destination in the dashboard.
  • Send a POST request to /webhook/<company>.
  • Open Deliveries to inspect status, response code, latency, attempts and replay actions.
curl
curl -X POST "https://api.rawnakwebhook.com/webhook/<company>" \
  -H "Content-Type: application/json" \
  -d '{"event":"order.created","id":"evt_123"}'

Authentication and secrets

Dashboard APIs require the Bearer token issued by the authentication flow. Webhook signing uses the workspace signing secret and the X-Rawnak-Signature header.

  • Keep the signing secret server-side; never put it in browser code.
  • Use Security to rotate the inbound signing secret. The new secret is revealed only by the rotation response.
  • The API also exposes a one-time initial-secret reveal flow at POST /api/security/reveal-initial-secret.
  • The dashboard token is separate from the webhook signing secret.

Receiving webhooks

The public ingest route is POST /webhook/<company>. The Flask application applies MAX_CONTENT_LENGTH; the default configured value is 1,048,576 bytes.

  • The request body is treated as the raw payload for signing and is stored as the event payload.
  • The service accepts JSON payloads for normal dashboard workflows; Content-Type: application/json is used by the product examples.
  • Successful acceptance returns HTTP 200. Invalid or inactive company lifecycle states are rejected before event insertion; exact error payloads are JSON with success:false, error and message.
  • The company identifier is the endpoint segment after /webhook/.

Destinations and forwarding

Each destination has a URL, secret, timeout_seconds, max_attempts, event filters and optional rate/concurrency controls.

  • Automatic delivery starts at attempt 1 and supports up to 3 attempts.
  • Retry delays in the worker are 180 seconds after attempt 1 and 360 seconds after attempt 2.
  • Destination timeouts are bounded by the API between 3 and 15 seconds; outbound requests disable redirects and use the secure HTTP layer.
  • Retryable HTTP responses include 408, 425, 429, 500, 502, 503 and 504 while attempts remain.
  • Replay is a new delivery run; Retry delivery advances an eligible retrying attempt.
curl
curl -X POST "https://api.rawnakwebhook.com/webhook/<company>" \
  -H "Content-Type: application/json" \
  -d '{"event":"order.created","id":"evt_123"}'
node
import crypto from "node:crypto";
const signature = crypto.createHmac("sha256", process.env.RAWNAK_SECRET)
  .update(rawBody).digest("hex");
// Send: X-Rawnak-Signature: sha256=<signature>
python
import hashlib, hmac
signature = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
headers = {"X-Rawnak-Signature": f"sha256={signature}"}
php
$signature = hash_hmac('sha256', $rawBody, $secret);
$headers = ['X-Rawnak-Signature: sha256=' . $signature];

Signature verification

RawNak signs the exact request body with HMAC-SHA256. The outbound header is X-Rawnak-Signature with the sha256= prefix.

  • Read the raw bytes before parsing JSON.
  • Compute HMAC-SHA256 with the workspace secret.
  • Compare the hexadecimal digest using a constant-time comparison.
  • Reject requests with a missing or mismatched signature.
node
import crypto from "node:crypto";
const signature = crypto.createHmac("sha256", process.env.RAWNAK_SECRET)
  .update(rawBody).digest("hex");
// Send: X-Rawnak-Signature: sha256=<signature>
python
import hashlib, hmac
signature = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
headers = {"X-Rawnak-Signature": f"sha256={signature}"}
php
$signature = hash_hmac('sha256', $rawBody, $secret);
$headers = ['X-Rawnak-Signature: sha256=' . $signature];

Plans and limits

The following values are the current PLAN_LIMITS and feature maps in webhook_server.py.

  • Free trial: 1 destination, 1,000 monthly events, 5 events/second, 1 concurrent request; core feature only.
  • Starter: 3 destinations, 10,000 monthly events, 5 events/second, 1 concurrent request; core feature only.
  • Growth: 10 destinations, 100,000 monthly events, 100 events/second, 10 concurrent requests; Telegram alerts and rate limiting.
  • Enterprise: 50 destinations, 1,000,000 monthly events, 1,000 events/second, 20 concurrent requests; payload filtering, bulk replay and team audit.
  • Retention is configured per workspace in settings.retention_days and bounded by the backend between 1 and 3,650 days; the default is trial 7 days, Starter 30 days, Growth 90 days, Enterprise 180 days.

Errors reference

API errors use JSON responses. The exact message may depend on lifecycle, validation and plan state.

  • 400 — invalid input, unsupported plan, malformed request or invalid signature payload.
  • 401 — missing, expired or invalid authentication; also invalid admin password/MFA credentials.
  • 402 — billing/lifecycle access is required before using the requested API.
  • 403 — authenticated user lacks the required admin or company permission.
  • 404 — resource or route not found.
  • 409 — conflicting state such as an existing subscription or duplicate action.
  • 429 — rate limit; retry after the Retry-After delay.
  • 500/503 — temporary server issue; retry later or contact [email protected].

Security best practices

Treat webhook secrets, dashboard tokens and destination credentials as server-side secrets.

  • Verify X-Rawnak-Signature against the raw request bytes.
  • Use HTTPS for destinations and keep redirects disabled.
  • Rotate signing secrets when a credential may have been exposed.
  • Use the smallest plan feature set and least privilege needed.
  • Do not log authorization headers, cookies or webhook secrets.

FAQ

The free trial lasts 7 days. Plan access and lifecycle rules are enforced by the backend, not by the browser. For implementation-specific behavior, use the endpoint and error references above.

Changelog

Release 4-1 adds this developer documentation surface and technical SEO preparation. Endpoint behavior remains owned by the backend implementation.