Safeput
Type to search documentation.

Reference

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.

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.

Last updated Aug 30, 2026