Code Examples

Working malware-scanning examples in 7 languages. Scan by file upload or URL. The API is a single REST endpoint — any language that can make an HTTP request will work.

Every field, status code and response shape is in the API reference.

curl

Terminal — the 30-second test

# 1. Submit a file (you get a ticket back instantly)
curl -H "Authorization: Bearer $UPSCAN_KEY" \
     -F file=@upload.pdf \
     https://api.upscan.example/v1/scans
# → { "id": "4821…", "status": "pending" }

# 2. Collect the verdict a couple of seconds later
curl -H "Authorization: Bearer $UPSCAN_KEY" \
     https://api.upscan.example/v1/scans/4821…
# → { "status": "done", "verdict": "clean", "sha256": "…" }

# Or scan a URL instead of uploading:
curl -H "Authorization: Bearer $UPSCAN_KEY" \
     -H "Content-Type: application/json" \
     -d '{"url":"https://example.com/report.pdf"}' \
     https://api.upscan.example/v1/scans

Node.js / TypeScript

Framework: Express · Client: built-in fetch (Node 18+)

import fs from "node:fs/promises";

const API = "https://api.upscan.example";
const KEY = process.env.UPSCAN_KEY;

async function scanFile(path) {
  // 1. Submit
  const form = new FormData();
  form.append("file", new Blob([await fs.readFile(path)]), path);

  const res = await fetch(`${API}/v1/scans`, {
    method: "POST",
    headers: { Authorization: `Bearer ${KEY}` },
    body: form,
  });
  const { id } = await res.json();

  // 2. Poll until the verdict lands (or use webhook_url instead)
  while (true) {
    await new Promise((r) => setTimeout(r, 1500));
    const scan = await (await fetch(`${API}/v1/scans/${id}`, {
      headers: { Authorization: `Bearer ${KEY}` },
    })).json();
    if (scan.status === "done" || scan.status === "error") return scan;
  }
}

const scan = await scanFile("upload.pdf");
if (scan.verdict === "infected") {
  console.log(`Blocked: ${scan.signature}`);  // reject the upload
}

Prefer push over polling? Add form.append("webhook_url", "https://yoursite.com/hooks/upscan") and we'll POST the verdict to you, signed with your webhook secret.

Python

Framework: Flask / Django · Client: requests

Install: pip install requests

import os, time, requests

API = "https://api.upscan.example"
HEADERS = {"Authorization": f"Bearer {os.environ['UPSCAN_KEY']}"}

def scan_file(path):
    # 1. Submit
    with open(path, "rb") as f:
        r = requests.post(f"{API}/v1/scans",
                          headers=HEADERS, files={"file": f})
    scan_id = r.json()["id"]

    # 2. Poll until done (or pass webhook_url and skip this)
    while True:
        time.sleep(1.5)
        scan = requests.get(f"{API}/v1/scans/{scan_id}",
                            headers=HEADERS).json()
        if scan["status"] in ("done", "error"):
            return scan

scan = scan_file("upload.pdf")
if scan["verdict"] == "infected":
    raise ValueError(f"Blocked: {scan['signature']}")

PHP

Framework: plain PHP / Laravel · Client: built-in cURL

<?php
$api = "https://api.upscan.example";
$key = getenv("UPSCAN_KEY");

// 1. Submit
$ch = curl_init("$api/v1/scans");
curl_setopt_array($ch, [
  CURLOPT_POST => true,
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ["Authorization: Bearer $key"],
  CURLOPT_POSTFIELDS => ["file" => new CURLFile("upload.pdf")],
]);
$scan = json_decode(curl_exec($ch), true);

// 2. Poll until the verdict lands
do {
  usleep(1500000);
  $ch = curl_init("$api/v1/scans/{$scan['id']}");
  curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ["Authorization: Bearer $key"],
  ]);
  $scan = json_decode(curl_exec($ch), true);
} while (!in_array($scan["status"], ["done", "error"]));

if ($scan["verdict"] === "infected") {
  http_response_code(422);
  exit("Blocked: {$scan['signature']}");
}

Ruby

Framework: Rails / Sinatra · Client: net/http (stdlib)

require "net/http"
require "json"

API = URI("https://api.upscan.example")
KEY = ENV.fetch("UPSCAN_KEY")

def scan_file(path)
  # 1. Submit
  req = Net::HTTP::Post.new("#{API}/v1/scans")
  req["Authorization"] = "Bearer #{KEY}"
  req.set_form([["file", File.open(path)]], "multipart/form-data")
  scan = JSON.parse(Net::HTTP.start(API.host, API.port, use_ssl: true) { |h| h.request(req) }.body)

  # 2. Poll until done
  loop do
    sleep 1.5
    res = Net::HTTP.get(URI("#{API}/v1/scans/#{scan['id']}"),
                        { "Authorization" => "Bearer #{KEY}" })
    scan = JSON.parse(res)
    break scan if %w[done error].include?(scan["status"])
  end
end

scan = scan_file("upload.pdf")
raise "Blocked: #{scan['signature']}" if scan["verdict"] == "infected"

Go

Client: net/http + mime/multipart (stdlib)

package main

import (
  "bytes"; "encoding/json"; "fmt"; "io"
  "mime/multipart"; "net/http"; "os"; "time"
)

const api = "https://api.upscan.example"

func scanFile(path string) (map[string]any, error) {
  key := os.Getenv("UPSCAN_KEY")

  // 1. Submit
  var buf bytes.Buffer
  w := multipart.NewWriter(&buf)
  fw, _ := w.CreateFormFile("file", path)
  f, _ := os.Open(path); defer f.Close()
  io.Copy(fw, f); w.Close()

  req, _ := http.NewRequest("POST", api+"/v1/scans", &buf)
  req.Header.Set("Authorization", "Bearer "+key)
  req.Header.Set("Content-Type", w.FormDataContentType())
  res, err := http.DefaultClient.Do(req)
  if err != nil { return nil, err }
  var scan map[string]any
  json.NewDecoder(res.Body).Decode(&scan)

  // 2. Poll until done
  for scan["status"] != "done" && scan["status"] != "error" {
    time.Sleep(1500 * time.Millisecond)
    req, _ := http.NewRequest("GET",
      fmt.Sprintf("%s/v1/scans/%v", api, scan["id"]), nil)
    req.Header.Set("Authorization", "Bearer "+key)
    res, _ := http.DefaultClient.Do(req)
    json.NewDecoder(res.Body).Decode(&scan)
  }
  return scan, nil
}

func main() {
  scan, _ := scanFile("upload.pdf")
  if scan["verdict"] == "infected" {
    fmt.Println("Blocked:", scan["signature"])
  }
}

C# / .NET

Framework: Minimal API · Client: HttpClient

using System.Net.Http.Headers;
using System.Text.Json;

var api = "https://api.upscan.example";
var key = Environment.GetEnvironmentVariable("UPSCAN_KEY");

var http = new HttpClient();
http.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", key);

// 1. Submit
using var form = new MultipartFormDataContent();
form.Add(new ByteArrayContent(File.ReadAllBytes("upload.pdf")),
         "file", "upload.pdf");
var res = await http.PostAsync($"{api}/v1/scans", form);
var scan = JsonDocument.Parse(await res.Content.ReadAsStringAsync()).RootElement;
var id = scan.GetProperty("id").GetString();

// 2. Poll until the verdict lands
string status;
do {
  await Task.Delay(1500);
  var body = await http.GetStringAsync($"{api}/v1/scans/{id}");
  scan = JsonDocument.Parse(body).RootElement;
  status = scan.GetProperty("status").GetString()!;
} while (status != "done" && status != "error");

if (scan.GetProperty("verdict").GetString() == "infected")
    Console.WriteLine($"Blocked: {scan.GetProperty("signature")}");

Need a different language?

The API is a simple REST endpoint. If you can make an HTTP request, you can scan files.

Get your free API key