# Examples

Minimal server-side Safeput integration examples.

Use Safeput only from trusted server-side code. The browser should send the file
to your backend first; your backend creates the upload record and returns only
the short-lived upload target to the browser.

## Create an upload with TypeScript

```ts
const apiKey = process.env.SAFEPUT_API_KEY;

const response = await fetch("https://dev.safeput.dev/v1/uploads", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${apiKey}`,
    "Content-Type": "application/json",
    "Idempotency-Key": crypto.randomUUID(),
  },
  body: JSON.stringify({
    filename: "invoice.pdf",
    content_type: "application/pdf",
    size: 12_480,
  }),
});

if (!response.ok) throw new Error(`Safeput returned ${response.status}`);

const { upload, upload_target: target } = await response.json();
```

Send the exact bytes to `target.url` with `target.method` and every header from
`target.headers`. Do not attach your project API key to that request.

## Wait for a terminal verdict

For a first integration, poll `GET /v1/uploads/:id` with a bounded delay. In a
production integration, prefer [signed webhooks](/docs/webhooks/).

```ts
const terminal = new Set(["clean", "rejected", "failed", "expired"]);

while (!terminal.has(upload.status)) {
  await new Promise((resolve) => setTimeout(resolve, 1_500));
  const response = await fetch(
    `https://dev.safeput.dev/v1/uploads/${upload.id}`,
    { headers: { Authorization: `Bearer ${apiKey}` } },
  );
  ({ upload } = await response.json());
}
```

Request a download URL only when `upload.status === "clean"` and
`upload.download_available` is true.
