zoxaAI
Homepage
API ReferenceKnowledge Base

Get an upload URL

POST /api/v1/knowledge-base/upload-url — get a presigned S3/MinIO URL to PUT a file directly.

POST /api/v1/knowledge-base/upload-url

Get a presigned PUT URL so you can upload a file directly to storage without proxying through zoxaAI. Two-step flow: get URL → PUT file → call process-document to start chunking + embedding.

Request body

FieldTypeRequiredNotes
filenamestring✓The file's display name. Used to name the S3 key.
mime_typestring✓Content type to enforce on upload (e.g. application/pdf).

Response

{
  "upload_url":   "https://.../signed?...",
  "document_uuid": "abc12345-...",
  "s3_key":        "knowledge_base/<org>/<uuid>/file.pdf"
}
FieldNotes
upload_urlPresigned PUT URL valid for 30 minutes. Maximum 100 MB.
document_uuidUUID for the future document record. Pass it back to process-document.
s3_keyInternal storage key. Pass it back to process-document.

Examples

# 1. Get the URL
RESP=$(curl -s -X POST https://dashboard.zoxa.ai/api/v1/knowledge-base/upload-url \
  -H "X-API-Key: zsk_..." \
  -H "Content-Type: application/json" \
  -d '{"filename":"product-faq.pdf","mime_type":"application/pdf"}')

UPLOAD_URL=$(echo "$RESP" | jq -r .upload_url)
DOC_UUID=$(echo "$RESP" | jq -r .document_uuid)
S3_KEY=$(echo "$RESP" | jq -r .s3_key)

# 2. PUT the file
curl -X PUT "$UPLOAD_URL" \
  -H "Content-Type: application/pdf" \
  --upload-file ./product-faq.pdf

# 3. Trigger processing
curl -X POST https://dashboard.zoxa.ai/api/v1/knowledge-base/process-document \
  -H "X-API-Key: zsk_..." \
  -H "Content-Type: application/json" \
  -d "{\"document_uuid\":\"$DOC_UUID\",\"s3_key\":\"$S3_KEY\",\"retrieval_mode\":\"chunked\"}"
import fs from "node:fs";

// 1. URL
const { upload_url, document_uuid, s3_key } = await fetch(
  "https://dashboard.zoxa.ai/api/v1/knowledge-base/upload-url",
  {
    method: "POST",
    headers: { "X-API-Key": "zsk_...", "Content-Type": "application/json" },
    body: JSON.stringify({ filename: "product-faq.pdf", mime_type: "application/pdf" }),
  },
).then((r) => r.json());

// 2. PUT
await fetch(upload_url, {
  method: "PUT",
  headers: { "Content-Type": "application/pdf" },
  body: fs.createReadStream("./product-faq.pdf"),
});

// 3. Process
await fetch("https://dashboard.zoxa.ai/api/v1/knowledge-base/process-document", {
  method: "POST",
  headers: { "X-API-Key": "zsk_...", "Content-Type": "application/json" },
  body: JSON.stringify({ document_uuid, s3_key, retrieval_mode: "chunked" }),
});
import httpx

# 1. URL
resp = httpx.post(
    "https://dashboard.zoxa.ai/api/v1/knowledge-base/upload-url",
    headers={"X-API-Key": "zsk_..."},
    json={"filename": "product-faq.pdf", "mime_type": "application/pdf"},
).json()

# 2. PUT
with open("product-faq.pdf", "rb") as f:
    httpx.put(resp["upload_url"], content=f.read(), headers={"Content-Type": "application/pdf"})

# 3. Process
httpx.post(
    "https://dashboard.zoxa.ai/api/v1/knowledge-base/process-document",
    headers={"X-API-Key": "zsk_..."},
    json={
        "document_uuid": resp["document_uuid"],
        "s3_key": resp["s3_key"],
        "retrieval_mode": "chunked",
    },
)

Single-call alternative

For server-side flows that already have the file in memory, POST /files handles upload + register in one multipart request — slightly simpler if you don't need direct browser upload.

Errors

StatusdetailWhen
500"Failed to generate presigned upload URL"Storage backend isn't returning a URL — usually misconfiguration.

On this page