Skip to content

Exemples d'intégration

Trois exemples de bout en bout qui couvrent les modèles d'intégration les plus courants avec Owning.pro. Chaque exemple inclut des implémentations en curl, TypeScript et Python.

#ExempleAuthentificationOutils / Endpoints
1Search & EvaluateNone (public)GET /api/listings, GET /api/listings/:id.md
2Publish a ListingAPI key (write)POST /api/api-keys, POST /api/upload, POST /api/listings, POST /api/listings/:id/publish
3Use MCP ServerAPI key (optional)search_listings, get_listing_markdown, create_listing, publish_listing
4Track Analytics EventsNone (public)POST /api/track
5Promote a Listing (Premium)JWT (owner)POST /api/listings/:id/premium, GET /api/listings/:id/premium-status *(planned)*

Exemple 1 : Rechercher et évaluer

Scénario : Un agent IA recherche des bateaux dans une catégorie spécifique, filtre par prix, récupère le détail Markdown du meilleur résultat et évalue s'il s'agit d'une bonne affaire.

Aucune authentification requise

Cet exemple utilise uniquement des endpoints de lecture publics. Aucune clé API ou JWT n'est nécessaire. Limite de débit : 100 requêtes/minute par IP.

Flux

1. Search listings (category=boats, max_price=200000)
   → GET /api/listings?category=boats&max_price=200000&limit=10
2. Pick the first result
3. Get the Markdown detail
   → GET /api/listings/{slug}.md
4. Parse and evaluate

curl

# Step 1: Search for boats under 200k
curl -s "https://api.owning.pro/api/listings?category=boats&max_price=200000&limit=10" \
  | jq '.results[0].slug'

# → "lagoon-400-s2-JP12QW"

# Step 2: Get the Markdown detail
curl -s "https://api.owning.pro/api/listings/lagoon-400-s2-JP12QW.md"

# → Returns Markdown with YAML frontmatter + structured sections

TypeScript

// search-and-evaluate.ts
const API_BASE = "https://api.owning.pro";

async function searchAndEvaluate() {
  // Step 1: Search for boats under 200k
  const searchUrl = new URL(`${API_BASE}/api/listings`);
  searchUrl.searchParams.set("category", "boats");
  searchUrl.searchParams.set("max_price", "200000");
  searchUrl.searchParams.set("limit", "10");

  const searchRes = await fetch(searchUrl);
  const searchData = await searchRes.json();

  console.log(`Found ${searchData.pagination.total} listings`);

  if (searchData.results.length === 0) {
    console.log("No results found");
    return;
  }

  // Step 2: Pick the first result
  const topListing = searchData.results[0];
  console.log(`Top result: ${topListing.title} — ${topListing.price.amount} ${topListing.price.currency}`);

  // Step 3: Get the Markdown detail
  const mdRes = await fetch(`${API_BASE}/api/listings/${topListing.slug}.md`);
  const markdown = await mdRes.text();

  // Step 4: Evaluate
  console.log("\n--- Listing Detail (Markdown) ---\n");
  console.log(markdown);

  // Parse key info from the Markdown for evaluation
  const priceMatch = markdown.match(/price:\s*(\d+)/);
  const yearMatch = markdown.match(/Year.*?(\d{4})/);
  const lengthMatch = markdown.match(/Length.*?([\d.]+)\s*m/);

  const evaluation = {
    title: topListing.title,
    price: priceMatch ? parseInt(priceMatch[1]) : null,
    year: yearMatch ? parseInt(yearMatch[1]) : null,
    length: lengthMatch ? parseFloat(lengthMatch[1]) : null,
    pricePerMeter: null as number | null,
  };

  if (evaluation.price && evaluation.length) {
    evaluation.pricePerMeter = Math.round(evaluation.price / evaluation.length);
  }

  console.log("\n--- Evaluation ---");
  console.log(JSON.stringify(evaluation, null, 2));
}

searchAndEvaluate().catch(console.error);

Python

# search_and_evaluate.py
import requests
import re
import json

API_BASE = "https://api.owning.pro"

def search_and_evaluate():
    # Step 1: Search for boats under 200k
    params = {
        "category": "boats",
        "max_price": "200000",
        "limit": "10",
    }
    resp = requests.get(f"{API_BASE}/api/listings", params=params)
    data = resp.json()

    print(f"Found {data['pagination']['total']} listings")

    if not data["results"]:
        print("No results found")
        return

    # Step 2: Pick the first result
    top = data["results"][0]
    print(f"Top result: {top['title']} — {top['price']['amount']} {top['price']['currency']}")

    # Step 3: Get the Markdown detail
    md_resp = requests.get(f"{API_BASE}/api/listings/{top['slug']}.md")
    markdown = md_resp.text

    # Step 4: Evaluate
    print("\n--- Listing Detail (Markdown) ---\n")
    print(markdown)

    # Parse key info
    price_match = re.search(r"price:\s*(\d+)", markdown)
    year_match = re.search(r"Year.*?(\d{4})", markdown)
    length_match = re.search(r"Length.*?([\d.]+)\s*m", markdown)

    evaluation = {
        "title": top["title"],
        "price": int(price_match.group(1)) if price_match else None,
        "year": int(year_match.group(1)) if year_match else None,
        "length": float(length_match.group(1)) if length_match else None,
        "price_per_meter": None,
    }

    if evaluation["price"] and evaluation["length"]:
        evaluation["price_per_meter"] = round(evaluation["price"] / evaluation["length"])

    print("\n--- Evaluation ---")
    print(json.dumps(evaluation, indent=2))

if __name__ == "__main__":
    search_and_evaluate()

Exemple 2 : Publier une annonce

Scénario : Un agent crée un compte, se connecte, crée une clé API avec des permissions d'écriture, téléverse une image, crée une annonce et la publie. Il s'agit du flux d'écriture complet de bout en bout.

Authentification requise

Cet exemple nécessite un token JWT (issu de l'inscription/connexion) pour créer une clé API, puis la clé API pour les opérations d'écriture suivantes. Limites de débit : 10 annonces/jour, 50 téléversements d'images/jour.

Flux

1. Register an account     → POST /api/auth/register
2. Login (get JWT)         → POST /api/auth/login
3. Create an API key       → POST /api/api-keys (JWT auth)
4. Upload an image         → POST /api/upload (API key auth)
5. Create a listing        → POST /api/listings (API key auth)
6. Publish the listing     → POST /api/listings/:id/publish (API key auth)

curl

# Step 1: Register
curl -s -X POST https://api.owning.pro/api/auth/register \
  -H "Content-Type: application/json" \
  -d '{"email":"agent@example.com","password":"SecurePass123!","name":"AI Agent"}'

# Step 2: Login (get JWT)
JWT=$(curl -s -X POST https://api.owning.pro/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"agent@example.com","password":"SecurePass123!"}' \
  | jq -r '.token')

# Step 3: Create an API key with write permission
API_KEY=$(curl -s -X POST https://api.owning.pro/api/api-keys \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $JWT" \
  -d '{"name":"agent-key","permissions":["read","write"]}' \
  | jq -r '.key')

echo "API Key: $API_KEY"

# Step 4: Upload an image
IMAGE_URL=$(curl -s -X POST https://api.owning.pro/api/upload \
  -H "Authorization: Bearer $API_KEY" \
  -F "file=@photo.jpg" \
  | jq -r '.url')

# Step 5: Create a listing
LISTING_ID=$(curl -s -X POST https://api.owning.pro/api/listings \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $API_KEY" \
  -d "{
    \"title\": \"Apple iPhone 13 128GB Blue\",
    \"description\": \"Apple iPhone 13 in blue, 128GB. Good condition, battery health 89%.\",
    \"category_id\": \"electronics\",
    \"condition\": \"good\",
    \"price\": { \"amount\": 399, \"currency\": \"EUR\", \"negotiable\": true },
    \"location\": { \"country\": \"ES\", \"city\": \"Madrid\", \"shipping\": true },
    \"images\": [{ \"url\": \"$IMAGE_URL\" }],
    \"tags\": [\"iphone\", \"apple\", \"smartphone\"]
  }" \
  | jq -r '.id')

echo "Listing ID: $LISTING_ID"

# Step 6: Publish the listing
curl -s -X POST "https://api.owning.pro/api/listings/$LISTING_ID/publish" \
  -H "Authorization: Bearer $API_KEY"

# → { "id": "...", "status": "active", ... }

TypeScript

// publish-listing.ts
const API_BASE = "https://api.owning.pro";

async function publishListing() {
  // Step 1: Register
  const regRes = await fetch(`${API_BASE}/api/auth/register`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      email: "agent@example.com",
      password: "SecurePass123!",
      name: "AI Agent",
    }),
  });
  // Ignore 409 (already registered) — proceed to login

  // Step 2: Login
  const loginRes = await fetch(`${API_BASE}/api/auth/login`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      email: "agent@example.com",
      password: "SecurePass123!",
    }),
  });
  const { token: jwt } = await loginRes.json();

  // Step 3: Create an API key
  const keyRes = await fetch(`${API_BASE}/api/api-keys`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${jwt}`,
    },
    body: JSON.stringify({
      name: "agent-key",
      permissions: ["read", "write"],
    }),
  });
  const { key: apiKey } = await keyRes.json();
  console.log("API Key:", apiKey);

  // Step 4: Upload an image
  const formData = new FormData();
  const imageBuffer = await fetch("https://example.com/photo.jpg").then((r) => r.blob());
  formData.append("file", imageBuffer, "photo.jpg");

  const uploadRes = await fetch(`${API_BASE}/api/upload`, {
    method: "POST",
    headers: { Authorization: `Bearer ${apiKey}` },
    body: formData,
  });
  const { url: imageUrl } = await uploadRes.json();
  console.log("Image URL:", imageUrl);

  // Step 5: Create a listing
  const createRes = await fetch(`${API_BASE}/api/listings`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${apiKey}`,
    },
    body: JSON.stringify({
      title: "Apple iPhone 13 128GB Blue",
      description: "Apple iPhone 13 in blue, 128GB. Good condition, battery health 89%.",
      category_id: "electronics",
      condition: "good",
      price: { amount: 399, currency: "EUR", negotiable: true },
      location: { country: "ES", city: "Madrid", shipping: true },
      images: [{ url: imageUrl }],
      tags: ["iphone", "apple", "smartphone"],
    }),
  });
  const listing = await createRes.json();
  console.log("Listing ID:", listing.id);

  // Step 6: Publish
  const pubRes = await fetch(`${API_BASE}/api/listings/${listing.id}/publish`, {
    method: "POST",
    headers: { Authorization: `Bearer ${apiKey}` },
  });
  const published = await pubRes.json();
  console.log("Published:", published.status); // → "active"
}

publishListing().catch(console.error);

Python

# publish_listing.py
import requests

API_BASE = "https://api.owning.pro"

def publish_listing():
    # Step 1: Register
    requests.post(f"{API_BASE}/api/auth/register", json={
        "email": "agent@example.com",
        "password": "SecurePass123!",
        "name": "AI Agent",
    })
    # Ignore 409 (already registered)

    # Step 2: Login
    login_resp = requests.post(f"{API_BASE}/api/auth/login", json={
        "email": "agent@example.com",
        "password": "SecurePass123!",
    })
    jwt = login_resp.json()["token"]

    # Step 3: Create an API key
    key_resp = requests.post(f"{API_BASE}/api/api-keys", json={
        "name": "agent-key",
        "permissions": ["read", "write"],
    }, headers={"Authorization": f"Bearer {jwt}"})
    api_key = key_resp.json()["key"]
    print(f"API Key: {api_key}")

    auth_headers = {"Authorization": f"Bearer {api_key}"}

    # Step 4: Upload an image
    with open("photo.jpg", "rb") as f:
        upload_resp = requests.post(
            f"{API_BASE}/api/upload",
            headers=auth_headers,
            files={"file": ("photo.jpg", f, "image/jpeg")},
        )
    image_url = upload_resp.json()["url"]
    print(f"Image URL: {image_url}")

    # Step 5: Create a listing
    create_resp = requests.post(f"{API_BASE}/api/listings", json={
        "title": "Apple iPhone 13 128GB Blue",
        "description": "Apple iPhone 13 in blue, 128GB. Good condition, battery health 89%.",
        "category_id": "electronics",
        "condition": "good",
        "price": {"amount": 399, "currency": "EUR", "negotiable": True},
        "location": {"country": "ES", "city": "Madrid", "shipping": True},
        "images": [{"url": image_url}],
        "tags": ["iphone", "apple", "smartphone"],
    }, headers={**auth_headers, "Content-Type": "application/json"})
    listing = create_resp.json()
    print(f"Listing ID: {listing['id']}")

    # Step 6: Publish
    pub_resp = requests.post(
        f"{API_BASE}/api/listings/{listing['id']}/publish",
        headers=auth_headers,
    )
    published = pub_resp.json()
    print(f"Published: {published['status']}")  # → "active"

if __name__ == "__main__":
    publish_listing()

Exemple 3 : Utiliser le serveur MCP

Scénario : Un agent se connecte au serveur MCP d'Owning, liste les outils disponibles, recherche des annonces, en récupère une au format Markdown, crée une nouvelle annonce et la publie — le tout via des appels d'outils MCP au lieu de requêtes HTTP brutes.

MCP vs REST

Cet exemple atteint les mêmes objectifs que les exemples 1 et 2, mais via l'interface d'outils du serveur MCP. Le serveur MCP gère les en-têtes d'authentification, la construction des URL et l'analyse des réponses en interne.

Flux

1. Initialize MCP session    → method: "initialize"
2. List available tools      → method: "tools/list"
3. Search listings           → tool: "search_listings"
4. Get Markdown detail       → tool: "get_listing_markdown"
5. Create a listing          → tool: "create_listing"
6. Publish the listing       → tool: "publish_listing"

curl

MCP_URL="https://mcp.owning.pro/mcp"
API_KEY="own_aBcD123eFgH456iJkL789mNoP012qRsT345uVwX678yZ"

# Step 1: Initialize
curl -s -X POST "$MCP_URL" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}'

# Step 2: List tools
curl -s -X POST "$MCP_URL" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}'

# Step 3: Search listings
curl -s -X POST "$MCP_URL" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $API_KEY" \
  -d '{
    "jsonrpc":"2.0","id":3,"method":"tools/call",
    "params":{"name":"search_listings","arguments":{
      "query":"lagoon","category":"boats","limit":5
    }}
  }'

# Step 4: Get Markdown detail
curl -s -X POST "$MCP_URL" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $API_KEY" \
  -d '{
    "jsonrpc":"2.0","id":4,"method":"tools/call",
    "params":{"name":"get_listing_markdown","arguments":{
      "id_or_slug":"lagoon-400-s2-JP12QW"
    }}
  }'

# Step 5: Create a listing
curl -s -X POST "$MCP_URL" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $API_KEY" \
  -d '{
    "jsonrpc":"2.0","id":5,"method":"tools/call",
    "params":{"name":"create_listing","arguments":{
      "title":"Apple iPhone 13 128GB Blue",
      "description":"Apple iPhone 13 in blue, 128GB. Good condition, battery health 89%.",
      "category_id":"electronics",
      "condition":"good",
      "price":{"amount":399,"currency":"EUR","negotiable":true},
      "location":{"country":"ES","city":"Madrid","shipping":true},
      "tags":["iphone","apple","smartphone"]
    }}
  }'

# Step 6: Publish (use the listing ID from step 5)
curl -s -X POST "$MCP_URL" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $API_KEY" \
  -d '{
    "jsonrpc":"2.0","id":6,"method":"tools/call",
    "params":{"name":"publish_listing","arguments":{
      "id_or_slug":"apple-iphone-13-128gb-blue"
    }}
  }'

TypeScript

// use-mcp-server.ts
const MCP_URL = "https://mcp.owning.pro/mcp";
const API_KEY = process.env.OWNING_API_KEY; // own_... format

let nextId = 1;

async function callMCP(method: string, params: Record<string, unknown> = {}) {
  const res = await fetch(MCP_URL, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      ...(API_KEY ? { Authorization: `Bearer ${API_KEY}` } : {}),
    },
    body: JSON.stringify({
      jsonrpc: "2.0",
      id: nextId++,
      method,
      params,
    }),
  });
  const data = await res.json();
  if (data.error) throw new Error(data.error.message);
  return data.result;
}

async function callTool(name: string, args: Record<string, unknown>) {
  const result = await callMCP("tools/call", { name, arguments: args });
  if (result.isError) {
    throw new Error(result.content[0].text);
  }
  // Parse the text content as JSON if possible
  const text = result.content[0].text;
  try {
    return JSON.parse(text);
  } catch {
    return text;
  }
}

async function main() {
  // Step 1: Initialize
  const init = await callMCP("initialize", {});
  console.log(`Connected to ${init.serverInfo.name} v${init.serverInfo.version}`);

  // Step 2: List tools
  const toolsList = await callMCP("tools/list", {});
  console.log(`Available tools: ${toolsList.tools.map((t: any) => t.name).join(", ")}`);

  // Step 3: Search listings
  const searchResult = await callTool("search_listings", {
    query: "lagoon",
    category: "boats",
    limit: 5,
  });
  console.log(`Found ${searchResult.results.length} listings`);
  const topListing = searchResult.results[0];
  console.log(`Top: ${topListing.title}`);

  // Step 4: Get Markdown detail
  const markdown = await callTool("get_listing_markdown", {
    id_or_slug: topListing.slug,
  });
  console.log("\n--- Markdown ---");
  console.log(typeof markdown === "string" ? markdown : JSON.stringify(markdown));

  // Step 5: Create a listing (requires write API key)
  if (!API_KEY) {
    console.log("\nSkipping write operations — no API key set");
    return;
  }
  const newListing = await callTool("create_listing", {
    title: "Apple iPhone 13 128GB Blue",
    description: "Apple iPhone 13 in blue, 128GB. Good condition, battery health 89%.",
    category_id: "electronics",
    condition: "good",
    price: { amount: 399, currency: "EUR", negotiable: true },
    location: { country: "ES", city: "Madrid", shipping: true },
    tags: ["iphone", "apple", "smartphone"],
  });
  console.log(`Created listing: ${newListing.id}`);

  // Step 6: Publish
  const published = await callTool("publish_listing", {
    id_or_slug: newListing.slug,
  });
  console.log(`Published: ${published.status}`);
}

main().catch(console.error);

Python

# use_mcp_server.py
import requests
import json
import os

MCP_URL = "https://mcp.owning.pro/mcp"
API_KEY = os.environ.get("OWNING_API_KEY")  # own_... format
_next_id = 1

def call_mcp(method, params=None):
    global _next_id
    headers = {"Content-Type": "application/json"}
    if API_KEY:
        headers["Authorization"] = f"Bearer {API_KEY}"

    resp = requests.post(MCP_URL, headers=headers, json={
        "jsonrpc": "2.0",
        "id": _next_id,
        "method": method,
        "params": params or {},
    })
    _next_id += 1
    data = resp.json()
    if "error" in data:
        raise Exception(data["error"]["message"])
    return data["result"]

def call_tool(name, args):
    result = call_mcp("tools/call", {"name": name, "arguments": args})
    if result.get("isError"):
        raise Exception(result["content"][0]["text"])
    text = result["content"][0]["text"]
    try:
        return json.loads(text)
    except json.JSONDecodeError:
        return text

def main():
    # Step 1: Initialize
    init = call_mcp("initialize", {})
    info = init["serverInfo"]
    print(f"Connected to {info['name']} v{info['version']}")

    # Step 2: List tools
    tools_list = call_mcp("tools/list", {})
    tool_names = [t["name"] for t in tools_list["tools"]]
    print(f"Available tools: {', '.join(tool_names)}")

    # Step 3: Search listings
    search_result = call_tool("search_listings", {
        "query": "lagoon",
        "category": "boats",
        "limit": 5,
    })
    print(f"Found {len(search_result['results'])} listings")
    top = search_result["results"][0]
    print(f"Top: {top['title']}")

    # Step 4: Get Markdown detail
    markdown = call_tool("get_listing_markdown", {
        "id_or_slug": top["slug"],
    })
    print("\n--- Markdown ---")
    if isinstance(markdown, str):
        print(markdown)
    else:
        print(json.dumps(markdown, indent=2))

    # Step 5: Create a listing (requires write API key)
    if not API_KEY:
        print("\nSkipping write operations — no API key set")
        return

    new_listing = call_tool("create_listing", {
        "title": "Apple iPhone 13 128GB Blue",
        "description": "Apple iPhone 13 in blue, 128GB. Good condition, battery health 89%.",
        "category_id": "electronics",
        "condition": "good",
        "price": {"amount": 399, "currency": "EUR", "negotiable": True},
        "location": {"country": "ES", "city": "Madrid", "shipping": True},
        "tags": ["iphone", "apple", "smartphone"],
    })
    print(f"Created listing: {new_listing['id']}")

    # Step 6: Publish
    published = call_tool("publish_listing", {
        "id_or_slug": new_listing["slug"],
    })
    print(f"Published: {published['status']}")

if __name__ == "__main__":
    main()

Exemple 4 : Suivre les événements analytiques

Scénario : Une application frontend envoie des événements analytiques à Owning pour suivre les pages vues, les recherches, les inscriptions et les vues d'annonces. Cet endpoint est public et de type « fire-and-forget » — il renvoie toujours 202 Accepted.

Confidentialité

Les IP des clients sont hachées (SHA-256 + sel) avant le stockage. Les IP brutes ne sont jamais persistées.

Types d'événements valides

  • page_view — include path, referrer
  • signup — include user_id
  • listing_created — include user_id, listing_id
  • search — include query, results_count
  • listing_view — include listing_id

curl

# Track a page view
curl -s -X POST https://api.owning.pro/api/track   -H "Content-Type: application/json"   -d '{"event":"page_view","path":"/listings/bavaria-s36-coupe","referrer":"https://google.com"}'
# → 202 {"ok":true}

# Track a search
curl -s -X POST https://api.owning.pro/api/track   -H "Content-Type: application/json"   -d '{"event":"search","query":"yacht","results_count":142,"path":"/listings?q=yacht"}'
# → 202 {"ok":true}

TypeScript

// Fire-and-forget analytics tracking
function track(event: string, data: Record<string, unknown> = {}) {
  fetch("https://api.owning.pro/api/track", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ event, ...data }),
  }).catch(() => {}); // silently fail — best-effort
}

track("page_view", { path: window.location.pathname, referrer: document.referrer });
track("search", { query: "yacht", results_count: 142 });

Python

import requests

def track(event: str, **data):
    """Send analytics event (fire-and-forget)."""
    try:
        requests.post("https://api.owning.pro/api/track",
            json={"event": event, **data}, timeout=5)
    except Exception:
        pass  # best-effort

track("page_view", path="/listings", referrer="https://google.com")
track("search", query="yacht", results_count=142)

Exemple 5 : Promouvoir une annonce (Premium)

Scénario : Un vendeur promeut son annonce avec une promotion premium en vedette via le paiement Stripe, puis vérifie le statut premium.

Statut de la fonctionnalité : En développement

Le schéma de base de données pour les annonces premium (premium_type, premium_until) est en ligne. Les endpoints de paiement Stripe et de webhook sont en cours de structuration. Les exemples montrent la surface d'API prévue.

Types de premium

  • featured — top of search results and category pages
  • urgent — urgent badge and priority placement

curl (prévu)

# Step 1: Initiate premium checkout (JWT — listing owner only)
curl -s -X POST https://api.owning.pro/api/listings/lst_01J.../premium   -H "Authorization: Bearer <jwt>"   -H "Content-Type: application/json"   -d '{"premium_type":"featured","duration_days":7}'
# → 200 {"checkout_url":"https://checkout.stripe.com/c/pay/cs_...","session_id":"cs_...","premium_type":"featured","amount":499,"currency":"eur","duration_days":7}

# Step 2: Check premium status (public)
curl -s https://api.owning.pro/api/listings/lst_01J.../premium-status
# → 200 {"listing_id":"lst_01J...","premium_type":"featured","premium_until":"2026-07-18T18:00:00.000Z","is_active":true}

TypeScript (prévu)

async function promoteListing(listingId: string, jwt: string, premiumType: "featured" | "urgent", durationDays = 7) {
  const res = await fetch(`https://api.owning.pro/api/listings/${listingId}/premium`, {
    method: "POST",
    headers: { "Authorization": `Bearer ${jwt}`, "Content-Type": "application/json" },
    body: JSON.stringify({ premium_type: premiumType, duration_days: durationDays }),
  });
  const data = await res.json();
  window.location.href = data.checkout_url; // redirect to Stripe
}

async function getPremiumStatus(listingId: string) {
  const res = await fetch(`https://api.owning.pro/api/listings/${listingId}/premium-status`);
  return res.json();
}

Python (prévu)

import requests

def promote_listing(listing_id: str, jwt: str, premium_type: str, duration_days: int = 7):
    res = requests.post(f"https://api.owning.pro/api/listings/{listing_id}/premium",
        headers={"Authorization": f"Bearer {jwt}", "Content-Type": "application/json"},
        json={"premium_type": premium_type, "duration_days": duration_days})
    return res.json()

def get_premium_status(listing_id: str):
    res = requests.get(f"https://api.owning.pro/api/listings/{listing_id}/premium-status")
    return res.json()

Conseils et bonnes pratiques

Choisir entre l'API REST et le serveur MCP

Utiliser l'API REST quand…Utiliser le serveur MCP quand…
Vous avez besoin d'un contrôle fin sur HTTP (en-têtes personnalisés, streaming, cache)Vous construisez un agent IA qui utilise un LLM pour décider des actions
Vous intégrez dans une base de code existante basée sur HTTPVous voulez des descriptions d'outils et des paramètres typés pour le LLM
Vous avez besoin d'endpoints non couverts par les outils MCP (par ex. auth, schéma)Vous voulez un code plus simple sans code HTTP récurrent
Vous consommez directement les flux Markdown/JSONVous utilisez un client qui prend en charge MCP nativement (Claude Desktop, Cursor, etc.)

Gestion des limites de débit

  • Mettez en cache les résultats de recherche — si vous effectuez des recherches répétées, mettez en cache les résultats localement pour éviter d'atteindre les limites de débit.
  • Utilisez des clés API pour des limites plus élevées — les requêtes authentifiées obtiennent 300 req/min contre 100 req/min non authentifiées.
  • Regroupez les téléversements d'images — vous disposez de 50 téléversements/jour. Téléversez toutes les images d'une annonce avant de la créer.
  • Gérez les réponses 429 — vérifiez l'en-tête Retry-After et reculez en conséquence.

Sécurité

  • Ne codez jamais les clés API en dur — utilisez des variables d'environnement ou un gestionnaire de secrets.
  • Utilisez des permissions minimales — si vous avez uniquement besoin de lire, créez une clé en lecture seule.
  • Faites une rotation régulière des clés — supprimez les anciennes clés et créez-en de nouvelles périodiquement.
  • Utilisez uniquement HTTPS — tous les endpoints d'Owning sont en HTTPS. N'utilisez jamais HTTP.
Besoin de plus de détails ?

Documentation complète des endpoints : Référence de l'API
Détails des outils MCP : Démarrage rapide du serveur MCP

Code Examples — Owning.pro API | Owning Docs