Skip to content

Référence de l'API

L'API d'Owning.pro est une API RESTful pour rechercher, parcourir, créer et gérer des annonces classées. Tous les endpoints renvoient du JSON ; les endpoints d'annonces prennent également en charge les réponses Markdown. L'API est disponible à https://api.owning.pro et proxyée à https://owning.pro/api.

Documentation interactive

Un explorateur d'API interactif (propulsé par Scalar) est disponible à https://api.owning.pro/api/docs. La spécification OpenAPI 3.1 brute se trouve à /api/openapi.json.

Résumé des endpoints

MéthodeEndpointDescriptionAuthentification
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

* = authentification requise (JWT ou clé API)

Authentification

Les endpoints de lecture publics (GET) ne nécessitent pas d'authentification. Les opérations d'écriture (POST, PUT, DELETE, PATCH) nécessitent une authentification.

docsApi.authDesc2

  • Tokens de session JWT — obtenus via POST /api/auth/register ou POST /api/auth/login. Valides pendant 7 jours.
  • Clés API — clés de longue durée au format own_..., créées via POST /api/api-keys. Prennent en charge les permissions read, write et admin.

L'API détecte automatiquement le type de token : les tokens commençant par own_ sont traités comme des clés API ; tous les autres sont traités comme des sessions JWT.

Créer une clé API

# 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..."

Limites de débit

État d'authentificationLimitePortée
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

Les réponses limitées en débit renvoient 429 Too Many Requests avec un error.code de rate_limited.

Formats de réponse

Les endpoints d'annonces prennent en charge deux formats de réponse :

  • JSON (par défaut) — application/json. Renvoie des objets d'annonce structurés.
  • Markdown — text/markdown. Renvoie un document Markdown lisible par machine avec un frontmatter YAML. Demandez-le en ajoutant .md à l'URL ou en envoyant Accept: text/markdown.
# 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"

Format d'erreur

Toutes les erreurs renvoient une structure JSON cohérente :

{
  "error": {
    "code": "not_found",
    "message": "Listing not found",
    "details": { "id": "lst_abc123" }
  }
}
Statut HTTPCode d'erreurSignification
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

Annonces

GET /api/listings

Rechercher et filtrer des annonces avec pagination, tri et filtres d'attributs dynamiques. Public — aucune authentification requise.

Paramètres de requête

ParamètreTypeDéfautDescription
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)

Exemple de réponse

{
  "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 }
}

Exemple : Recherche avec filtres

# 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"

Codes de statut

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

POST /api/listings

docsApi.createListingDesc

Corps de la requête

ChampTypeRequisDescription
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

Exemple

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"]
  }'

Codes de statut

CodeSignification
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}

Obtenir une annonce unique par ID ou slug. Public. La réponse détaillée inclut long_description (si disponible), qui n'est pas présente dans les réponses de liste.

Exemple

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

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

GET /api/listings/{id}.md

Obtenir une annonce au format Markdown lisible par machine. Public. Le Markdown inclut un frontmatter YAML avec les métadonnées clés, suivi de sections structurées.

Exemple de réponse

---
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}

Mettre à jour une annonce. Mise à jour partielle — seuls les champs fournis sont modifiés. Authentification requise — propriétaire uniquement.

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 } }'
CodeSignification
200Updated listing
403Not the listing owner
404Listing not found

DELETE /api/listings/{id}

Suppression douce d'une annonce. Authentification requise — propriétaire uniquement.

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}

Changer le statut d'une annonce. Authentification requise — propriétaire uniquement. Transitions autorisées : 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

Publier une annonce brouillon — la fait passer de brouillon à actif. Authentification requise — propriétaire uniquement.

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

POST /api/listings/{id}/contact

Envoyer un message au propriétaire de l'annonce par email. Public — aucune authentification requise. L'email du vendeur n'est jamais exposé. Limite de débit : 5 par heure et par IP.

Corps de la requête

ChampTypeRequisDescription
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

Téléverser des images vers une annonce existante (propriétaire uniquement). Authentification requise. Données de formulaire multipart, jusqu'à 10 images par requête. Limite de débit : 50 images par jour.

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

Obtenir le catalogue complet des annonces en Markdown. Public. Prend en charge les mêmes paramètres de requête que GET /api/listings. Utile pour les agents qui souhaitent parcourir le catalogue en une seule requête.

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

Catégories

GET /api/categories

Obtenir l'arbre complet des catégories avec le nombre d'annonces. Public. Hiérarchique avec count (annonces actives) et children sur chaque nœud.

Paramètres de requête

ParamètreTypeDescription
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}

Obtenir une catégorie unique par ID ou slug, avec ses enfants directs et les compteurs. Public.

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

Types d'actifs

Les types d'actifs définissent des modèles d'attributs structurés par catégorie. Ils indiquent quels champs sont disponibles pour les annonces dans une catégorie donnée, et lesquels sont filtrables dans la recherche.

GET /api/asset-types

Lister tous les modèles de types d'actifs disponibles. Public.

GET /api/asset-types/{type}

Obtenir la définition d'un type d'actif spécifique avec tous ses attributs. Public. La réponse indique quels attributs sont filtrables et leurs types de filtre (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" }
  ]
}

Utilisez les attributs filtrables pour construire les paramètres de requête attr[...] pour GET /api/listings.

Authentification et clés API

POST /api/auth/register

S'inscrire avec un email et un mot de passe. Public. Renvoie immédiatement un token de session JWT.

ChampTypeRequisDescription
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
}
CodeSignification
201Account created, session token returned
409Email already registered

POST /api/auth/login

Se connecter avec un email et un mot de passe. Public. Renvoie un JWT valide pendant 7 jours.

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

GET /api/me

Obtenir le profil de l'utilisateur authentifié. Authentification requise.

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

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

POST /api/api-keys

Générer une nouvelle clé API. Authentification requise (session JWT). La clé en texte clair n'est renvoyée qu'une seule fois — stockez-la en toute sécurité.

ChampTypeRequisDescription
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

Lister les clés API de l'utilisateur authentifié (sans texte clair). Authentification requise.

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}

Révoquer (suppression douce) une clé API. Authentification requise — seul le propriétaire de la clé peut la révoquer.

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

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

Téléversement d'images

POST /api/upload

Téléverser une image autonome (aucune annonce requise). Authentification requise. L'image est convertie en webp. Limite de débit : 50 images par jour. Utilisez ceci pour obtenir des URL d'images avant de créer une annonce.

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" }
CodeSignification
201Image uploaded
400Invalid file type or size (max 10MB; jpg, png, webp, heic, heif, avif)
401Authentication required
429Daily upload limit exceeded (50/day)

Schéma

GET /api/schema/listing

Obtenir le schéma JSON (draft 2020-12) pour le type de données Listing. Public. Utilisez-le pour valider les données de l'annonce avant de les soumettre via POST /api/listings.

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

Obtenir le schéma des annonces au format Markdown pour les agents IA. Public.

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

Découverte pour agents

GET /.well-known/ai.json

Description lisible par machine de la surface de l'API pour l'auto-découverte par les agents. Public. Renvoie les chemins des endpoints, le schéma d'authentification, les limites de débit, les formats de réponse et les références de schéma. Également découvrable via la directive AI-Discovery dans /robots.txt.

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"]
}
Astuce pour les agents IA

docsApi.calloutTipDesc

API Documentation — Owning.pro | Owning Docs