Full workflow

Select a language to see the complete integration example.

import base64
import time
import requests

API_KEY = "vnd_your_api_key"
BASE_URL = "https://api.helvetii.ai"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}


def process_document(file_path: str, project: str, document_type: str) -> dict:
    """Submit a document and wait for the result."""
    with open(file_path, "rb") as f:
        file_b64 = base64.b64encode(f.read()).decode()

    # Submit
    resp = requests.post(
        f"{BASE_URL}/process_file",
        headers=HEADERS,
        json={
            "file_base64": file_b64,
            "project": project,
            "document_type": document_type,
        },
    )
    resp.raise_for_status()
    task_id = resp.json()["task_id"]

    # Poll
    while True:
        status = requests.get(
            f"{BASE_URL}/task_status/{task_id}",
            headers=HEADERS,
        ).json()

        if status["status"] == "complete":
            return status["result"]
        if status["status"] == "failed":
            raise RuntimeError(status["error"])

        time.sleep(2)


result = process_document("invoice.pdf", "my_project", "invoice")
print(result)
const API_KEY = "vnd_your_api_key";
const BASE_URL = "https://api.helvetii.ai";

async function processDocument(
  file: File,
  project: string,
  documentType: string
): Promise<Record<string, unknown>> {
  const buffer = await file.arrayBuffer();
  const fileBase64 = btoa(
    String.fromCharCode(...new Uint8Array(buffer))
  );

  // Submit
  const submitRes = await fetch(`${BASE_URL}/process_file`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      file_base64: fileBase64,
      project,
      document_type: documentType,
    }),
  });

  if (!submitRes.ok) throw new Error(await submitRes.text());
  const { task_id } = await submitRes.json();

  // Poll
  while (true) {
    const statusRes = await fetch(
      `${BASE_URL}/task_status/${task_id}`,
      { headers: { Authorization: `Bearer ${API_KEY}` } }
    );
    const status = await statusRes.json();

    if (status.status === "complete") return status.result;
    if (status.status === "failed") throw new Error(status.error);

    await new Promise((r) => setTimeout(r, 2000));
  }
}
# Step 1: Submit the document
TASK_ID=$(curl -s -X POST https://api.helvetii.ai/process_file \
  -H "Authorization: Bearer vnd_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "file_base64": "'$(base64 -i invoice.pdf)'",
    "project": "my_project",
    "document_type": "invoice"
  }' | jq -r '.task_id')

echo "Task ID: $TASK_ID"

# Step 2: Poll until complete
while true; do
  RESULT=$(curl -s https://api.helvetii.ai/task_status/$TASK_ID \
    -H "Authorization: Bearer vnd_your_api_key")

  STATUS=$(echo $RESULT | jq -r '.status')

  if [ "$STATUS" = "complete" ]; then
    echo $RESULT | jq '.result'
    break
  elif [ "$STATUS" = "failed" ]; then
    echo "Error:" $(echo $RESULT | jq -r '.error')
    break
  fi

  sleep 2
done
package main

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

const (
	apiKey  = "vnd_your_api_key"
	baseURL = "https://api.helvetii.ai"
)

func processDocument(filePath, project, docType string) (map[string]any, error) {
	data, err := os.ReadFile(filePath)
	if err != nil {
		return nil, err
	}

	body, _ := json.Marshal(map[string]any{
		"file_base64":   base64.StdEncoding.EncodeToString(data),
		"project":       project,
		"document_type": docType,
	})

	req, _ := http.NewRequest("POST", baseURL+"/process_file", bytes.NewReader(body))
	req.Header.Set("Authorization", "Bearer "+apiKey)
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var submitResult struct{ TaskID string `json:"task_id"` }
	json.NewDecoder(resp.Body).Decode(&submitResult)

	// Poll for result
	for {
		req, _ := http.NewRequest("GET",
			fmt.Sprintf("%s/task_status/%s", baseURL, submitResult.TaskID), nil)
		req.Header.Set("Authorization", "Bearer "+apiKey)

		resp, err := http.DefaultClient.Do(req)
		if err != nil {
			return nil, err
		}

		respBody, _ := io.ReadAll(resp.Body)
		resp.Body.Close()

		var status struct {
			Status string         `json:"status"`
			Result map[string]any `json:"result"`
			Error  string         `json:"error"`
		}
		json.Unmarshal(respBody, &status)

		switch status.Status {
		case "complete":
			return status.Result, nil
		case "failed":
			return nil, fmt.Errorf("task failed: %s", status.Error)
		}

		time.Sleep(2 * time.Second)
	}
}

func main() {
	result, err := processDocument("invoice.pdf", "my_project", "invoice")
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	fmt.Println(result)
}
<?php

$apiKey  = "vnd_your_api_key";
$baseUrl = "https://api.helvetii.ai";

function processDocument(string $filePath, string $project, string $docType): array
{
    global $apiKey, $baseUrl;

    $fileB64 = base64_encode(file_get_contents($filePath));

    // Submit
    $ch = curl_init("$baseUrl/process_file");
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER     => [
            "Authorization: Bearer $apiKey",
            "Content-Type: application/json",
        ],
        CURLOPT_POSTFIELDS => json_encode([
            "file_base64"   => $fileB64,
            "project"       => $project,
            "document_type" => $docType,
        ]),
    ]);

    $response = json_decode(curl_exec($ch), true);
    curl_close($ch);
    $taskId = $response["task_id"];

    // Poll
    while (true) {
        $ch = curl_init("$baseUrl/task_status/$taskId");
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER     => ["Authorization: Bearer $apiKey"],
        ]);

        $status = json_decode(curl_exec($ch), true);
        curl_close($ch);

        if ($status["status"] === "complete") {
            return $status["result"];
        }
        if ($status["status"] === "failed") {
            throw new RuntimeException($status["error"]);
        }

        sleep(2);
    }
}

$result = processDocument("invoice.pdf", "my_project", "invoice");
print_r($result);

How it works

  1. 1Read and encode — Load the PDF or image file and base64-encode its binary content.
  2. 2Submit — POST the encoded file to /process_file with your project and document type. The API returns a task_id.
  3. 3Poll — GET /task_status/{task_id} every 2 seconds until status is complete or failed.
  4. 4Extract — Read the structured data from the result field.

Error handling

The API returns standard HTTP status codes. All error responses include a detail field with a human-readable message.

CodeHandling
401Check API key format and validity. Keys use vnd_ prefix.
402Subscription inactive. Renew or contact support.
404Project or document type not found. Verify the ID or name.
422Validation error. Check required fields and data formats.
500Server error. Retry with exponential backoff.

Tip

For production use, implement retries with exponential backoff for 5xx errors. A good starting point is 3 attempts with 1s, 2s, and 4s delays.