Integrations
TypeScript / Node.js
Integrate SafeURL into a TypeScript or Node.js application
No SDK required — the API is a standard REST interface. These examples use the native fetch API (Node 18+).
Setup
const SAFEURL_API = "https://api.safeurl.ai";
const API_KEY = process.env.SAFEURL_API_KEY!; // sk_live_...
function safeurl(path: string, init?: RequestInit) {
return fetch(`${SAFEURL_API}${path}`, {
...init,
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
...init?.headers,
},
});
}Single scan
type ScanState =
| "QUEUED"
| "FETCHING"
| "ANALYZING"
| "COMPLETED"
| "FAILED"
| "TIMED_OUT";
interface ScanResult {
riskScore: number; // 0–100
confidence: number; // 0–1
categories: string[];
reasoning: string;
indicators: string[];
}
interface ScanJob {
id: string;
url: string;
state: ScanState;
result?: ScanResult;
createdAt: string;
}
async function scan(url: string): Promise<ScanJob> {
const res = await safeurl("/v1/scans", {
method: "POST",
body: JSON.stringify({ url }),
});
if (!res.ok) throw new Error(`Scan failed: ${res.status}`);
return res.json() as Promise<ScanJob>;
}
const job = await scan("https://example.com");
console.log(job.id, job.state); // job_01j... QUEUEDPoll until complete
async function waitForScan(
jobId: string,
timeoutMs = 60_000,
): Promise<ScanJob> {
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
const res = await safeurl(`/v1/scans/${jobId}`);
const job = (await res.json()) as ScanJob;
if (job.state === "COMPLETED" || job.state === "FAILED") return job;
await new Promise((r) => setTimeout(r, 2000));
}
throw new Error(`Scan ${jobId} timed out after ${timeoutMs}ms`);
}
const completed = await waitForScan(job.id);
console.log(completed.result?.riskScore); // e.g. 12Stream state transitions (SSE)
import { EventSource } from "eventsource"; // npm i eventsource
function streamScan(jobId: string): Promise<ScanJob> {
return new Promise((resolve, reject) => {
const es = new EventSource(`${SAFEURL_API}/v1/scans/${jobId}/events`, {
headers: { Authorization: `Bearer ${API_KEY}` },
});
es.onmessage = (event) => {
const job = JSON.parse(event.data) as ScanJob;
if (job.state === "COMPLETED" || job.state === "FAILED") {
es.close();
resolve(job);
}
};
es.onerror = (err) => {
es.close();
reject(err);
};
});
}Batch scan
Scan up to 50 URLs in a single request. All jobs share a batchId.
interface BatchResponse {
batchId: string;
jobs: ScanJob[];
}
async function batchScan(urls: string[]): Promise<BatchResponse> {
const res = await safeurl("/v1/scans/batch", {
method: "POST",
body: JSON.stringify({ urls }),
});
if (!res.ok) throw new Error(`Batch scan failed: ${res.status}`);
return res.json() as Promise<BatchResponse>;
}
const { batchId, jobs } = await batchScan([
"https://example.com",
"https://suspicious-site.xyz",
]);
// Poll all jobs
const results = await Promise.all(jobs.map((j) => waitForScan(j.id)));