Skavio Processing API: verify the webhook, then authenticate the download

Skavio Processing API supports signed completion webhooks and authenticated result downloads, allowing your application to handle asynchronous processing without keeping the original request open. These features protect different boundaries: the webhook signature verifies the notification, while download authentication controls access to the output. A reliable integration keeps those checks separate—and records the event durably before acknowledging it.

1. Register the callback and attach it to the job

Start with a public HTTPS endpoint on your receiving server. Register it through the Skavio dashboard or through an administrator session using POST /v1/webhooks. Registration is not an ordinary Bearer-key operation. Save the webhook signing secret when it is shown: it is displayed once. Keep it in server-side secret storage, separate from the API key used to access jobs and download results. Pass the registration’s returned id as webhook_id when submitting a processing job. Also persist the relationship between your application’s request, the Skavio job and the company that owns it. That record lets a background worker connect a completion event to the correct internal workflow without trusting an incoming identifier alone. Use Skavio’s idempotent submission support when retrying a submission after a network timeout; webhook handling does not replace submission idempotency.

2. Verify the unchanged request before acting on it

The documented completion and failure event types are job.completed and job.failed. The event envelope contains id, type, created_at and job; the request includes X-Skavio-Signature, X-Skavio-Timestamp and X-Skavio-Event-Id. Capture the exact request-body bytes before JSON parsing or reserialization. The expected signature is `v1=` followed by the hexadecimal HMAC-SHA256 of the timestamp, a literal period and the raw body bytes, keyed with the webhook signing secret. Changing whitespace or rebuilding JSON can change the signed content. The official Python verifier rejects malformed timestamps and timestamps more than 300 seconds in either direction from the receiver’s clock. It then uses hmac.compare_digest for constant-time signature comparison. Follow that construction rather than borrowing another provider’s header names or signing format. After verification, parse the body and validate the event. As an additional application-level check, require X-Skavio-Event-Id to match the id inside the verified body before deduplicating: the documented signature covers the timestamp and body, not that header separately. This matching check is a defensive recommendation, not a documented Skavio requirement.

3. Record durably, acknowledge promptly, process separately

Use a durable inbox rather than downloading files inside the callback request. After verification, transactionally insert the event into your database with a uniqueness constraint—for example, on the webhook registration and verified event id. Return a 2xx response only after that transaction commits. A background worker can then process pending inbox records independently. For a duplicate that is already durably recorded, return 2xx without repeating downstream effects. If persistence fails, do not acknowledge successful receipt: an early 2xx could leave Skavio considering the notification delivered while your application has no recoverable record. The worker should distinguish job.completed from job.failed before attempting retrieval. A failure notification belongs on your error-handling path, not on a download path. Record worker progress separately from receipt so a crash after acknowledgement does not strand the event. This transactional-inbox design is an integration recommendation, not a built-in Skavio queue. Event deduplication also does not by itself make later actions exactly once: file storage, notifications and business-system updates need their own retry-safe handling.

4. Download through the authenticated API—not through trust in the callback

For a completed job, use the API-returned result.files download_path. Make the initial request from your backend with Bearer authentication and a suitably scoped company API key. A verified webhook is not a download credential, and its signing secret must not be used as one. Resolve the returned path against your configured Skavio API origin and validate that the initial request stays on that origin rather than accepting an arbitrary download host from incoming data. Preserve the company-to-job association when choosing credentials, and keep API keys out of browser code and URL query strings. Storage-backed downloads can return HTTP 307 to a short-lived signed URL. That storage URL needs no Skavio API key. Configure redirect handling so the Authorization header is not forwarded to the storage host. The official guide recommends curl -L without --location-trusted; check the equivalent behavior explicitly in your HTTP client. Treat the temporary signed URL as sensitive while it is valid: possession enables retrieval without an API key. Avoid logging it, verify that the download succeeded, and store the output under your application’s own access controls.

5. Reconcile missing notifications before retention expires

Skavio documents at-least-once callback delivery with up to six attempts. Approximate retry delays are 60, 120, 240, 480 and 960 seconds; callback redirects are not followed. Configure the registered callback URL to reach the receiver directly rather than relying on a redirect. Bounded retries are not a guarantee that every event will eventually reach your application. Run periodic authenticated reconciliation for outstanding jobs, and send discovered completions through the same retry-safe processing path as webhook events. Do not submit a new processing job simply because its callback is missing. Plan around the seven-day retention period in Skavio’s supplied product information. Retrieve outputs promptly and alert on jobs that remain unresolved or completed but not downloaded. Do not assume extended retention without confirmation. Before deployment, test the failure paths as carefully as the successful download. The goal is not merely to receive a callback: it is to recover a result safely when requests are duplicated, storage is unavailable or your receiver restarts.

Read the Processing API documentation →