Esempi di integrazione
Tre esempi end-to-end che coprono i pattern di integrazione più comuni con Owning.pro. Ogni esempio include implementazioni curl, TypeScript e Python.
| # | Esempio | Auth | Strumenti / Endpoint |
|---|---|---|---|
| 1 | Search & Evaluate | None (public) | GET /api/listings, GET /api/listings/:id.md |
| 2 | Publish a Listing | API key (write) | POST /api/api-keys, POST /api/upload, POST /api/listings, POST /api/listings/:id/publish |
| 3 | Use MCP Server | API key (optional) | search_listings, get_listing_markdown, create_listing, publish_listing |
| 4 | Track Analytics Events | None (public) | POST /api/track |
| 5 | Promote a Listing (Premium) | JWT (owner) | POST /api/listings/:id/premium, GET /api/listings/:id/premium-status *(planned)* |
Esempio 1: Cerca e valuta
Scenario: Un agente IA cerca barche in una categoria specifica, filtra per prezzo, recupera il dettaglio Markdown del risultato principale e valuta se è un buon affare.
Questo esempio usa solo endpoint di lettura pubblici. Nessuna API key o JWT necessaria. Rate limit: 100 richieste/minuto per IP.
Flusso
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 evaluatecurl
# 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 sectionsTypeScript
// 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()Esempio 2: Pubblica un annuncio
Scenario: Un agente registra un account, accede, crea una API key con permessi di scrittura, carica un'immagine, crea un annuncio e lo pubblica. Questo è il flusso di scrittura completo end-to-end.
Questo esempio richiede un token JWT (da register/login) per creare una API key, e poi l'API key per le successive operazioni di scrittura. Rate limit: 10 annunci/giorno, 50 caricamenti immagini/giorno.
Flusso
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()Esempio 3: Usa il server MCP
Scenario: Un agente si connette al server MCP di Owning, elenca gli strumenti disponibili, cerca annunci, ne recupera uno in formato Markdown, crea un nuovo annuncio e lo pubblica — tutto tramite chiamate MCP invece di richieste HTTP raw.
Questo esempio raggiunge gli stessi obiettivi degli Esempi 1 e 2, ma tramite l'interfaccia strumenti del server MCP. Il server MCP gestisce internamente header di auth, costruzione degli URL e parsing delle risposte.
Flusso
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()Esempio 4: Traccia eventi analytics
Scenario: Un'applicazione frontend invia eventi analytics a Owning per tracciare visualizzazioni di pagina, ricerche, registrazioni e visualizzazioni di annunci. Questo endpoint è pubblico e fire-and-forget — restituisce sempre 202 Accepted.
Gli IP dei client sono hashati (SHA-256 + salt) prima della memorizzazione. Gli IP raw non vengono mai persistiti.
Tipi di evento validi
page_view— includepath,referrersignup— includeuser_idlisting_created— includeuser_id,listing_idsearch— includequery,results_countlisting_view— includelisting_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)Esempio 5: Promuovi un annuncio (Premium)
Scenario: Un venditore promuove il proprio annuncio con una promozione premium featured via checkout Stripe, poi verifica lo stato premium.
Lo schema DB per annunci premium (premium_type, premium_until) è attivo. Gli endpoint checkout e webhook Stripe sono in fase di scaffolding. Gli esempi mostrano la superficie API pianificata.
Tipi premium
featured— top of search results and category pagesurgent— urgent badge and priority placement
curl (pianificato)
# 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 (pianificato)
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 (pianificato)
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()Suggerimenti e best practice
Scegliere tra REST API e MCP Server
| Usa la REST API quando… | Usa il MCP Server quando… |
|---|---|
| Hai bisogno di controllo granulare su HTTP (header personalizzati, streaming, caching) | Stai costruendo un agente IA che usa un LLM per decidere le azioni |
| Stai integrando in un codebase esistente basato su HTTP | Vuoi descrizioni degli strumenti e parametri tipizzati per l'LLM |
| Hai bisogno di endpoint non coperti dagli strumenti MCP (es. auth, schema) | Vuoi codice più semplice senza boilerplate HTTP |
| Stai consumando direttamente i feed Markdown/JSON | Stai usando un client che supporta MCP nativamente (Claude Desktop, Cursor, ecc.) |
Gestione rate limit
- Memorizza in cache i risultati di ricerca — se cerchi ripetutamente, salva i risultati localmente per evitare di raggiungere i rate limit.
- Usa API key per limiti più alti — le richieste autenticate ottengono 300 req/min contro 100 req/min non autenticate.
- Carica immagini in batch — hai 50 caricamenti/giorno. Carica tutte le immagini di un annuncio prima di crearlo.
- Gestisci le risposte 429 — controlla l'header Retry-After e fai backoff di conseguenza.
Sicurezza
- Non hardcodare mai le API key — usa variabili d'ambiente o un secrets manager.
- Usa permessi minimi — se devi solo leggere, crea una chiave di sola lettura.
- Ruota le chiavi regolarmente — elimina le chiavi vecchie e creane di nuove periodicamente.
- Usa solo HTTPS — tutti gli endpoint Owning sono HTTPS. Non usare mai HTTP.
Documentazione completa endpoint: Riferimento API
Dettagli strumenti MCP: Guida rapida MCP Server