# Webhooks

> Learn how Copyleaks notifies your server the moment a job finishes, so you never have to poll for results.

A **webhook** is a push notification for your server. Jobs run **asynchronously** and can take a while to finish, so instead of polling (asking *"is it done yet?"* in a loop), you give us a URL when you submit a job. The moment it finishes, we send an HTTP `POST` to that URL with the result. It's faster, real-time, and scales without wasting requests.

How you configure the URL depends on the job.

## One URL, several events

Some jobs move through multiple events - a cost check, indexing, completion, an error - and you may want to react to each one separately. For these you give a single URL with a `{STATUS}` token, for example:

`https://yoursite.com/copyleaks/{STATUS}/SCAN_ID`

We replace `{STATUS}` with the event name before calling, so each event lands on its own path and your server handles them separately. Putting the job ID in the path is optional but recommended; it lets you match the call to the right record at a glance. Some jobs can also stream partial results as they're found, before the job completes - handy for time-sensitive integrations.

The exact field and the full list of events depend on the product - see each product's reference for specifics.

## Identifying and trusting the call

Your endpoint is a public door on the internet, so treat every call as untrusted until verified.

Pass a `developerPayload` at submission and we echo it back in every webhook - use it to match a call to your own record. To confirm a call really came from us, attach custom **headers** to every webhook carrying a secret such as a bearer token, then validate it on receipt and pass the call through your existing auth middleware. For stronger guarantees we also support HTTPS client certificates and, on Enterprise, delivery from a fixed set of static IPs you can allowlist.

<Warning>
Never act on a webhook before confirming it came from us. Validate a shared secret in your headers (or a client certificate) on every request, and reject anything that doesn't match.
</Warning>

## Choosing the HTTP verb

By default we send each webhook as a `POST`. Where a webhook uploads a file for you to store, you can choose the HTTP method instead (for example `PUT`) to match whatever your endpoint or storage target expects.

## Export straight to a storage bucket

A webhook target doesn't have to be your own server. When you only want to **store** an asset and there's no logic to run, point the webhook at a storage service like **Amazon S3**, **Google Cloud Storage**, or **Azure Blob Storage** and we'll upload the file directly into your bucket.

This is a clean, serverless option: no endpoint to host, scale, or keep online. Use a signed/authorized upload URL, set the HTTP verb your provider expects (often `PUT`), and add any required auth via custom headers - the asset lands in your bucket with no code in between.

## Designing for reliable delivery

Your endpoint must be **publicly reachable over HTTPS** and respond within **70 seconds** with a `2xx`. Return success as soon as you've accepted the payload, then do the heavy work afterward.

On a timeout or `5xx`, we retry automatically - up to **17 attempts** on an exponential backoff (1, 2, 4, 8 seconds, and so on). Because of retries, delivery is **at-least-once**: the same webhook can occasionally arrive twice.

<Note>
Make your handlers **idempotent**. Key off a stable identifier like the scan ID or your `developerPayload` so receiving a webhook twice does no harm - no duplicate charges, no double-processing.
</Note>

For scans, if you miss a webhook you can re-trigger it with the [resend webhook](/reference/actions/authenticity/resend-webhook) endpoint.

## Testing without spending credits

Set `sandbox: true` on any submission to receive **real webhooks with mock results**, free. It's the fastest way to build and verify your receiver before going live.

<Tip>
Point your sandbox webhook at a temporary public URL (for example, a local tunneling tool) so you can inspect exactly what we send before wiring up production.
</Tip>

## Next steps

<CardGroup cols={2}>
  <Card title="Authenticity Scan Webhooks" icon="plug" href="/reference/data-types/authenticity/webhooks/overview">The full reference for authenticity scan webhooks and their configuration.</Card>
  <Card title="AI Image Detection (Async)" icon="image" href="/reference/actions/ai-image-detector/submit">Submit an image and receive the detection result via webhook.</Card>
  <Card title="AI Video Detection" icon="video" href="/reference/actions/ai-video-detector/submit">Submit a video and receive the detection result via webhook.</Card>
  <Card title="Webhooks Security" icon="lock" href="/concepts/security/webhooks">Secure your endpoints with secrets, certificates, and IP allowlisting.</Card>
</CardGroup>
