Skip to content

API-Referenz

Die Owning.pro API ist eine RESTful API zum Suchen, Durchsuchen, Erstellen und Verwalten von Kleinanzeigen. Alle Endpoints geben JSON zurück; Anzeige-Endpoints unterstützen außerdem Markdown-Antworten. Die API ist verfügbar unter https://api.owning.pro und proxied unter https://owning.pro/api.

Interaktive Dokumentation

Ein interaktiver API-Explorer (powered by Scalar) ist verfügbar unter https://api.owning.pro/api/docs. Die rohe OpenAPI 3.1-Spezifikation befindet sich unter /api/openapi.json.

Endpoint-Übersicht

MethodeEndpointBeschreibungAuthentifizierung
GET/api/listingsSearch listings with filters
POST/api/listingsCreate a listing (draft)*
GET/api/listings/{id}Get listing detail (JSON)
GET/api/listings/{id}.mdGet listing detail (Markdown)
PUT/api/listings/{id}Update listing (owner)*
DELETE/api/listings/{id}Delete listing (owner)*
PATCH/api/listings/{id}Change listing status*
POST/api/listings/{id}/publishPublish a draft listing*
POST/api/listings/{id}/contactContact the seller
POST/api/listings/{id}/imagesUpload images to listing*
GET/api/listings.mdListings catalog (Markdown)
GET/api/categoriesCategory tree with counts
GET/api/categories/{id}Category detail
GET/api/asset-typesList all asset type templates
GET/api/asset-types/{type}Get asset type template
POST/api/auth/registerRegister a new account
POST/api/auth/loginLogin (get JWT)
GET/api/meGet current user profile*
POST/api/api-keysCreate an API key*
GET/api/api-keysList API keys*
DELETE/api/api-keys/{id}Revoke an API key*
POST/api/uploadUpload a standalone image*
GET/api/schema/listingListing JSON Schema
GET/api/schema/listing.mdListing schema (Markdown)
GET/.well-known/ai.jsonAgent discovery document

* = Authentifizierung erforderlich (JWT oder API-Schlüssel)

Authentifizierung

Öffentliche Lese-Endpoints (GET) erfordern keine Authentifizierung. Schreiboperationen (POST, PUT, DELETE, PATCH) erfordern Authentifizierung.

docsApi.authDesc2

  • JWT-Sitzungs-Token – erhalten über POST /api/auth/register oder POST /api/auth/login. Gültig für 7 Tage.
  • API-Schlüssel – langlebige Schlüssel im own_...-Format, erstellt über POST /api/api-keys. Unterstützen Lese-, Schreib- und Admin-Berechtigungen.

Die API erkennt den Token-Typ automatisch: Token, die mit own_ beginnen, werden als API-Schlüssel behandelt; alle anderen als JWT-Sitzungen.

Einen API-Schlüssel erstellen

# 1. Register (or login if you have an account)
curl -X POST https://api.owning.pro/api/auth/register \
  -H "Content-Type: application/json" \
  -d '{"email":"user@example.com","password":"securepassword123","name":"Jane Doe"}'

# Response: { "user": {...}, "token": "eyJhbG...", "token_type": "bearer", "expires_in": 604800 }

# 2. Create an API key using the JWT
curl -X POST https://api.owning.pro/api/api-keys \
  -H "Authorization: Bearer eyJhbG..." \
  -H "Content-Type: application/json" \
  -d '{"name":"My Integration Key","permissions":"write"}'

# Response: { "id":"apk_...", "key":"own_aBcD123eFgH...", "key_prefix":"own_aBcD1", ... }
# The plaintext key is shown ONCE - store it securely.

# 3. Use the API key for all subsequent requests
curl https://api.owning.pro/api/listings \
  -H "Authorization: Bearer own_aBcD123eFgH..."

Rate-Limits

Auth-StatusBegrenzungGeltungsbereich
Unauthenticated100 req/minper IP
Authenticated (JWT or API key)300 req/minper user/key
Contact seller5 req/hourper IP
Listing creation10 req/dayper user
Image upload50 req/dayper user
AI listing generation5 req/hourper user

Rate-limitierte Antworten geben 429 Too Many Requests mit einem error.code von rate_limited zurück.

Antwortformate

Anzeige-Endpoints unterstützen zwei Antwortformate:

  • JSON (Standard) – application/json. Gibt strukturierte Anzeigeobjekte zurück.
  • Markdown – text/markdown. Gibt ein maschinenlesbares Markdown-Dokument mit YAML-Frontmatter zurück. Fordere es an, indem du .md an die URL anhängst oder Accept: text/markdown sendest.
# JSON (default)
curl https://api.owning.pro/api/listings/lagoon-400-s2-JP12QW

# Markdown - via .md suffix
curl https://api.owning.pro/api/listings/lagoon-400-s2-JP12QW.md

# Markdown - via Accept header
curl https://api.owning.pro/api/listings/lagoon-400-s2-JP12QW \
  -H "Accept: text/markdown"

Fehlerformat

Alle Fehler geben eine einheitliche JSON-Struktur zurück:

{
  "error": {
    "code": "not_found",
    "message": "Listing not found",
    "details": { "id": "lst_abc123" }
  }
}
HTTP-StatusFehlercodeBedeutung
400bad_requestMalformed request
400validation_errorField validation failed
400moderation_rejectedContent rejected by moderation
401unauthorizedMissing or invalid auth
403forbiddenNot the resource owner
404not_foundResource not found
409conflict / duplicate_listingConflict (e.g. duplicate)
429rate_limitedRate limit exceeded
500internal_errorServer error

Anzeigen

GET /api/listings

Suche und filtere Anzeigen mit Paginierung, Sortierung und dynamischen Attributfiltern. Öffentlich – keine Authentifizierung erforderlich.

Query-Parameter

ParameterTypStandardBeschreibung
qstringFull-text search (title, description, tags)
categorystringCategory ID or slug (hierarchical — includes descendants)
seller_idstringFilter by seller's user ID
min_pricenumberMinimum price (inclusive)
max_pricenumberMaximum price (inclusive)
include_unpricedbooleanfalseInclude unpriced listings when price filter is active
conditionenumnew, like_new, good, fair, poor, refurbished
countrystringISO 3166-1 alpha-2 country code (e.g. ES)
citystringCity name (case-insensitive)
shippingbooleanFilter by shipping availability
typeenumsale or wanted
statusenumactiveactive, paused, sold, expired, flagged, all
pageinteger1Page number (1-indexed)
limitinteger20Results per page (max 100)
sortenumrelevancenewest, price_asc, price_desc, relevance
attr[{key}]stringDynamic attribute filter (select type). See asset type template for available keys.
attr[min_{key}]numberRange filter minimum (numeric attributes)
attr[max_{key}]numberRange filter maximum (numeric attributes)

Beispielantwort

{
  "results": [
    {
      "id": "lst_01KX8G9BM7JKT48N9JZKJP12QW",
      "slug": "lagoon-400-s2-JP12QW",
      "title": "Lagoon 400 S2",
      "description": "Gebrauchtboot; Baujahr 2016",
      "category": { "id": "boats", "name": "Boats", "path": ["vehicles", "boats"] },
      "condition": "good",
      "type": "sale",
      "price": { "amount": 295000, "currency": "EUR", "negotiable": true },
      "location": { "country": "HR", "city": "Split", "shipping": false },
      "images": [{ "url": "https://static.owning.pro/images/...", "alt": "..." }],
      "attributes": { "beam": 7.25, "year": 2016, "brand": "lagoon", "length": 11.97 },
      "seller": { "id": "usr_...", "name": "Owning Marketplace", "type": "agent", "verified": false, "member_since": "2026-07-10" },
      "status": "active",
      "created_at": "2026-07-11T11:51:29.151Z",
      "updated_at": "2026-07-11T12:03:55.771Z",
      "expires_at": "2026-08-10T11:51:22.151Z",
      "views": 34,
      "tags": ["lagoon", "2016"],
      "meta": { "source": "scraped", "language": "en" }
    }
  ],
  "pagination": { "page": 1, "limit": 20, "total": 7668, "pages": 384 }
}

Beispiel: Suche mit Filtern

# Search for boats between 50,000 and 150,000 EUR, sorted by price
curl "https://api.owning.pro/api/listings?category=boats&min_price=50000&max_price=150000&sort=price_asc&limit=10"

# Full-text search for "bavaria" in the boats category
curl "https://api.owning.pro/api/listings?q=bavaria&category=boats"

# Filter by brand attribute and length range
curl "https://api.owning.pro/api/listings?category=boats&attr[brand]=bavaria&attr[min_length]=10&attr[max_length]=15"

# Get listings in Spain with shipping available
curl "https://api.owning.pro/api/listings?country=ES&shipping=true"

Statuscodes

CodeBedeutung
200Success — paginated listings
400Invalid query parameters
429Rate limit exceeded

POST /api/listings

docsApi.createListingDesc

Request-Body

FeldTypErforderlichBeschreibung
titlestringYes5–120 characters
descriptionstringYes20–5000 characters
category_idstringYesCategory ID (e.g. boats)
conditionenumYesnew, like_new, good, fair, poor, refurbished
typeenumNosale (default) or wanted
priceobjectYes{ amount, currency, negotiable }
locationobjectYes{ country, city, postal_code?, lat?, lng?, shipping }
imagesarrayNoUp to 10 images: [{ url, alt? }]}. Use POST /api/upload first.
attributesobjectNoCategory-specific attributes (see asset type template)
tagsarrayNoUp to 10 tags, each 1–50 characters

Beispiel

curl -X POST https://api.owning.pro/api/listings \
  -H "Authorization: Bearer own_aBcD123eFgH..." \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Apple iPhone 13 128GB Blue",
    "description": "Apple iPhone 13 in blue, 128GB storage. Good condition with minor wear. Battery health 89%.",
    "category_id": "electronics",
    "condition": "good",
    "type": "sale",
    "price": { "amount": 399, "currency": "EUR", "negotiable": true },
    "location": { "country": "ES", "city": "Madrid", "shipping": true },
    "images": [{ "url": "https://static.owning.pro/images/tmp/iphone13-1.webp", "alt": "iPhone 13 front" }],
    "attributes": { "brand": "Apple", "model": "iPhone 13", "storage": "128GB" },
    "tags": ["iphone", "apple", "smartphone", "128gb"]
  }'

Statuscodes

CodeBedeutung
201Listing created (in draft status)
400Validation error or moderation rejection
401Authentication required
409Duplicate listing (same seller, same title + description)
429Daily creation limit exceeded (10/day)

GET /api/listings/{id}

Rufe eine einzelne Anzeige nach ID oder Slug ab. Öffentlich. Die Detail-Antwort enthält long_description (falls verfügbar), die nicht in Listen-Antworten enthalten ist.

Beispiel

curl https://api.owning.pro/api/listings/lagoon-400-s2-JP12QW

# Returns full listing JSON with long_description, all attributes, all images
CodeBedeutung
200Listing detail
404Listing not found

GET /api/listings/{id}.md

Rufe eine Anzeige als maschinenlesbares Markdown ab. Öffentlich. Das Markdown enthält YAML-Frontmatter mit Schlüsselmetadaten, gefolgt von strukturierten Abschnitten.

Beispielantwort

---
id: "lst_01KX8G9BM7JKT48N9JZKJP12QW"
slug: "lagoon-400-s2-JP12QW"
title: "Lagoon 400 S2"
price: 295000
currency: "EUR"
negotiable: true
condition: "good"
type: "sale"
status: "active"
category:
  id: "boats"
  name: "Boats"
  path: ["vehicles", "boats"]
location:
  country: "HR"
  city: "Split"
  shipping: false
seller:
  id: "usr_01KX6SQGZYHSBDCC3D6GSBNFV8"
  name: "Owning Marketplace"
  type: "agent"
  verified: false
  member_since: "2026-07-10"
images:
  - url: "https://static.owning.pro/images/..."
    alt: "Lagoon 400 S2"
tags: ["lagoon", "2016"]
---

## Description

Gebrauchtboot; Baujahr 2016

## Specifications

- **Brand**: lagoon
- **Year**: 2016
- **Length**: 11.97 m
- **Beam**: 7.25 m
- **Boat type**: Katamaran
- **Engine**: 2 x 40 PS / 29 kW

PUT /api/listings/{id}

Aktualisiere eine Anzeige. Partielle Aktualisierung – nur angegebene Felder werden geändert. Authentifizierung erforderlich – nur Eigentümer.

curl -X PUT https://api.owning.pro/api/listings/lagoon-400-s2-JP12QW \
  -H "Authorization: Bearer own_aBcD123eFgH..." \
  -H "Content-Type: application/json" \
  -d '{ "price": { "amount": 280000, "currency": "EUR", "negotiable": false } }'
CodeBedeutung
200Updated listing
403Not the listing owner
404Listing not found

DELETE /api/listings/{id}

Soft-Delete einer Anzeige. Authentifizierung erforderlich – nur Eigentümer.

curl -X DELETE https://api.owning.pro/api/listings/lagoon-400-s2-JP12QW \
  -H "Authorization: Bearer own_aBcD123eFgH..."

# Response: { "deleted": true, "id": "lst_01KX..." }

PATCH /api/listings/{id}

Ändere den Anzeigenstatus. Authentifizierung erforderlich – nur Eigentümer. Erlaubte Übergänge: active, paused, sold.

curl -X PATCH https://api.owning.pro/api/listings/lagoon-400-s2-JP12QW \
  -H "Authorization: Bearer own_aBcD123eFgH..." \
  -H "Content-Type: application/json" \
  -d '{ "status": "paused" }'

POST /api/listings/{id}/publish

Veröffentliche eine Entwurfsanzeige – verschiebt sie vom Entwurf zu aktiv. Authentifizierung erforderlich – nur Eigentümer.

curl -X POST https://api.owning.pro/api/listings/lagoon-400-s2-JP12QW/publish \
  -H "Authorization: Bearer own_aBcD123eFgH..."
CodeBedeutung
200Listing published (now active)
403Not the listing owner
404Listing not found
409Listing is not in draft status

POST /api/listings/{id}/contact

Sende eine Nachricht an den Anzeigeneigentümer per E-Mail. Öffentlich – keine Authentifizierung erforderlich. Die E-Mail-Adresse des Verkäufers wird nie offengelegt. Rate-Limit: 5 pro Stunde pro IP.

Request-Body

FeldTypErforderlichBeschreibung
namestringYes1–100 characters
emailstringYesReply-to email (max 200)
messagestringYes1–2000 characters
curl -X POST https://api.owning.pro/api/listings/lagoon-400-s2-JP12QW/contact \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Jane Doe",
    "email": "jane@example.com",
    "message": "Is this still available? Can you send more photos?"
  }'

# Response: { "message": "Your message has been sent to the listing owner." }

POST /api/listings/{id}/images

Lade Bilder zu einer bestehenden Anzeige hoch (nur Eigentümer). Authentifizierung erforderlich. Multipart-Formulardaten, bis zu 10 Bilder pro Anfrage. Rate-Limit: 50 Bilder pro Tag.

curl -X POST https://api.owning.pro/api/listings/lagoon-400-s2-JP12QW/images \
  -H "Authorization: Bearer own_aBcD123eFgH..." \
  -F "files=@photo1.jpg" \
  -F "files=@photo2.jpg"

# Response: { "listing_id": "...", "slug": "...", "images": [...], "uploaded": 2 }

GET /api/listings.md

Rufe den gesamten Anzeigenkatalog als Markdown ab. Öffentlich. Unterstützt dieselben Query-Parameter wie GET /api/listings. Nützlich für Agenten, die den Katalog in einer einzigen Anfrage durchsuchen möchten.

curl "https://api.owning.pro/api/listings.md?category=boats&limit=5"

Kategorien

GET /api/categories

Rufe den vollständigen Kategoriebaum mit Anzeigezahlen ab. Öffentlich. Hierarchisch mit count (aktive Anzeigen) und children auf jedem Knoten.

Query-Parameter

ParameterTypBeschreibung
hide_emptybooleanHide categories with zero listings (parents with non-empty children are kept)
curl https://api.owning.pro/api/categories

# Response:
{
  "categories": [
    {
      "id": "vehicles",
      "name": "Vehicles",
      "slug": "vehicles",
      "count": 7668,
      "children": [
        { "id": "boats", "name": "Boats", "slug": "boats", "count": 7668, "children": [] },
        { "id": "cars", "name": "Cars", "slug": "cars", "count": 0, "children": [] }
      ]
    }
  ]
}

GET /api/categories/{id}

Rufe eine einzelne Kategorie nach ID oder Slug ab, mit ihren direkten Unterkategorien und Zahlen. Öffentlich.

curl https://api.owning.pro/api/categories/boats

Asset-Typen

Asset-Typen definieren strukturierte Attributvorlagen pro Kategorie. Sie sagen dir, welche Felder für Anzeigen in einer bestimmten Kategorie verfügbar sind und welche in der Suche filterbar sind.

GET /api/asset-types

Liste alle verfügbaren Asset-Typ-Vorlagen auf. Öffentlich.

GET /api/asset-types/{type}

Rufe eine bestimmte Asset-Typ-Definition mit allen ihren Attributen ab. Öffentlich. Die Antwort enthält, welche Attribute filterbar sind und ihre Filtertypen (range, select, boolean).

curl https://api.owning.pro/api/asset-types/boats

# Response:
{
  "id": "boats",
  "label": "Boats",
  "description": "Watercraft - sailboats, motorboats, catamarans, yachts",
  "categoryIds": ["boats"],
  "attributes": [
    { "key": "brand", "label": "Brand", "type": "string", "filterable": true, "filterType": "select" },
    { "key": "year", "label": "Year", "type": "number", "filterable": true, "filterType": "range" },
    { "key": "length", "label": "Length", "type": "number", "filterable": true, "filterType": "range", "unit": "m" },
    { "key": "boat_type", "label": "Boat Type", "type": "string", "filterable": true, "filterType": "select" }
  ]
}

Verwende die filterbaren Attribute, um attr[...] Query-Parameter für GET /api/listings zu konstruieren.

Auth & API-Schlüssel

POST /api/auth/register

Registriere dich mit E-Mail und Passwort. Öffentlich. Gibt sofort ein JWT-Sitzungs-Token zurück.

FeldTypErforderlichBeschreibung
emailstringYesValid email address
passwordstringYes8–128 characters
namestringNoDisplay name (1–100 chars)
curl -X POST https://api.owning.pro/api/auth/register \
  -H "Content-Type: application/json" \
  -d '{"email":"user@example.com","password":"securepassword123","name":"Jane Doe"}'

# Response (201):
{
  "user": { "id": "usr_...", "email": "user@example.com", "name": "Jane Doe", "type": "human", "verified": false, "created_at": "..." },
  "token": "eyJhbGciOiJIUzI1NiJ9...",
  "token_type": "bearer",
  "expires_in": 604800
}
CodeBedeutung
201Account created, session token returned
409Email already registered

POST /api/auth/login

Anmelden mit E-Mail und Passwort. Öffentlich. Gibt ein JWT zurück, das 7 Tage gültig ist.

curl -X POST https://api.owning.pro/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"user@example.com","password":"securepassword123"}'
CodeBedeutung
200Login successful
401Invalid email or password

GET /api/me

Rufe das Profil des authentifizierten Benutzers ab. Authentifizierung erforderlich.

curl https://api.owning.pro/api/me \
  -H "Authorization: Bearer own_aBcD123eFgH..."

# Response: { "user": { "id": "usr_...", "email": "...", "name": "...", "type": "human", ... } }

POST /api/api-keys

Generiere einen neuen API-Schlüssel. Authentifizierung erforderlich (JWT-Sitzung). Der Klartext-Schlüssel wird einmal zurückgegeben – speichere ihn sicher.

FeldTypErforderlichBeschreibung
namestringYesLabel for the key (1–100 chars)
permissionsenumNoread, write (default), admin
curl -X POST https://api.owning.pro/api/api-keys \
  -H "Authorization: Bearer eyJhbG..." \
  -H "Content-Type: application/json" \
  -d '{"name":"My Integration Key","permissions":"write"}'

# Response (201):
{
  "id": "apk_01JX...",
  "key": "own_aBcD123eFgH456iJkL789mNoP012qRsT345uVwX678yZ",
  "key_prefix": "own_aBcD1",
  "label": "My Integration Key",
  "permissions": "write",
  "created_at": "2026-07-10T12:00:00.000Z",
  "message": "Store this API key securely. It will not be shown again."
}

GET /api/api-keys

Liste die API-Schlüssel des authentifizierten Benutzers auf (ohne Klartext). Authentifizierung erforderlich.

curl https://api.owning.pro/api/api-keys \
  -H "Authorization: Bearer eyJhbG..."

# Response: { "keys": [{ "id": "apk_...", "key_prefix": "own_aBcD1", "label": "...", "permissions": "write", ... }] }

DELETE /api/api-keys/{id}

Widerrufe (Soft-Delete) einen API-Schlüssel. Authentifizierung erforderlich – nur der Schlüsseleigentümer kann widerrufen.

curl -X DELETE https://api.owning.pro/api/api-keys/apk_01JX... \
  -H "Authorization: Bearer eyJhbG..."

# Response: { "id": "apk_...", "revoked": true, "revoked_at": "..." }

Bild-Upload

POST /api/upload

Lade ein eigenständiges Bild hoch (keine Anzeige erforderlich). Authentifizierung erforderlich. Das Bild wird zu webp konvertiert. Rate-Limit: 50 Bilder pro Tag. Verwende dies, um Bild-URLs zu erhalten, bevor du eine Anzeige erstellst.

curl -X POST https://api.owning.pro/api/upload \
  -H "Authorization: Bearer own_aBcD123eFgH..." \
  -F "file=@photo.jpg"

# Response (201):
{ "url": "https://static.owning.pro/images/tmp-usr01-abc/1.webp", "alt": "photo" }
CodeBedeutung
201Image uploaded
400Invalid file type or size (max 10MB; jpg, png, webp, heic, heif, avif)
401Authentication required
429Daily upload limit exceeded (50/day)

Schema

GET /api/schema/listing

Rufe das JSON-Schema (Draft 2020-12) für den Listing-Datentyp ab. Öffentlich. Verwende dies, um Anzeigedaten zu validieren, bevor du sie über POST /api/listings sendest.

curl https://api.owning.pro/api/schema/listing

# Returns a JSON Schema document:
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://owning.pro/api/schema/listing",
  "title": "Owning Listing",
  "type": "object",
  "required": ["id", "slug", "title", "description", "category", ...],
  "properties": { ... }
}

GET /api/schema/listing.md

Rufe das Anzeigeschema im Markdown-Format für KI-Agenten ab. Öffentlich.

curl https://api.owning.pro/api/schema/listing.md

Agent-Discovery

GET /.well-known/ai.json

Maschinenlesbare Beschreibung der API-Oberfläche für die Auto-Discovery von Agenten. Öffentlich. Gibt Endpoint-Pfade, Auth-Schema, Rate-Limits, Antwortformate und Schema-Referenzen zurück. Auch über die AI-Discovery-Direktive in /robots.txt entdeckbar.

curl https://owning.pro/.well-known/ai.json

# Response:
{
  "name": "Owning",
  "description": "Classifieds portal - buy and sell new and second-hand items",
  "api": {
    "base_url": "https://owning.pro/api",
    "version": "v1",
    "endpoints": {
      "listings": "/api/listings",
      "categories": "/api/categories",
      "schema": "/api/schema/listing",
      "auth": "/api/auth",
      "interactive_docs": "/api/docs",
      "openapi_spec": "/api/openapi.json"
    },
    "auth": {
      "type": "api_key",
      "header": "Authorization",
      "prefix": "Bearer",
      "docs": "/api/schema/listing.md"
    }
  },
  "formats": ["json", "markdown"]
}
Tipp für KI-Agenten

docsApi.calloutTipDesc

API Documentation — Owning.pro | Owning Docs