Suchen
POST /api/v1/search durchsucht die Team-Bibliothek des API-Key-Inhabers. Der
Endpoint benötigt den Scope search und akzeptiert ein JSON-Objekt. Alle
Felder sind optional.
Request
| Feld | Typ | Standard | Beschreibung |
|---|---|---|---|
q | string | keiner | Nicht leere Freitextsuche. Ohne q erscheinen die neuesten Dateien zuerst. |
mode | string | hybrid | hybrid, text oder vector; wird mit q verwendet. |
filters | object | {} | Strukturierte Filter wie unten beschrieben. |
limit | number | 50 | Ganze Zahl von 1 bis 100. |
cursor | string | keiner | Opaque Cursor der vorherigen Seite. |
hybrid kombiniert BM25 Full-Text Search mit Semantic Similarity. text
verwendet nur BM25, vector nur Semantic Search.
{
"q": "Sonnenuntergang am Strand",
"mode": "hybrid",
"filters": {
"media_type": { "image": "include" },
"rating": { "3:4": "include", "3:5": "include" }
},
"limit": 25
}curl --fail-with-body \
-X POST "$NEW_ARCHIVE_URL/api/v1/search" \
-H "Authorization: Bearer $NEW_ARCHIVE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"q": "Sonnenuntergang am Strand",
"mode": "hybrid",
"filters": {"media_type": {"image": "include"}},
"limit": 10
}'Response
{
"items": [
{
"id": "0198c9a0-7d3e-7c41-b7a2-3f9d1c2e4a5b",
"status": "ready",
"original_name": "sunset.jpg",
"mime_type": "image/jpeg",
"size_bytes": 2481931,
"width": 4000,
"height": 3000,
"taken_at": "2026-06-30T18:41:02.000Z",
"created_at": "2026-07-11T09:12:44.201Z",
"thumbnail_url": "https://storage.example/signed-thumbnail"
}
],
"next_cursor": "eyJvIjoyNX0"
}Einträge verwenden dasselbe Schema wie
GET /api/v1/files/:fileId.
Fertige Dateien enthalten eine Signed URL für ein kleines Thumbnail.
next_cursor fehlt, wenn es keine weitere Seite gibt.
Pagination
Sende next_cursor unverändert zurück und behalte Query, Mode, Filter und
Limit bei. Cursor sind opaque und dürfen von Clients weder erzeugt noch
dekodiert werden.
async function searchAll(request) {
const items = []
let cursor
do {
const response = await fetch(
`${process.env.NEW_ARCHIVE_URL}/api/v1/search`,
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.NEW_ARCHIVE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ ...request, cursor }),
}
)
const page = await response.json()
if (!response.ok)
throw new Error(`${page.error.code}: ${page.error.message}`)
items.push(...page.items)
cursor = page.next_cursor
} while (cursor)
return items
}Filterverhalten
Die meisten Filterkategorien sind Tri-State-Maps. Jeder Wert verweist auf
include oder exclude; ein fehlender Wert ist neutral. include-Werte
innerhalb einer Kategorie werden per OR verknüpft, aktive Kategorien per AND.
exclude-Werte werden immer vom Ergebnis abgezogen.
{
"filters": {
"media_type": { "image": "include" },
"date": { "2026-06": "include" },
"camera_make": { "Canon": "exclude" }
}
}Dies wählt Bilder aus Juni 2026 aus, die nicht mit einer Canon aufgenommen wurden.
Filterreferenz
| Kategorie | Akzeptierte Keys |
|---|---|
date, import_date | YYYY, YYYY-MM oder YYYY-MM-DD. |
media_type | image, video, other. |
orientation | landscape, portrait, square. |
format | 1:1, 4:3, 3:2, 16:9, other. |
iso | low, medium, high oder eine exakte Ganzzahl wie 400. |
focal_length, focal_length_35mm | super-wide, wide-angle, normal, tele, super-tele oder exakte Millimeter als Ganzzahl. |
aperture | very-wide, wide, medium, narrow, very-narrow oder eine exakte Blendenzahl wie 1.8. |
shutter_speed | very-fast, fast, normal, slow, long oder exakte Sekunden wie 0.002. |
resolution | sd, hd, fhd, 4k, 6k, 8k. Die lange Kante bestimmt den Bucket. |
file_size | tiny, small, medium, large, xlarge, huge. |
person_count | none, single, two, three, small-group, big-group, crowd. |
lens | Exakte Objektivbezeichnung aus den Metadaten. |
color_space | srgb, display-p3, adobe-rgb, prophoto-rgb, uncalibrated. |
bit_depth | String wie 8, 10, 12, 14, 16 oder 32. |
file_type | Dateiendung in Kleinbuchstaben, etwa jpg, cr3 oder mp4. |
camera_make | Exakte Herstellerbezeichnung. |
camera_model | Hersteller:Modell, etwa Canon:EOS R5. |
geography | has_location oder no_location. |
versions | has_versions (mehr als die Ursprungsversion) oder no_versions. |
country, state, city, suburb | Standort-IDs als Strings. |
categories | Kategorie-IDs als Strings; ein Elternknoten schließt seinen Unterbaum ein. |
labels | Label-IDs als Strings. |
collections | Sammlungs-UUIDs. |
rating | <criterionId>:<stars>, <criterionId>:unrated, avg:<stars>, any:unrated oder any:incomplete. |
custom | <fieldId>:<value>, <fieldId>:__has__ oder <fieldId>:__empty__. |
File-Size-Buckets verwenden dezimale Bytes: tiny liegt unter 1 MB,
small bei 1–10 MB, medium bei 10–50 MB, large bei 50–250 MB, xlarge
bei 250 MB–1 GB und huge ab 1 GB.
avg:<stars> bucketet jede Datei nach dem gerundeten Mittel ihrer
durchschnittlichen Bewertungen pro Kriterium. Es zählen nur System- und
Team-Kriterien, für die die Datei Bewertungen hat; Bewertungen auf
Collection-Kriterien fließen nicht in den Durchschnitt der API ein.
ID-basierte Werte stammen aus eigenen Datensätzen oder der App. API v1 bietet keine Endpoints für Facetten- oder Taxonomielisten.
Numerische Custom Fields
custom_ranges ist keine Tri-State-Map. Die Keys sind Custom-Field-IDs; eine
der beiden Grenzen darf fehlen.
{
"filters": {
"custom_ranges": {
"7": { "min": 10, "max": 500 }
}
}
}Semantic Search steuern
Beschreibende Phrasen eignen sich gut für Semantic Search. Stelle einem
einzelnen Wort - voran, um das Konzept auszuschließen, etwa
Hund am Strand -Menschen.
Wenn q oder filters.similar_to gesetzt ist, legt filters.max_distance
einen Threshold für die Cosine Distance von 0 bis 1 fest. Niedrigere Werte
sind strenger, 1 deaktiviert den Threshold. Ohne Angabe gilt der
Server-Default (0.55).
{
"q": "goldene Stunde",
"filters": { "max_distance": 0.4 }
}Bildsuche
filters.similar_to nimmt die ID einer deiner Dateien und sortiert die
Ergebnisse nach visueller Ähnlichkeit zu ihr: ähnlichste zuerst, die Datei
selbst ausgenommen, alle anderen Filter grenzen die sortierte Menge ein. Ist
similar_to gesetzt, werden q und mode ignoriert. Eine gelöschte Datei
oder eine ohne Bild-Embedding (Videos und Dokumente bekommen keins) liefert
eine leere Liste.
{
"filters": {
"similar_to": "019b1a2c-3d4e-7f80-9a1b-2c3d4e5f6a7b",
"labels": { "12": "include" }
}
}