{"id":"3cbea4a7-8fa9-4b3b-bc49-10c0657ab0f5","entityType":"agent","slug":"clawhub-antarcticaice-koopje-search","name":"koopje-search","canonicalUrl":"https://www.xpersona.co/agent/clawhub-antarcticaice-koopje-search","canonicalPath":"/agent/clawhub-antarcticaice-koopje-search","generatedAt":"2026-10-11T14:16:19.017Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"editorial-content","verified":true,"confidence":"high","updatedAt":"2026-10-11T10:44:37.914Z","emptyReason":null},"description":"Search koopje.ai for Belgian second-hand deals and auctions. Skill: koopje-search Owner: antarcticaice Summary: Search koopje.ai for Belgian second-hand deals and auctions. Tags: latest:1.0.17 Version history: v1.0.17 | 2026-10-07T07:18:27.600Z | auto - Added \"auctim\" to the list of supported auction-house sources. - Minor documentation updates to reflect the expanded source coverage. - Removed the obsolete skill-card.md file. v1.0.16 | 2026-10-02T14:36:56.562Z | auto - Added","descriptionLabel":"Technical summary","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1.1K downloads reported by the source. Last updated 10/11/2026.","installCommand":"clawhub skill install s170rf08skjvq3c8ct6ptsyjy58dn6we:koopje-search","sourceUrl":"https://clawhub.ai/antarcticaice/koopje-search","homepage":"https://clawhub.ai/antarcticaice/skills/koopje-search","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/antarcticaice/koopje-search","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/antarcticaice/skills/koopje-search","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":61,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"Search koopje.ai for Belgian second-hand deals and auctions. Skill: koopje-search Owner: antarcticaice Summary: Search koopje.ai for Belgian second-hand deals a"},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-11T10:44:37.914Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T10:44:37.914Z","emptyReason":null},"stars":null,"forks":null,"downloads":1084,"packageName":null,"latestVersion":"1.0.17","tractionLabel":"1.1K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T10:44:37.856Z","emptyReason":null},"lastUpdatedAt":"2026-10-11T10:44:37.914Z","lastCrawledAt":"2026-10-11T10:44:37.856Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-12T10:44:37.856Z","lastVerifiedAt":null,"highlights":[{"version":"1.0.17","createdAt":"2026-10-07T07:18:27.600Z","changelog":"- Added \"auctim\" to the list of supported auction-house sources. - Minor documentation updates to reflect the expanded source coverage. - Removed the obsolete skill-card.md file.","fileCount":4,"zipByteSize":8479},{"version":"1.0.16","createdAt":"2026-10-02T14:36:56.562Z","changelog":"- Added documentation for MCP (Claude/Cursor/ChatGPT) hosted endpoint with tools and setup link. - Removed deprecated skill-card.md file.","fileCount":4,"zipByteSize":8496},{"version":"1.0.15","createdAt":"2026-10-01T07:34:54.774Z","changelog":"- Added De Striep Promo (\"strieppromo\") as a new Belgian second-hand source. - Updated documentation to include \"strieppromo\" in the list of searchable sources and examples. - Removed the file: skill-card.md. - General documentation refresh.","fileCount":4,"zipByteSize":8381},{"version":"1.0.14","createdAt":"2026-09-29T15:48:39.391Z","changelog":"- Added support and documentation for the Think Twice (Think2.eu) vintage chain (“thinktwice” source). - Updated the list of searchable sources and bucket aliases to include Think Twice. - Updated references and examples to reflect the newly supported source. - Removed obsolete file: skill-card.md.","fileCount":4,"zipByteSize":8242},{"version":"1.0.13","createdAt":"2026-09-23T16:58:41.050Z","changelog":"- Added new listing type kringloop (for Troc.com and Kringwinkel thrift shops) alongside tweedehands and veiling in both API documentation and usage. - Updated /v1/search parameter details: listing_type now accepts tweedehands, veiling, and kringloop (can be repeated for multiselect). - Clarified that source param accepts bucket aliases like kringloop/troc for thrift stores. - Updated pitfalls section to explain new aliasing and listing_type selection changes. - Removed file: skill-card.md.","fileCount":4,"zipByteSize":8301},{"version":"1.0.12","createdAt":"2026-09-22T18:25:01.605Z","changelog":"- Updated documentation in SKILL.md and references/api.md for clarity and improved guidance. - Removed the outdated skill-card.md file. - Clarified available endpoints and example usage. - Adjusted rate limit details and error handling notes for /v1/answer endpoint. - Streamlined and cleaned up sections to reduce duplication.","fileCount":4,"zipByteSize":8125},{"version":"1.0.11","createdAt":"2026-09-16T19:34:34.922Z","changelog":"- Added Kringwinkel.be as a new supported source (including fixed-price webshop and auction lots). - Updated documentation to reflect Kringwinkel integration; new `source` option and usage notes. - Removed outdated file: skill-card.md.","fileCount":4,"zipByteSize":8485},{"version":"1.0.10","createdAt":"2026-09-15T13:02:58.797Z","changelog":"- Increased the default and maximum values for the search result limit (`limit`): now defaults to 24; max 100 for `keyword` search or 50 for `neural`/`auto`. - Updated search pagination instructions: use the `offset` parameter while `hasMore` is true. - Documentation improvements reflecting API changes, including limit adjustments. - Removed redundant documentation file (skill-card.md).","fileCount":4,"zipByteSize":8359}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s170rf08skjvq3c8ct6ptsyjy58dn6we:koopje-search","setupComplexity":"low","setupSteps":["Setup complexity is classified as HIGH. You must provision dedicated cloud infrastructure or an isolated VM. Do not run this directly on your local workstation.","Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-antarcticaice-koopje-search/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-antarcticaice-koopje-search/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-antarcticaice-koopje-search/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-antarcticaice-koopje-search/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-antarcticaice-koopje-search/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-antarcticaice-koopje-search/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-11T14:16:19.010Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-antarcticaice-koopje-search/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-antarcticaice-koopje-search/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-antarcticaice-koopje-search/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-antarcticaice-koopje-search/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"high","updatedAt":"2026-10-11T10:44:37.914Z","emptyReason":null},"readme":"Skill: koopje-search\n\nOwner: antarcticaice\n\nSummary: Search koopje.ai for Belgian second-hand deals and auctions.\n\nTags: latest:1.0.17\n\nVersion history:\n\nv1.0.17 | 2026-10-07T07:18:27.600Z | auto\n\n- Added \"auctim\" to the list of supported auction-house sources.\n- Minor documentation updates to reflect the expanded source coverage.\n- Removed the obsolete skill-card.md file.\n\nv1.0.16 | 2026-10-02T14:36:56.562Z | auto\n\n- Added documentation for MCP (Claude/Cursor/ChatGPT) hosted endpoint with tools and setup link.\n- Removed deprecated skill-card.md file.\n\nv1.0.15 | 2026-10-01T07:34:54.774Z | auto\n\n- Added De Striep Promo (\"strieppromo\") as a new Belgian second-hand source.\n- Updated documentation to include \"strieppromo\" in the list of searchable sources and examples.\n- Removed the file: skill-card.md.\n- General documentation refresh.\n\nv1.0.14 | 2026-09-29T15:48:39.391Z | auto\n\n- Added support and documentation for the Think Twice (Think2.eu) vintage chain (“thinktwice” source).\n- Updated the list of searchable sources and bucket aliases to include Think Twice.\n- Updated references and examples to reflect the newly supported source.\n- Removed obsolete file: skill-card.md.\n\nv1.0.13 | 2026-09-23T16:58:41.050Z | auto\n\n- Added new listing type kringloop (for Troc.com and Kringwinkel thrift shops) alongside tweedehands and veiling in both API documentation and usage.\n- Updated /v1/search parameter details: listing_type now accepts tweedehands, veiling, and kringloop (can be repeated for multiselect).\n- Clarified that source param accepts bucket aliases like kringloop/troc for thrift stores.\n- Updated pitfalls section to explain new aliasing and listing_type selection changes.\n- Removed file: skill-card.md.\n\nv1.0.12 | 2026-09-22T18:25:01.605Z | auto\n\n- Updated documentation in SKILL.md and references/api.md for clarity and improved guidance.\n- Removed the outdated skill-card.md file.\n- Clarified available endpoints and example usage.\n- Adjusted rate limit details and error handling notes for /v1/answer endpoint.\n- Streamlined and cleaned up sections to reduce duplication.\n\nv1.0.11 | 2026-09-16T19:34:34.922Z | auto\n\n- Added Kringwinkel.be as a new supported source (including fixed-price webshop and auction lots).\n- Updated documentation to reflect Kringwinkel integration; new `source` option and usage notes.\n- Removed outdated file: skill-card.md.\n\nv1.0.10 | 2026-09-15T13:02:58.797Z | auto\n\n- Increased the default and maximum values for the search result limit (`limit`): now defaults to 24; max 100 for `keyword` search or 50 for `neural`/`auto`.\n- Updated search pagination instructions: use the `offset` parameter while `hasMore` is true.\n- Documentation improvements reflecting API changes, including limit adjustments.\n- Removed redundant documentation file (skill-card.md).\n\nv1.0.9 | 2026-09-15T11:37:19.050Z | auto\n\n- Documentation updated in SKILL.md and references/api.md to reflect improvements or clarifications.\n- Removed the file skill-card.md.\n- No functional or API changes; this is a documentation cleanup release.\n\nv1.0.8 | 2026-09-12T13:03:47.333Z | auto\n\n- Added support for Belgian car dealer sources (e.g. autoscout24.be, gocar.be, mazdastock.be, vroom.be, autohero.com, irisautocenter.be, autocadre.com) as searchable domains.\n- Updated documentation to reflect new data sources and clarify car-dealer source usage.\n- Removed outdated references to troc.com being paused.\n- Cleaned up and clarified instructions for using the API.\n- Removed deprecated file: skill-card.md.\n\nv1.0.7 | 2026-09-09T10:45:35.139Z | auto\n\n- Updated user ad URL format: own ads now live at koopje.ai/<category>/<slug>-<id> instead of koopje.ai/l/<id>.\n- Documentation improvements to reflect new ad URL structure.\n- Removed obsolete documentation file: skill-card.md.\n\nv1.0.6 | 2026-09-09T06:44:49.353Z | auto\n\n- Added support and documentation for new own-ad endpoints: creating drafts (`POST /v1/listings/draft`) and publishing drafts (`POST /v1/listings/publish`).\n- Updated references to list the new endpoints for handling unindexed user listing drafts.\n- Removed the deprecated file `skill-card.md`.\n- Minor documentation clarifications and consistency fixes.\n\nv1.0.5 | 2026-09-08T21:05:16.098Z | auto\n\n- Added support for user-submitted own ads as a new source (`user`) in the koopje.ai search API.\n- Updated documentation to include endpoints and usage for creating, renewing, and managing user listings.\n- Removed outdated file: skill-card.md.\n\nv1.0.4 | 2026-09-08T19:21:03.671Z | auto\n\n- Expanded to 155k+ listings, now aggregating six sources (added Zoekertjes.be and individual auction-house slugs).\n- Introduced `listing_type` (binary: \"tweedehands\" or \"veiling\") for clearer filtering, independent of source.\n- Updated supported sources and parameter options, including more granular control over `source`.\n- Added agent endpoint (`POST /v1/agent`) and saved listings endpoints.\n- Clarified API limits, error reporting, latest pitfalls, and new features in documentation.\n- Removed outdated references and simplified instructions.\n\nv1.0.3 | 2026-09-03T11:59:12.425Z | user\n\nv1.0.3: offset pagination, _price_kind, distance/userLocation envelope, /v1/me usage\n\nv1.0.2 | 2026-09-03T10:16:53.849Z | user\n\nv1.0.2: distance filter params (postcode/max_km), auction-house naming\n\nv1.0.1 | 2026-09-03T08:20:55.151Z | user\n\nv1.0.1: name the actual auction houses (Vavato, Troostwijk, Belga-Veilingen, …) in results instead of only alleveilingen\n\nv1.0.0 | 2026-09-02T21:56:32.293Z | user\n\nInitial release: search 2dehands, Troc.com, Marktplaats BE listings and alleveilingen.be auctions\n\nArchive index:\n\nArchive v1.0.17: 4 files, 8479 bytes\n\nFiles: references/api.md (7920b), skill-card.md (1879b), SKILL.md (7791b), _meta.json (133b)\n\nFile v1.0.17:SKILL.md\n\n---\nname: koopje-search\ndescription: Search koopje.ai for Belgian second-hand deals and auctions.\nversion: 1.0.17\nauthor: Lukas, koopje.ai\nlicense: MIT\nmetadata:\n  openclaw:\n    requires:\n      env:\n        - KOOPJE_API_KEY\n  hermes:\n    tags: [koopje, search, second-hand, belgium, api]\n---\n\n# koopje.ai search API\n\nSearch ~155k Belgian second-hand listings and live auctions via the\nkoopje.ai REST API. The index aggregates 2dehands.be, auction houses,\nTroc.com, Think Twice, De Striep Promo, Marktplaats, Zoekertjes.be and Belgian car dealers, plus user ads:\n\n| source | what it is |\n|---|---|\n| `2dehands` | private sellers on 2dehands.be (Belgium's largest marketplace) |\n| `trader` | professional occasion sellers on 2dehands.be |\n| `troc` | Troc.com second-hand store inventory (Belgian stores) |\n| `thinktwice` | Think Twice vintage chain webshop Think2.eu (fixed price, kringloop) |\n| `strieppromo` | De Striep Promo Belgian strip shop, second-hand wall (fixed price, tweedehands) |\n| `marktplaats` | Belgian listings on Marktplaats.nl |\n| `zoekertjes` | free classifieds on Zoekertjes.be |\n| `kringwinkel` | Kringwinkel.be thrift webshop (fixed price) + veilingsite (auction lots); one source, `listing_type` splits them |\n| `user` | user-submitted own ads (live at `https://koopje.ai/<category>/<slug>-<id>`, 30-day expiry) |\n| car-dealer domains | Belgian cars carry their dealer/platform as source: `autoscout24.be`, `gocar.be`, `mazdastock.be`, `vroom.be`, `autohero.com`, `irisautocenter.be`, `autocadre.com` (resolved from listings, never the aggregator) |\n| auction-house slugs | auction lots carry their house as source: `alleveilingen`, `vavato`, `troostwijk`, `auctelia`, `belga-veilingen`, `vlavem`, `auctionport`, `openbare-verkopen`, `bopa`, `hammertime`, `veilbalie`, `komerco`, `lussis`, `bell-auction`, `industrial-auctions`, `appelboom`, `auctim` (house name also in `seller_name`) |\n\nEvery result also carries `listing_type`: `veiling` (any auction house),\n`kringloop` (Troc.com + Kringwinkel shop) or `tweedehands` (everything\nelse) — repeatable for multiselect, independent of source.\n\n## When to use\n\nTriggers: finding, comparing or pricing used items (\"tweedehands\",\n\"koopjes\", \"second-hand\"), auction lots (\"veiling\"), or Belgian\nmarketplace listings — e.g. \"find a used bike in Gent\", \"wat kost een\ntweedehands espresso-machine?\", \"similar to <listing url>\".\n\n## Prerequisites\n\n- `KOOPJE_API_KEY` env var, a `kk_...` key from koopje.ai (account →\n  \"API keys\"; shown once at creation).\n\n## How to call\n\nAll endpoints: `https://koopje.ai`, auth header on every request:\n`Authorization: Bearer $KOOPJE_API_KEY`. JSON responses, CORS enabled.\n\n### POST-free quickstart — GET /v1/search\n\n```\ncurl -s \"https://koopje.ai/v1/search?q=vintage+stoel&price_max=200&limit=5\" \\\n  -H \"Authorization: Bearer $KOOPJE_API_KEY\"\n```\n\nKey parameters (full list in `references/api.md`):\n\n| param | notes |\n|---|---|\n| `q` | required, natural language or keywords (Dutch works best) |\n| `source` | exact origin: `2dehands`, `troc`, `thinktwice`, `strieppromo`, `marktplaats`, `zoekertjes`, `kringwinkel`, a car-dealer domain (`autoscout24.be`, `gocar.be`, …), or an auction-house slug (`vavato`, `troostwijk`, …). Legacy aliases still work: `2dehands` → all tweedehands, `veiling` → all auctions. Default: all sources |\n| `listing_type` | `tweedehands` (all second-hand), `veiling` (all auction lots) or `kringloop` (thrift stores) — repeat for multiselect, independent of source |\n| `type` | `auto` (default), `neural` (semantic), `keyword` |\n| `price_min` / `price_max` | euros |\n| `no_price` | `0` hides listings without a price |\n| `limit` | default 24; max 100 (`keyword`) or 50 (`neural`/`auto`) |\n\n### Other endpoints\n\n- `GET /v1/similar?url=<listing-url>&limit=12` — visually/semantically\n  similar listings; url must be a listing already in the index.\n- `POST /v1/agent` — the website agent as an API: JSON body\n  `{\"message\": \"...\", \"conversation\": [...], \"source\": \"...\"}`,\n  streams the answer as Server-Sent Events (multi-step: it runs its own\n  searches). Limits: 10/min + 100/day per key.\n- `GET /v1/contents?urls=<url1,url2,...>` — full details per listing URL\n  (max 20 urls). Use after search when the user wants depth.\n- `GET /v1/stats` — per-source listing counts; good connectivity check.\n- MCP (Claude/Cursor/ChatGPT): hosted endpoint `https://koopje.ai/mcp`\n  (Streamable HTTP, JSON-RPC 2.0) with your Bearer key — tools\n  `search_listings`, `find_similar`, `get_listing`, `corpus_stats`,\n  same params and limits as above. Full setup: https://koopje.ai/api#mcp.\n- Saved listings (need the user's key; login-gated like everything else):\n  `GET /v1/saved` (newest first), `POST /v1/saved` with\n  `{\"url\": ..., \"title\": ..., \"price_value\": ..., \"price_text\": ...,\n  \"thumbnail_url\": ..., \"source\": ..., \"location\": ...}` (idempotent),\n  `POST /v1/saved/remove` with `{\"url\": ...}`.\n- Own listings (need the user's key): `POST /v1/listings` with\n  `{title, location, own: true}` plus `description, price_value,\n  category, source_url, images[]` (base64, max 5) → `{id, url}`;\n  `POST /v1/listings/fetch-url` to prefill from an ad link;\n  `POST /v1/listings/draft` with `{url, own: true}` for an unindexed\n  draft → `POST /v1/listings/publish` with `{id, ...overrides}`;\n  `GET /v1/listings/mine`, `POST /v1/listings/remove|renew`.\n  Full fields in `references/api.md`.\n\n## Reading results\n\n`results[]` items carry: `url`, `title`, `description` (short snippet),\n`price_value` + `price_text` (null when bidding/no price), `location`\n(city), `source` (actual origin: `2dehands`, `trader`, `troc`,\n`thinktwice`, `strieppromo`, `marktplaats`, `zoekertjes`, `user` (own ads at `koopje.ai/<category>/…`), a car-dealer domain (`autoscout24.be`,\n`gocar.be`, …), or an auction-house slug — `alleveilingen`,\n`vavato`, `troostwijk`, `auctelia`, `belga-veilingen`, `vlavem`, `auctionport`,\n`openbare-verkopen`, `bopa`, `hammertime`, `veilbalie`, `komerco`,\n`lussis`, `bell-auction`, `industrial-auctions`, `appelboom`, `auctim`), `listing_type`\n(`tweedehands` or `veiling`), `thumbnail_url`, `_score` (similarity).\n\nReport to the user in Dutch where possible; always include price,\nlocation and the actual source: name the site or auction house\nexplicitly (2dehands, Troc.com, Marktplaats.nl, or for auctions the\nauction house from `seller_name` — e.g. Vavato, Troostwijk,\nBelga-Veilingen); link the `url`. Auction items\n(`source: \"veiling\"`) have no fixed price — say so instead of quoting\n`price_text` as a sale price.\n\n## Pitfalls\n\n- `limit` caps at 100 (`keyword`) or 50 (`neural`/`auto`) — page with `offset` while `hasMore` is true.\n- `source` is a bucket alias (`2dehands` = all tweedehands, `veiling` = all auctions, `kringloop`/`troc`/`thinktwice` = thrift stores); the fine-grained site is\n  only visible per-result in the `source` field of the response.\n- 401 → key missing/revoked; 429 → rate limited (search/similar/contents/stats:\n  60/min + 2,000/day per key; agent: 10/min +\n  100/day), back off and retry once. Other failures (400/403/404/500) come\n  as `{\"error\": \"...\"}` — report the message, don't guess.\n- Agent docs: `GET https://koopje.ai/llms.txt` lists every agent-readable\n  page; `Accept: text/markdown` on `/`, `/docs`, `/api`, `/koppelen`\n  returns Markdown instead of HTML. n8n users: ready-made agent template\n  at https://koopje.ai/koppelen (n8n tab).\n- Empty `results` ≠ error: rephrase the query broader (Dutch nouns help)\n  before giving up.\n- Never invent listings; only report what the API returned.\n\n## Verification\n\n`GET /v1/stats` returns `{\"total\": ..., \"2dehands\": ..., \"veiling\": ...}`\n— if that fails, the key or connectivity is broken; tell the user instead\nof guessing.\n\nFile v1.0.17:_meta.json\n\n{\n  \"ownerId\": \"kn75qdj5yqrfxrwjd9tq8atz8n8dnsea\",\n  \"slug\": \"koopje-search\",\n  \"version\": \"1.0.17\",\n  \"publishedAt\": 1791357507600\n}\n\nFile v1.0.17:references/api.md\n\n# koopje.ai /v1 API reference\n\nBase: `https://koopje.ai` — all requests need `Authorization: Bearer kk_...`.\nAll responses JSON; `/v1/*` sends `Access-Control-Allow-Origin: *`.\n\nErrors: 401 missing/invalid key · 401 revoked key · 400 invalid params ·\n429 rate limited.\n\n## GET /v1/search\n\nSemantic + keyword search over the unified index.\n\n| param | type | required | description |\n|---|---|---|---|\n| `q` | string | yes | natural language or keywords (Dutch works best) |\n| `type` | string | no | `auto` (default) · `neural` · `keyword` |\n| `source` | string | no | exact origin: `2dehands` (2dehands.be platform incl. traders) · `troc` · `thinktwice` (Think Twice vintage) · `marktplaats` · `zoekertjes` · `kringwinkel` (thrift webshop + veilingsite, split by `listing_type`) · car-dealer domain (`autoscout24.be`, `gocar.be`, `mazdastock.be`, `vroom.be`, `autohero.com`, `irisautocenter.be`, `autocadre.com`) · auction house slug (`vavato`, `troostwijk`, `auctelia`, `belga-veilingen`, `vlavem`, `auctionport`, `openbare-verkopen`, `bopa`, `hammertime`, `veilbalie`, `komerco`, `lussis`, `bell-auction`, `industrial-auctions`, `appelboom`, `auctim`) · legacy bucket aliases: `2dehands`/`trader` → all tweedehands, `veiling` → all auctions |\n| `listing_type` | string | no | `tweedehands` (all second-hand) · `veiling` (all auction lots, every auction house) · `kringloop` (thrift stores) — repeatable for multiselect |\n| `price_min` | number | no | minimum price in euro |\n| `price_max` | number | no | maximum price in euro |\n| `no_price` | bool | no | `0` hides listings without a price (default `1` shows them) |\n| `limit` | number | no | default 24; max 100 (`keyword`) or 50 (`neural`/`auto`) |\n| `offset` | number | no | skip N results (\"toon meer\" pagination) |\n| `postcode` | string | no | 4-digit Belgian postcode (\"2000\") — results filtered to `max_km` around it and annotated with `_distance_km` |\n| `lat` / `lng` | number | no | raw user coordinates (alternative to `postcode`) |\n| `max_km` | number | no | radius in km around the user location (omit = no limit). Listings without any locatable city/coords are excluded when a location filter is active |\n\n`hasMore` is exact (server gathers limit+1 survivors past availability /\ntitle-dedup filters) — page with `offset` while it is true.\n\nResponse:\n\n```json\n{\n  \"requestId\": \"…\",\n  \"resolvedSearchType\": \"auto\",\n  \"hasMore\": true,\n  \"results\": [\n    {\n      \"url\": \"https://www.2dehands.be/v/…\",\n      \"title\": \"…\",\n      \"description\": \"short snippet\",\n      \"price_value\": 60.0,\n      \"price_text\": \"60 EUR\",\n      \"location\": \"Borgerhout\",\n      \"source\": \"2dehands\",\n      \"thumbnail_url\": \"…\",\n      \"_score\": 0.83\n    }\n  ]\n}\n```\n\n`source` values in results: `2dehands` (private sellers on 2dehands.be),\n`trader` (professional occasion sellers on 2dehands.be), `troc` (Troc.com\nstore inventory), `thinktwice` (Think Twice vintage webshop), `strieppromo` (De Striep Promo second-hand strips), `marktplaats` (Belgian listings on Marktplaats.nl),\n`zoekertjes` (Zoekertjes.be free classifieds), and auction-house slugs for\nauction lots (`vavato`, `troostwijk`, `auctelia`, `belga-veilingen`,\n`vlavem`, `auctionport`, `openbare-verkopen`, `bopa`, `hammertime`,\n`veilbalie`, `komerco`, `lussis`, `bell-auction`, `industrial-auctions`,\n`appelboom`, `auctim`; `alleveilingen` when the house is unknown), and car-dealer\ndomains for Belgian cars (`autoscout24.be`, `gocar.be`, `mazdastock.be`,\n`vroom.be`, `autohero.com`, `irisautocenter.be`, `autocadre.com`). Every result also\ncarries `listing_type`: `veiling` for auction lots, `kringloop` for\nthrift stores, `tweedehands` for everything else. Auction lots have no fixed price.\n\nEach result also carries `_price_kind` (`fixed`, `bid`, `auction`,\n`free`, `none`) and `category_slug`: the site's fine-grained\n`category`/`subcategory` names mapped onto one of 27 canonical Dutch\nfacets (`fietsen`, `autos`, …, `overig` when unmappable) — use the facet\nfor grouping/filtering, the originals for detail. Chat answers show it as\n`Categorie: <original> [<facet>]`. When a location filter was given — `_distance_km`\n(+ `_distance_approx` when derived from a city centroid). The envelope\nechoes `userLocation` (`label`, `lat`, `lng`, `maxKm`, `approx`) and\n`distance` (`maxKm`, `hidden`: rows dropped for lack of location).\n\n## GET /v1/similar\n\n| param | type | required | description |\n|---|---|---|---|\n| `url` | string | yes | URL of a listing in the index (2dehands, troc, thinktwice, strieppromo, marktplaats, zoekertjes, kringwinkel, veiling urls work) |\n| `limit` | number | no | default 24; keyword max 100, neural/auto max 50 |\n\nSame response shape as search.\n\nIf the seed URL is gone (sold/delisted), `similar` falls back to live\nlookalikes derived from the URL slug instead of a bare 404: the response\ncarries `\"seed_gone\": true` alongside `results`. Only a hintless/empty\nfallback still 404s (`{\"error\": \"listing not found\"}`).\n\n## GET /v1/contents\n\n| param | type | required | description |\n|---|---|---|---|\n| `urls` | string | yes | comma-separated listing URLs, max 20 |\n| `similar` | int | no | attach N similar listings per result (max 12, default 0) |\n\nFull listing details (description, attributes, seller, images) for the\ngiven URLs — use to deepen search results before reporting.\n\n## POST /v1/agent\n\nThe website agent as an API (streaming Server-Sent Events — read until\nconnection close). JSON body:\n\n| param | type | required | description |\n|---|---|---|---|\n| `message` | string | yes | the question in natural language |\n| `conversation` | array | no | earlier [{role, content}] messages for follow-ups |\n| `source` | string | no | source filter, same values as search |\n\nLimits: 10/min + 100/day per key. Use for multi-step tasks (it runs its\nown searches); use `/v1/search` + `/v1/contents` for single questions.\n\n## GET /v1/stats\n\nNo parameters. Returns `{\"total\": N, \"2dehands\": N, \"veiling\": N,\n\"trader\": N, \"troc\": N, \"thinktwice\": N, \"strieppromo\": N, \"marktplaats\": N, \"zoekertjes\": N, \"kringwinkel\": N}` — per-source listing counts.\n\n## Saved listings (login-gated)\n\n- `GET /v1/saved` → `{\"saved\": [{url, title, price_value, price_text,\n  thumbnail_url, source, location, saved_at}]}` newest first.\n- `POST /v1/saved` with `{\"url\": ...}` plus the snapshot fields above\n  (idempotent upsert — re-saving refreshes the snapshot).\n- `POST /v1/saved/remove` with `{\"url\": ...}`.\n\n## Own listings (login-gated, own ads only)\n\nUsers can publish their own ads (link import or from scratch); rows\ncarry `source: \"user\"`, live at `https://koopje.ai/<category>/<slug>-<id>`, expire\nafter 30 days (renewable). They appear in search like any row.\n\n- `POST /v1/listings/fetch-url` with `{\"url\": ...}` (known ad platform)\n  → `{title, description, price_value?, images?}` prefill, writes nothing.\n- `POST /v1/listings` with `{title, location, own: true}` plus\n  `description, price_value, price_text, category, source_url,\n  origin (\"manual\"|\"link\"), images[]` (base64 data URLs, max 5, 5MB each)\n  → `{ok, id, url, expires_at}`. `own: true` (ownership declaration)\n  is required. Max 10 active listings per account.\n- `GET /v1/listings/mine` → `{\"listings\": [...]}` newest first.\n- `POST /v1/listings/remove` / `POST /v1/listings/renew` with `{\"id\": ...}`.\n- `POST /v1/listings/draft` with `{url, own: true}` reads an ad link\n  into an unindexed, non-public draft → `{ok, id, draft: true, ...}`.\n- `POST /v1/listings/publish` with `{id}` plus optional field\n  overrides (title, description, price_value, price_text, location,\n  category, images[]) validates, indexes and publishes at\n  `https://koopje.ai/<category>/<slug>-<id>`, 30 days. (`/l/<id>` redirects there.)\n\n## Getting a key\n\nLog in at koopje.ai → menu (top right) → *API keys* → create. Keys\nare `kk_` + 32 chars and shown exactly once. Store as `KOOPJE_API_KEY`.\n\nFile v1.0.17:skill-card.md\n\n## Description:\n\nSearch koopje.ai for Belgian second-hand deals and auctions.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[antarcticaice](https://clawhub.ai/user/antarcticaice)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nShoppers and agents search and compare Belgian second-hand listings and auction lots, inspect listing details, and optionally manage saved or owned listings with the user's permission.\n\n### Deployment Geography for Use:\n\nGlobal (search coverage focuses on Belgian listings)\n\n## Known Risks and Mitigations:\n\nRisk: Searches and location details are sent to koopje.ai using the user's API key.\n\nMitigation: Use only when the user intends to share the search and any provided location details with koopje.ai.\n\nRisk: Saving, removing, renewing, or publishing listings can change the user's account or make an ad public.\n\nMitigation: Require an explicit request and final confirmation before each account-changing action, especially for public listings or precise coordinates.\n\n## Reference(s):\n\n- [ClawHub skill release](https://clawhub.ai/antarcticaice/skills/koopje-search)\n- [koopje.ai API documentation](https://koopje.ai/api)\n- [Included API reference](references/api.md)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Markdown, Shell commands]\n\n**Output Format:** [Markdown summaries with listing links and optional API examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Results include available prices, locations, and original listing sources.]\n\n## Skill Version(s):\n\n1.0.17 (source: server release metadata and frontmatter)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.0.16: 4 files, 8496 bytes\n\nFiles: references/api.md (7900b), skill-card.md (1907b), SKILL.md (7771b), _meta.json (133b)\n\nFile v1.0.16:SKILL.md\n\n---\nname: koopje-search\ndescription: Search koopje.ai for Belgian second-hand deals and auctions.\nversion: 1.0.16\nauthor: Lukas, koopje.ai\nlicense: MIT\nmetadata:\n  openclaw:\n    requires:\n      env:\n        - KOOPJE_API_KEY\n  hermes:\n    tags: [koopje, search, second-hand, belgium, api]\n---\n\n# koopje.ai search API\n\nSearch ~155k Belgian second-hand listings and live auctions via the\nkoopje.ai REST API. The index aggregates 2dehands.be, auction houses,\nTroc.com, Think Twice, De Striep Promo, Marktplaats, Zoekertjes.be and Belgian car dealers, plus user ads:\n\n| source | what it is |\n|---|---|\n| `2dehands` | private sellers on 2dehands.be (Belgium's largest marketplace) |\n| `trader` | professional occasion sellers on 2dehands.be |\n| `troc` | Troc.com second-hand store inventory (Belgian stores) |\n| `thinktwice` | Think Twice vintage chain webshop Think2.eu (fixed price, kringloop) |\n| `strieppromo` | De Striep Promo Belgian strip shop, second-hand wall (fixed price, tweedehands) |\n| `marktplaats` | Belgian listings on Marktplaats.nl |\n| `zoekertjes` | free classifieds on Zoekertjes.be |\n| `kringwinkel` | Kringwinkel.be thrift webshop (fixed price) + veilingsite (auction lots); one source, `listing_type` splits them |\n| `user` | user-submitted own ads (live at `https://koopje.ai/<category>/<slug>-<id>`, 30-day expiry) |\n| car-dealer domains | Belgian cars carry their dealer/platform as source: `autoscout24.be`, `gocar.be`, `mazdastock.be`, `vroom.be`, `autohero.com`, `irisautocenter.be`, `autocadre.com` (resolved from listings, never the aggregator) |\n| auction-house slugs | auction lots carry their house as source: `alleveilingen`, `vavato`, `troostwijk`, `auctelia`, `belga-veilingen`, `vlavem`, `auctionport`, `openbare-verkopen`, `bopa`, `hammertime`, `veilbalie`, `komerco`, `lussis`, `bell-auction`, `industrial-auctions`, `appelboom` (house name also in `seller_name`) |\n\nEvery result also carries `listing_type`: `veiling` (any auction house),\n`kringloop` (Troc.com + Kringwinkel shop) or `tweedehands` (everything\nelse) — repeatable for multiselect, independent of source.\n\n## When to use\n\nTriggers: finding, comparing or pricing used items (\"tweedehands\",\n\"koopjes\", \"second-hand\"), auction lots (\"veiling\"), or Belgian\nmarketplace listings — e.g. \"find a used bike in Gent\", \"wat kost een\ntweedehands espresso-machine?\", \"similar to <listing url>\".\n\n## Prerequisites\n\n- `KOOPJE_API_KEY` env var, a `kk_...` key from koopje.ai (account →\n  \"API keys\"; shown once at creation).\n\n## How to call\n\nAll endpoints: `https://koopje.ai`, auth header on every request:\n`Authorization: Bearer $KOOPJE_API_KEY`. JSON responses, CORS enabled.\n\n### POST-free quickstart — GET /v1/search\n\n```\ncurl -s \"https://koopje.ai/v1/search?q=vintage+stoel&price_max=200&limit=5\" \\\n  -H \"Authorization: Bearer $KOOPJE_API_KEY\"\n```\n\nKey parameters (full list in `references/api.md`):\n\n| param | notes |\n|---|---|\n| `q` | required, natural language or keywords (Dutch works best) |\n| `source` | exact origin: `2dehands`, `troc`, `thinktwice`, `strieppromo`, `marktplaats`, `zoekertjes`, `kringwinkel`, a car-dealer domain (`autoscout24.be`, `gocar.be`, …), or an auction-house slug (`vavato`, `troostwijk`, …). Legacy aliases still work: `2dehands` → all tweedehands, `veiling` → all auctions. Default: all sources |\n| `listing_type` | `tweedehands` (all second-hand), `veiling` (all auction lots) or `kringloop` (thrift stores) — repeat for multiselect, independent of source |\n| `type` | `auto` (default), `neural` (semantic), `keyword` |\n| `price_min` / `price_max` | euros |\n| `no_price` | `0` hides listings without a price |\n| `limit` | default 24; max 100 (`keyword`) or 50 (`neural`/`auto`) |\n\n### Other endpoints\n\n- `GET /v1/similar?url=<listing-url>&limit=12` — visually/semantically\n  similar listings; url must be a listing already in the index.\n- `POST /v1/agent` — the website agent as an API: JSON body\n  `{\"message\": \"...\", \"conversation\": [...], \"source\": \"...\"}`,\n  streams the answer as Server-Sent Events (multi-step: it runs its own\n  searches). Limits: 10/min + 100/day per key.\n- `GET /v1/contents?urls=<url1,url2,...>` — full details per listing URL\n  (max 20 urls). Use after search when the user wants depth.\n- `GET /v1/stats` — per-source listing counts; good connectivity check.\n- MCP (Claude/Cursor/ChatGPT): hosted endpoint `https://koopje.ai/mcp`\n  (Streamable HTTP, JSON-RPC 2.0) with your Bearer key — tools\n  `search_listings`, `find_similar`, `get_listing`, `corpus_stats`,\n  same params and limits as above. Full setup: https://koopje.ai/api#mcp.\n- Saved listings (need the user's key; login-gated like everything else):\n  `GET /v1/saved` (newest first), `POST /v1/saved` with\n  `{\"url\": ..., \"title\": ..., \"price_value\": ..., \"price_text\": ...,\n  \"thumbnail_url\": ..., \"source\": ..., \"location\": ...}` (idempotent),\n  `POST /v1/saved/remove` with `{\"url\": ...}`.\n- Own listings (need the user's key): `POST /v1/listings` with\n  `{title, location, own: true}` plus `description, price_value,\n  category, source_url, images[]` (base64, max 5) → `{id, url}`;\n  `POST /v1/listings/fetch-url` to prefill from an ad link;\n  `POST /v1/listings/draft` with `{url, own: true}` for an unindexed\n  draft → `POST /v1/listings/publish` with `{id, ...overrides}`;\n  `GET /v1/listings/mine`, `POST /v1/listings/remove|renew`.\n  Full fields in `references/api.md`.\n\n## Reading results\n\n`results[]` items carry: `url`, `title`, `description` (short snippet),\n`price_value` + `price_text` (null when bidding/no price), `location`\n(city), `source` (actual origin: `2dehands`, `trader`, `troc`,\n`thinktwice`, `strieppromo`, `marktplaats`, `zoekertjes`, `user` (own ads at `koopje.ai/<category>/…`), a car-dealer domain (`autoscout24.be`,\n`gocar.be`, …), or an auction-house slug — `alleveilingen`,\n`vavato`, `troostwijk`, `auctelia`, `belga-veilingen`, `vlavem`, `auctionport`,\n`openbare-verkopen`, `bopa`, `hammertime`, `veilbalie`, `komerco`,\n`lussis`, `bell-auction`, `industrial-auctions`, `appelboom`), `listing_type`\n(`tweedehands` or `veiling`), `thumbnail_url`, `_score` (similarity).\n\nReport to the user in Dutch where possible; always include price,\nlocation and the actual source: name the site or auction house\nexplicitly (2dehands, Troc.com, Marktplaats.nl, or for auctions the\nauction house from `seller_name` — e.g. Vavato, Troostwijk,\nBelga-Veilingen); link the `url`. Auction items\n(`source: \"veiling\"`) have no fixed price — say so instead of quoting\n`price_text` as a sale price.\n\n## Pitfalls\n\n- `limit` caps at 100 (`keyword`) or 50 (`neural`/`auto`) — page with `offset` while `hasMore` is true.\n- `source` is a bucket alias (`2dehands` = all tweedehands, `veiling` = all auctions, `kringloop`/`troc`/`thinktwice` = thrift stores); the fine-grained site is\n  only visible per-result in the `source` field of the response.\n- 401 → key missing/revoked; 429 → rate limited (search/similar/contents/stats:\n  60/min + 2,000/day per key; agent: 10/min +\n  100/day), back off and retry once. Other failures (400/403/404/500) come\n  as `{\"error\": \"...\"}` — report the message, don't guess.\n- Agent docs: `GET https://koopje.ai/llms.txt` lists every agent-readable\n  page; `Accept: text/markdown` on `/`, `/docs`, `/api`, `/koppelen`\n  returns Markdown instead of HTML. n8n users: ready-made agent template\n  at https://koopje.ai/koppelen (n8n tab).\n- Empty `results` ≠ error: rephrase the query broader (Dutch nouns help)\n  before giving up.\n- Never invent listings; only report what the API returned.\n\n## Verification\n\n`GET /v1/stats` returns `{\"total\": ..., \"2dehands\": ..., \"veiling\": ...}`\n— if that fails, the key or connectivity is broken; tell the user instead\nof guessing.\n\nFile v1.0.16:_meta.json\n\n{\n  \"ownerId\": \"kn75qdj5yqrfxrwjd9tq8atz8n8dnsea\",\n  \"slug\": \"koopje-search\",\n  \"version\": \"1.0.16\",\n  \"publishedAt\": 1790951816562\n}\n\nFile v1.0.16:references/api.md\n\n# koopje.ai /v1 API reference\n\nBase: `https://koopje.ai` — all requests need `Authorization: Bearer kk_...`.\nAll responses JSON; `/v1/*` sends `Access-Control-Allow-Origin: *`.\n\nErrors: 401 missing/invalid key · 401 revoked key · 400 invalid params ·\n429 rate limited.\n\n## GET /v1/search\n\nSemantic + keyword search over the unified index.\n\n| param | type | required | description |\n|---|---|---|---|\n| `q` | string | yes | natural language or keywords (Dutch works best) |\n| `type` | string | no | `auto` (default) · `neural` · `keyword` |\n| `source` | string | no | exact origin: `2dehands` (2dehands.be platform incl. traders) · `troc` · `thinktwice` (Think Twice vintage) · `marktplaats` · `zoekertjes` · `kringwinkel` (thrift webshop + veilingsite, split by `listing_type`) · car-dealer domain (`autoscout24.be`, `gocar.be`, `mazdastock.be`, `vroom.be`, `autohero.com`, `irisautocenter.be`, `autocadre.com`) · auction house slug (`vavato`, `troostwijk`, `auctelia`, `belga-veilingen`, `vlavem`, `auctionport`, `openbare-verkopen`, `bopa`, `hammertime`, `veilbalie`, `komerco`, `lussis`, `bell-auction`, `industrial-auctions`, `appelboom`) · legacy bucket aliases: `2dehands`/`trader` → all tweedehands, `veiling` → all auctions |\n| `listing_type` | string | no | `tweedehands` (all second-hand) · `veiling` (all auction lots, every auction house) · `kringloop` (thrift stores) — repeatable for multiselect |\n| `price_min` | number | no | minimum price in euro |\n| `price_max` | number | no | maximum price in euro |\n| `no_price` | bool | no | `0` hides listings without a price (default `1` shows them) |\n| `limit` | number | no | default 24; max 100 (`keyword`) or 50 (`neural`/`auto`) |\n| `offset` | number | no | skip N results (\"toon meer\" pagination) |\n| `postcode` | string | no | 4-digit Belgian postcode (\"2000\") — results filtered to `max_km` around it and annotated with `_distance_km` |\n| `lat` / `lng` | number | no | raw user coordinates (alternative to `postcode`) |\n| `max_km` | number | no | radius in km around the user location (omit = no limit). Listings without any locatable city/coords are excluded when a location filter is active |\n\n`hasMore` is exact (server gathers limit+1 survivors past availability /\ntitle-dedup filters) — page with `offset` while it is true.\n\nResponse:\n\n```json\n{\n  \"requestId\": \"…\",\n  \"resolvedSearchType\": \"auto\",\n  \"hasMore\": true,\n  \"results\": [\n    {\n      \"url\": \"https://www.2dehands.be/v/…\",\n      \"title\": \"…\",\n      \"description\": \"short snippet\",\n      \"price_value\": 60.0,\n      \"price_text\": \"60 EUR\",\n      \"location\": \"Borgerhout\",\n      \"source\": \"2dehands\",\n      \"thumbnail_url\": \"…\",\n      \"_score\": 0.83\n    }\n  ]\n}\n```\n\n`source` values in results: `2dehands` (private sellers on 2dehands.be),\n`trader` (professional occasion sellers on 2dehands.be), `troc` (Troc.com\nstore inventory), `thinktwice` (Think Twice vintage webshop), `strieppromo` (De Striep Promo second-hand strips), `marktplaats` (Belgian listings on Marktplaats.nl),\n`zoekertjes` (Zoekertjes.be free classifieds), and auction-house slugs for\nauction lots (`vavato`, `troostwijk`, `auctelia`, `belga-veilingen`,\n`vlavem`, `auctionport`, `openbare-verkopen`, `bopa`, `hammertime`,\n`veilbalie`, `komerco`, `lussis`, `bell-auction`, `industrial-auctions`,\n`appelboom`; `alleveilingen` when the house is unknown), and car-dealer\ndomains for Belgian cars (`autoscout24.be`, `gocar.be`, `mazdastock.be`,\n`vroom.be`, `autohero.com`, `irisautocenter.be`, `autocadre.com`). Every result also\ncarries `listing_type`: `veiling` for auction lots, `kringloop` for\nthrift stores, `tweedehands` for everything else. Auction lots have no fixed price.\n\nEach result also carries `_price_kind` (`fixed`, `bid`, `auction`,\n`free`, `none`) and `category_slug`: the site's fine-grained\n`category`/`subcategory` names mapped onto one of 27 canonical Dutch\nfacets (`fietsen`, `autos`, …, `overig` when unmappable) — use the facet\nfor grouping/filtering, the originals for detail. Chat answers show it as\n`Categorie: <original> [<facet>]`. When a location filter was given — `_distance_km`\n(+ `_distance_approx` when derived from a city centroid). The envelope\nechoes `userLocation` (`label`, `lat`, `lng`, `maxKm`, `approx`) and\n`distance` (`maxKm`, `hidden`: rows dropped for lack of location).\n\n## GET /v1/similar\n\n| param | type | required | description |\n|---|---|---|---|\n| `url` | string | yes | URL of a listing in the index (2dehands, troc, thinktwice, strieppromo, marktplaats, zoekertjes, kringwinkel, veiling urls work) |\n| `limit` | number | no | default 24; keyword max 100, neural/auto max 50 |\n\nSame response shape as search.\n\nIf the seed URL is gone (sold/delisted), `similar` falls back to live\nlookalikes derived from the URL slug instead of a bare 404: the response\ncarries `\"seed_gone\": true` alongside `results`. Only a hintless/empty\nfallback still 404s (`{\"error\": \"listing not found\"}`).\n\n## GET /v1/contents\n\n| param | type | required | description |\n|---|---|---|---|\n| `urls` | string | yes | comma-separated listing URLs, max 20 |\n| `similar` | int | no | attach N similar listings per result (max 12, default 0) |\n\nFull listing details (description, attributes, seller, images) for the\ngiven URLs — use to deepen search results before reporting.\n\n## POST /v1/agent\n\nThe website agent as an API (streaming Server-Sent Events — read until\nconnection close). JSON body:\n\n| param | type | required | description |\n|---|---|---|---|\n| `message` | string | yes | the question in natural language |\n| `conversation` | array | no | earlier [{role, content}] messages for follow-ups |\n| `source` | string | no | source filter, same values as search |\n\nLimits: 10/min + 100/day per key. Use for multi-step tasks (it runs its\nown searches); use `/v1/search` + `/v1/contents` for single questions.\n\n## GET /v1/stats\n\nNo parameters. Returns `{\"total\": N, \"2dehands\": N, \"veiling\": N,\n\"trader\": N, \"troc\": N, \"thinktwice\": N, \"strieppromo\": N, \"marktplaats\": N, \"zoekertjes\": N, \"kringwinkel\": N}` — per-source listing counts.\n\n## Saved listings (login-gated)\n\n- `GET /v1/saved` → `{\"saved\": [{url, title, price_value, price_text,\n  thumbnail_url, source, location, saved_at}]}` newest first.\n- `POST /v1/saved` with `{\"url\": ...}` plus the snapshot fields above\n  (idempotent upsert — re-saving refreshes the snapshot).\n- `POST /v1/saved/remove` with `{\"url\": ...}`.\n\n## Own listings (login-gated, own ads only)\n\nUsers can publish their own ads (link import or from scratch); rows\ncarry `source: \"user\"`, live at `https://koopje.ai/<category>/<slug>-<id>`, expire\nafter 30 days (renewable). They appear in search like any row.\n\n- `POST /v1/listings/fetch-url` with `{\"url\": ...}` (known ad platform)\n  → `{title, description, price_value?, images?}` prefill, writes nothing.\n- `POST /v1/listings` with `{title, location, own: true}` plus\n  `description, price_value, price_text, category, source_url,\n  origin (\"manual\"|\"link\"), images[]` (base64 data URLs, max 5, 5MB each)\n  → `{ok, id, url, expires_at}`. `own: true` (ownership declaration)\n  is required. Max 10 active listings per account.\n- `GET /v1/listings/mine` → `{\"listings\": [...]}` newest first.\n- `POST /v1/listings/remove` / `POST /v1/listings/renew` with `{\"id\": ...}`.\n- `POST /v1/listings/draft` with `{url, own: true}` reads an ad link\n  into an unindexed, non-public draft → `{ok, id, draft: true, ...}`.\n- `POST /v1/listings/publish` with `{id}` plus optional field\n  overrides (title, description, price_value, price_text, location,\n  category, images[]) validates, indexes and publishes at\n  `https://koopje.ai/<category>/<slug>-<id>`, 30 days. (`/l/<id>` redirects there.)\n\n## Getting a key\n\nLog in at koopje.ai → menu (top right) → *API keys* → create. Keys\nare `kk_` + 32 chars and shown exactly once. Store as `KOOPJE_API_KEY`.\n\nFile v1.0.16:skill-card.md\n\n## Description:\n\nSearch koopje.ai for Belgian second-hand deals and auctions.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[antarcticaice](https://clawhub.ai/user/antarcticaice)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nShoppers and assistants search and compare Belgian second-hand listings and auction lots, check listing details, and share prices, locations, sources, and links.\n\n### Deployment Geography for Use:\n\nGlobal (focused on Belgian marketplace listings)\n\n## Known Risks and Mitigations:\n\nRisk: A search-focused skill also provides actions that change saved items and public listings.\n\nMitigation: Treat searches as read-only; require explicit confirmation before saving or removing items, creating drafts, publishing or renewing ads, or removing listings.\n\nRisk: The API key may grant broader account access than search, and precise location may be disclosed.\n\nMitigation: Use a key only if its account permissions are acceptable, keep it private, and confirm before sending precise latitude and longitude.\n\n## Reference(s):\n\n- [ClawHub skill release](https://clawhub.ai/antarcticaice/skills/koopje-search)\n- [Koopje API reference](references/api.md)\n- [Koopje API and MCP setup](https://koopje.ai/api#mcp)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Markdown, Guidance]\n\n**Output Format:** [Markdown with listing links and summaries]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Results should identify prices, locations, and original sources; auction lots may not have fixed prices.]\n\n## Skill Version(s):\n\n1.0.16 (source: release metadata and skill frontmatter)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.0.15: 4 files, 8381 bytes\n\nFiles: references/api.md (7900b), skill-card.md (1986b), SKILL.md (7493b), _meta.json (133b)\n\nFile v1.0.15:SKILL.md\n\n---\nname: koopje-search\ndescription: Search koopje.ai for Belgian second-hand deals and auctions.\nversion: 1.0.15\nauthor: Lukas, koopje.ai\nlicense: MIT\nmetadata:\n  openclaw:\n    requires:\n      env:\n        - KOOPJE_API_KEY\n  hermes:\n    tags: [koopje, search, second-hand, belgium, api]\n---\n\n# koopje.ai search API\n\nSearch ~155k Belgian second-hand listings and live auctions via the\nkoopje.ai REST API. The index aggregates 2dehands.be, auction houses,\nTroc.com, Think Twice, De Striep Promo, Marktplaats, Zoekertjes.be and Belgian car dealers, plus user ads:\n\n| source | what it is |\n|---|---|\n| `2dehands` | private sellers on 2dehands.be (Belgium's largest marketplace) |\n| `trader` | professional occasion sellers on 2dehands.be |\n| `troc` | Troc.com second-hand store inventory (Belgian stores) |\n| `thinktwice` | Think Twice vintage chain webshop Think2.eu (fixed price, kringloop) |\n| `strieppromo` | De Striep Promo Belgian strip shop, second-hand wall (fixed price, tweedehands) |\n| `marktplaats` | Belgian listings on Marktplaats.nl |\n| `zoekertjes` | free classifieds on Zoekertjes.be |\n| `kringwinkel` | Kringwinkel.be thrift webshop (fixed price) + veilingsite (auction lots); one source, `listing_type` splits them |\n| `user` | user-submitted own ads (live at `https://koopje.ai/<category>/<slug>-<id>`, 30-day expiry) |\n| car-dealer domains | Belgian cars carry their dealer/platform as source: `autoscout24.be`, `gocar.be`, `mazdastock.be`, `vroom.be`, `autohero.com`, `irisautocenter.be`, `autocadre.com` (resolved from listings, never the aggregator) |\n| auction-house slugs | auction lots carry their house as source: `alleveilingen`, `vavato`, `troostwijk`, `auctelia`, `belga-veilingen`, `vlavem`, `auctionport`, `openbare-verkopen`, `bopa`, `hammertime`, `veilbalie`, `komerco`, `lussis`, `bell-auction`, `industrial-auctions`, `appelboom` (house name also in `seller_name`) |\n\nEvery result also carries `listing_type`: `veiling` (any auction house),\n`kringloop` (Troc.com + Kringwinkel shop) or `tweedehands` (everything\nelse) — repeatable for multiselect, independent of source.\n\n## When to use\n\nTriggers: finding, comparing or pricing used items (\"tweedehands\",\n\"koopjes\", \"second-hand\"), auction lots (\"veiling\"), or Belgian\nmarketplace listings — e.g. \"find a used bike in Gent\", \"wat kost een\ntweedehands espresso-machine?\", \"similar to <listing url>\".\n\n## Prerequisites\n\n- `KOOPJE_API_KEY` env var, a `kk_...` key from koopje.ai (account →\n  \"API keys\"; shown once at creation).\n\n## How to call\n\nAll endpoints: `https://koopje.ai`, auth header on every request:\n`Authorization: Bearer $KOOPJE_API_KEY`. JSON responses, CORS enabled.\n\n### POST-free quickstart — GET /v1/search\n\n```\ncurl -s \"https://koopje.ai/v1/search?q=vintage+stoel&price_max=200&limit=5\" \\\n  -H \"Authorization: Bearer $KOOPJE_API_KEY\"\n```\n\nKey parameters (full list in `references/api.md`):\n\n| param | notes |\n|---|---|\n| `q` | required, natural language or keywords (Dutch works best) |\n| `source` | exact origin: `2dehands`, `troc`, `thinktwice`, `strieppromo`, `marktplaats`, `zoekertjes`, `kringwinkel`, a car-dealer domain (`autoscout24.be`, `gocar.be`, …), or an auction-house slug (`vavato`, `troostwijk`, …). Legacy aliases still work: `2dehands` → all tweedehands, `veiling` → all auctions. Default: all sources |\n| `listing_type` | `tweedehands` (all second-hand), `veiling` (all auction lots) or `kringloop` (thrift stores) — repeat for multiselect, independent of source |\n| `type` | `auto` (default), `neural` (semantic), `keyword` |\n| `price_min` / `price_max` | euros |\n| `no_price` | `0` hides listings without a price |\n| `limit` | default 24; max 100 (`keyword`) or 50 (`neural`/`auto`) |\n\n### Other endpoints\n\n- `GET /v1/similar?url=<listing-url>&limit=12` — visually/semantically\n  similar listings; url must be a listing already in the index.\n- `POST /v1/agent` — the website agent as an API: JSON body\n  `{\"message\": \"...\", \"conversation\": [...], \"source\": \"...\"}`,\n  streams the answer as Server-Sent Events (multi-step: it runs its own\n  searches). Limits: 10/min + 100/day per key.\n- `GET /v1/contents?urls=<url1,url2,...>` — full details per listing URL\n  (max 20 urls). Use after search when the user wants depth.\n- `GET /v1/stats` — per-source listing counts; good connectivity check.\n- Saved listings (need the user's key; login-gated like everything else):\n  `GET /v1/saved` (newest first), `POST /v1/saved` with\n  `{\"url\": ..., \"title\": ..., \"price_value\": ..., \"price_text\": ...,\n  \"thumbnail_url\": ..., \"source\": ..., \"location\": ...}` (idempotent),\n  `POST /v1/saved/remove` with `{\"url\": ...}`.\n- Own listings (need the user's key): `POST /v1/listings` with\n  `{title, location, own: true}` plus `description, price_value,\n  category, source_url, images[]` (base64, max 5) → `{id, url}`;\n  `POST /v1/listings/fetch-url` to prefill from an ad link;\n  `POST /v1/listings/draft` with `{url, own: true}` for an unindexed\n  draft → `POST /v1/listings/publish` with `{id, ...overrides}`;\n  `GET /v1/listings/mine`, `POST /v1/listings/remove|renew`.\n  Full fields in `references/api.md`.\n\n## Reading results\n\n`results[]` items carry: `url`, `title`, `description` (short snippet),\n`price_value` + `price_text` (null when bidding/no price), `location`\n(city), `source` (actual origin: `2dehands`, `trader`, `troc`,\n`thinktwice`, `strieppromo`, `marktplaats`, `zoekertjes`, `user` (own ads at `koopje.ai/<category>/…`), a car-dealer domain (`autoscout24.be`,\n`gocar.be`, …), or an auction-house slug — `alleveilingen`,\n`vavato`, `troostwijk`, `auctelia`, `belga-veilingen`, `vlavem`, `auctionport`,\n`openbare-verkopen`, `bopa`, `hammertime`, `veilbalie`, `komerco`,\n`lussis`, `bell-auction`, `industrial-auctions`, `appelboom`), `listing_type`\n(`tweedehands` or `veiling`), `thumbnail_url`, `_score` (similarity).\n\nReport to the user in Dutch where possible; always include price,\nlocation and the actual source: name the site or auction house\nexplicitly (2dehands, Troc.com, Marktplaats.nl, or for auctions the\nauction house from `seller_name` — e.g. Vavato, Troostwijk,\nBelga-Veilingen); link the `url`. Auction items\n(`source: \"veiling\"`) have no fixed price — say so instead of quoting\n`price_text` as a sale price.\n\n## Pitfalls\n\n- `limit` caps at 100 (`keyword`) or 50 (`neural`/`auto`) — page with `offset` while `hasMore` is true.\n- `source` is a bucket alias (`2dehands` = all tweedehands, `veiling` = all auctions, `kringloop`/`troc`/`thinktwice` = thrift stores); the fine-grained site is\n  only visible per-result in the `source` field of the response.\n- 401 → key missing/revoked; 429 → rate limited (search/similar/contents/stats:\n  60/min + 2,000/day per key; agent: 10/min +\n  100/day), back off and retry once. Other failures (400/403/404/500) come\n  as `{\"error\": \"...\"}` — report the message, don't guess.\n- Agent docs: `GET https://koopje.ai/llms.txt` lists every agent-readable\n  page; `Accept: text/markdown` on `/`, `/docs`, `/api`, `/koppelen`\n  returns Markdown instead of HTML. n8n users: ready-made agent template\n  at https://koopje.ai/koppelen (n8n tab).\n- Empty `results` ≠ error: rephrase the query broader (Dutch nouns help)\n  before giving up.\n- Never invent listings; only report what the API returned.\n\n## Verification\n\n`GET /v1/stats` returns `{\"total\": ..., \"2dehands\": ..., \"veiling\": ...}`\n— if that fails, the key or connectivity is broken; tell the user instead\nof guessing.\n\nFile v1.0.15:_meta.json\n\n{\n  \"ownerId\": \"kn75qdj5yqrfxrwjd9tq8atz8n8dnsea\",\n  \"slug\": \"koopje-search\",\n  \"version\": \"1.0.15\",\n  \"publishedAt\": 1790840094774\n}\n\nFile v1.0.15:references/api.md\n\n# koopje.ai /v1 API reference\n\nBase: `https://koopje.ai` — all requests need `Authorization: Bearer kk_...`.\nAll responses JSON; `/v1/*` sends `Access-Control-Allow-Origin: *`.\n\nErrors: 401 missing/invalid key · 401 revoked key · 400 invalid params ·\n429 rate limited.\n\n## GET /v1/search\n\nSemantic + keyword search over the unified index.\n\n| param | type | required | description |\n|---|---|---|---|\n| `q` | string | yes | natural language or keywords (Dutch works best) |\n| `type` | string | no | `auto` (default) · `neural` · `keyword` |\n| `source` | string | no | exact origin: `2dehands` (2dehands.be platform incl. traders) · `troc` · `thinktwice` (Think Twice vintage) · `marktplaats` · `zoekertjes` · `kringwinkel` (thrift webshop + veilingsite, split by `listing_type`) · car-dealer domain (`autoscout24.be`, `gocar.be`, `mazdastock.be`, `vroom.be`, `autohero.com`, `irisautocenter.be`, `autocadre.com`) · auction house slug (`vavato`, `troostwijk`, `auctelia`, `belga-veilingen`, `vlavem`, `auctionport`, `openbare-verkopen`, `bopa`, `hammertime`, `veilbalie`, `komerco`, `lussis`, `bell-auction`, `industrial-auctions`, `appelboom`) · legacy bucket aliases: `2dehands`/`trader` → all tweedehands, `veiling` → all auctions |\n| `listing_type` | string | no | `tweedehands` (all second-hand) · `veiling` (all auction lots, every auction house) · `kringloop` (thrift stores) — repeatable for multiselect |\n| `price_min` | number | no | minimum price in euro |\n| `price_max` | number | no | maximum price in euro |\n| `no_price` | bool | no | `0` hides listings without a price (default `1` shows them) |\n| `limit` | number | no | default 24; max 100 (`keyword`) or 50 (`neural`/`auto`) |\n| `offset` | number | no | skip N results (\"toon meer\" pagination) |\n| `postcode` | string | no | 4-digit Belgian postcode (\"2000\") — results filtered to `max_km` around it and annotated with `_distance_km` |\n| `lat` / `lng` | number | no | raw user coordinates (alternative to `postcode`) |\n| `max_km` | number | no | radius in km around the user location (omit = no limit). Listings without any locatable city/coords are excluded when a location filter is active |\n\n`hasMore` is exact (server gathers limit+1 survivors past availability /\ntitle-dedup filters) — page with `offset` while it is true.\n\nResponse:\n\n```json\n{\n  \"requestId\": \"…\",\n  \"resolvedSearchType\": \"auto\",\n  \"hasMore\": true,\n  \"results\": [\n    {\n      \"url\": \"https://www.2dehands.be/v/…\",\n      \"title\": \"…\",\n      \"description\": \"short snippet\",\n      \"price_value\": 60.0,\n      \"price_text\": \"60 EUR\",\n      \"location\": \"Borgerhout\",\n      \"source\": \"2dehands\",\n      \"thumbnail_url\": \"…\",\n      \"_score\": 0.83\n    }\n  ]\n}\n```\n\n`source` values in results: `2dehands` (private sellers on 2dehands.be),\n`trader` (professional occasion sellers on 2dehands.be), `troc` (Troc.com\nstore inventory), `thinktwice` (Think Twice vintage webshop), `strieppromo` (De Striep Promo second-hand strips), `marktplaats` (Belgian listings on Marktplaats.nl),\n`zoekertjes` (Zoekertjes.be free classifieds), and auction-house slugs for\nauction lots (`vavato`, `troostwijk`, `auctelia`, `belga-veilingen`,\n`vlavem`, `auctionport`, `openbare-verkopen`, `bopa`, `hammertime`,\n`veilbalie`, `komerco`, `lussis`, `bell-auction`, `industrial-auctions`,\n`appelboom`; `alleveilingen` when the house is unknown), and car-dealer\ndomains for Belgian cars (`autoscout24.be`, `gocar.be`, `mazdastock.be`,\n`vroom.be`, `autohero.com`, `irisautocenter.be`, `autocadre.com`). Every result also\ncarries `listing_type`: `veiling` for auction lots, `kringloop` for\nthrift stores, `tweedehands` for everything else. Auction lots have no fixed price.\n\nEach result also carries `_price_kind` (`fixed`, `bid`, `auction`,\n`free`, `none`) and `category_slug`: the site's fine-grained\n`category`/`subcategory` names mapped onto one of 27 canonical Dutch\nfacets (`fietsen`, `autos`, …, `overig` when unmappable) — use the facet\nfor grouping/filtering, the originals for detail. Chat answers show it as\n`Categorie: <original> [<facet>]`. When a location filter was given — `_distance_km`\n(+ `_distance_approx` when derived from a city centroid). The envelope\nechoes `userLocation` (`label`, `lat`, `lng`, `maxKm`, `approx`) and\n`distance` (`maxKm`, `hidden`: rows dropped for lack of location).\n\n## GET /v1/similar\n\n| param | type | required | description |\n|---|---|---|---|\n| `url` | string | yes | URL of a listing in the index (2dehands, troc, thinktwice, strieppromo, marktplaats, zoekertjes, kringwinkel, veiling urls work) |\n| `limit` | number | no | default 24; keyword max 100, neural/auto max 50 |\n\nSame response shape as search.\n\nIf the seed URL is gone (sold/delisted), `similar` falls back to live\nlookalikes derived from the URL slug instead of a bare 404: the response\ncarries `\"seed_gone\": true` alongside `results`. Only a hintless/empty\nfallback still 404s (`{\"error\": \"listing not found\"}`).\n\n## GET /v1/contents\n\n| param | type | required | description |\n|---|---|---|---|\n| `urls` | string | yes | comma-separated listing URLs, max 20 |\n| `similar` | int | no | attach N similar listings per result (max 12, default 0) |\n\nFull listing details (description, attributes, seller, images) for the\ngiven URLs — use to deepen search results before reporting.\n\n## POST /v1/agent\n\nThe website agent as an API (streaming Server-Sent Events — read until\nconnection close). JSON body:\n\n| param | type | required | description |\n|---|---|---|---|\n| `message` | string | yes | the question in natural language |\n| `conversation` | array | no | earlier [{role, content}] messages for follow-ups |\n| `source` | string | no | source filter, same values as search |\n\nLimits: 10/min + 100/day per key. Use for multi-step tasks (it runs its\nown searches); use `/v1/search` + `/v1/contents` for single questions.\n\n## GET /v1/stats\n\nNo parameters. Returns `{\"total\": N, \"2dehands\": N, \"veiling\": N,\n\"trader\": N, \"troc\": N, \"thinktwice\": N, \"strieppromo\": N, \"marktplaats\": N, \"zoekertjes\": N, \"kringwinkel\": N}` — per-source listing counts.\n\n## Saved listings (login-gated)\n\n- `GET /v1/saved` → `{\"saved\": [{url, title, price_value, price_text,\n  thumbnail_url, source, location, saved_at}]}` newest first.\n- `POST /v1/saved` with `{\"url\": ...}` plus the snapshot fields above\n  (idempotent upsert — re-saving refreshes the snapshot).\n- `POST /v1/saved/remove` with `{\"url\": ...}`.\n\n## Own listings (login-gated, own ads only)\n\nUsers can publish their own ads (link import or from scratch); rows\ncarry `source: \"user\"`, live at `https://koopje.ai/<category>/<slug>-<id>`, expire\nafter 30 days (renewable). They appear in search like any row.\n\n- `POST /v1/listings/fetch-url` with `{\"url\": ...}` (known ad platform)\n  → `{title, description, price_value?, images?}` prefill, writes nothing.\n- `POST /v1/listings` with `{title, location, own: true}` plus\n  `description, price_value, price_text, category, source_url,\n  origin (\"manual\"|\"link\"), images[]` (base64 data URLs, max 5, 5MB each)\n  → `{ok, id, url, expires_at}`. `own: true` (ownership declaration)\n  is required. Max 10 active listings per account.\n- `GET /v1/listings/mine` → `{\"listings\": [...]}` newest first.\n- `POST /v1/listings/remove` / `POST /v1/listings/renew` with `{\"id\": ...}`.\n- `POST /v1/listings/draft` with `{url, own: true}` reads an ad link\n  into an unindexed, non-public draft → `{ok, id, draft: true, ...}`.\n- `POST /v1/listings/publish` with `{id}` plus optional field\n  overrides (title, description, price_value, price_text, location,\n  category, images[]) validates, indexes and publishes at\n  `https://koopje.ai/<category>/<slug>-<id>`, 30 days. (`/l/<id>` redirects there.)\n\n## Getting a key\n\nLog in at koopje.ai → menu (top right) → *API keys* → create. Keys\nare `kk_` + 32 chars and shown exactly once. Store as `KOOPJE_API_KEY`.\n\nFile v1.0.15:skill-card.md\n\n## Description:\n\nSearch koopje.ai for Belgian second-hand deals and auctions.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[antarcticaice](https://clawhub.ai/user/antarcticaice)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nShoppers and agents use this skill to find and compare Belgian second-hand listings and auction lots, check listing details, and report prices, locations, and sources.\n\n### Deployment Geography for Use:\n\nGlobal (searches focus on listings in Belgium)\n\n## Known Risks and Mitigations:\n\nRisk: Account actions can save or remove items and create, publish, renew, or remove public listings.\n\nMitigation: Prefer read-only search and require clear user confirmation before any listing or saved-item change.\n\nRisk: Location-based searches can disclose precise user coordinates to koopje.ai.\n\nMitigation: Use a postcode or omit location when possible; send precise coordinates only with explicit user consent.\n\nRisk: API access requires a private account key.\n\nMitigation: Keep the API key in the configured environment variable and do not include it in shared commands or responses.\n\n## Reference(s):\n\n- [ClawHub skill release](https://clawhub.ai/antarcticaice/skills/koopje-search)\n- [koopje.ai API reference](references/api.md)\n- [koopje.ai agent-readable documentation](https://koopje.ai/llms.txt)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Markdown, Guidance]\n\n**Output Format:** [Markdown with listing links, prices, locations, and sources]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Requires a koopje.ai API key; auction lots may not have a fixed price.]\n\n## Skill Version(s):\n\n1.0.15 (source: frontmatter and server release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.0.14: 4 files, 8242 bytes\n\nFiles: references/api.md (7817b), skill-card.md (1793b), SKILL.md (7346b), _meta.json (133b)\n\nFile v1.0.14:SKILL.md\n\n---\nname: koopje-search\ndescription: Search koopje.ai for Belgian second-hand deals and auctions.\nversion: 1.0.14\nauthor: Lukas, koopje.ai\nlicense: MIT\nmetadata:\n  openclaw:\n    requires:\n      env:\n        - KOOPJE_API_KEY\n  hermes:\n    tags: [koopje, search, second-hand, belgium, api]\n---\n\n# koopje.ai search API\n\nSearch ~155k Belgian second-hand listings and live auctions via the\nkoopje.ai REST API. The index aggregates 2dehands.be, auction houses,\nTroc.com, Think Twice, Marktplaats, Zoekertjes.be and Belgian car dealers, plus user ads:\n\n| source | what it is |\n|---|---|\n| `2dehands` | private sellers on 2dehands.be (Belgium's largest marketplace) |\n| `trader` | professional occasion sellers on 2dehands.be |\n| `troc` | Troc.com second-hand store inventory (Belgian stores) |\n| `thinktwice` | Think Twice vintage chain webshop Think2.eu (fixed price, kringloop) |\n| `marktplaats` | Belgian listings on Marktplaats.nl |\n| `zoekertjes` | free classifieds on Zoekertjes.be |\n| `kringwinkel` | Kringwinkel.be thrift webshop (fixed price) + veilingsite (auction lots); one source, `listing_type` splits them |\n| `user` | user-submitted own ads (live at `https://koopje.ai/<category>/<slug>-<id>`, 30-day expiry) |\n| car-dealer domains | Belgian cars carry their dealer/platform as source: `autoscout24.be`, `gocar.be`, `mazdastock.be`, `vroom.be`, `autohero.com`, `irisautocenter.be`, `autocadre.com` (resolved from listings, never the aggregator) |\n| auction-house slugs | auction lots carry their house as source: `alleveilingen`, `vavato`, `troostwijk`, `auctelia`, `belga-veilingen`, `vlavem`, `auctionport`, `openbare-verkopen`, `bopa`, `hammertime`, `veilbalie`, `komerco`, `lussis`, `bell-auction`, `industrial-auctions`, `appelboom` (house name also in `seller_name`) |\n\nEvery result also carries `listing_type`: `veiling` (any auction house),\n`kringloop` (Troc.com + Kringwinkel shop) or `tweedehands` (everything\nelse) — repeatable for multiselect, independent of source.\n\n## When to use\n\nTriggers: finding, comparing or pricing used items (\"tweedehands\",\n\"koopjes\", \"second-hand\"), auction lots (\"veiling\"), or Belgian\nmarketplace listings — e.g. \"find a used bike in Gent\", \"wat kost een\ntweedehands espresso-machine?\", \"similar to <listing url>\".\n\n## Prerequisites\n\n- `KOOPJE_API_KEY` env var, a `kk_...` key from koopje.ai (account →\n  \"API keys\"; shown once at creation).\n\n## How to call\n\nAll endpoints: `https://koopje.ai`, auth header on every request:\n`Authorization: Bearer $KOOPJE_API_KEY`. JSON responses, CORS enabled.\n\n### POST-free quickstart — GET /v1/search\n\n```\ncurl -s \"https://koopje.ai/v1/search?q=vintage+stoel&price_max=200&limit=5\" \\\n  -H \"Authorization: Bearer $KOOPJE_API_KEY\"\n```\n\nKey parameters (full list in `references/api.md`):\n\n| param | notes |\n|---|---|\n| `q` | required, natural language or keywords (Dutch works best) |\n| `source` | exact origin: `2dehands`, `troc`, `thinktwice`, `marktplaats`, `zoekertjes`, `kringwinkel`, a car-dealer domain (`autoscout24.be`, `gocar.be`, …), or an auction-house slug (`vavato`, `troostwijk`, …). Legacy aliases still work: `2dehands` → all tweedehands, `veiling` → all auctions. Default: all sources |\n| `listing_type` | `tweedehands` (all second-hand), `veiling` (all auction lots) or `kringloop` (thrift stores) — repeat for multiselect, independent of source |\n| `type` | `auto` (default), `neural` (semantic), `keyword` |\n| `price_min` / `price_max` | euros |\n| `no_price` | `0` hides listings without a price |\n| `limit` | default 24; max 100 (`keyword`) or 50 (`neural`/`auto`) |\n\n### Other endpoints\n\n- `GET /v1/similar?url=<listing-url>&limit=12` — visually/semantically\n  similar listings; url must be a listing already in the index.\n- `POST /v1/agent` — the website agent as an API: JSON body\n  `{\"message\": \"...\", \"conversation\": [...], \"source\": \"...\"}`,\n  streams the answer as Server-Sent Events (multi-step: it runs its own\n  searches). Limits: 10/min + 100/day per key.\n- `GET /v1/contents?urls=<url1,url2,...>` — full details per listing URL\n  (max 20 urls). Use after search when the user wants depth.\n- `GET /v1/stats` — per-source listing counts; good connectivity check.\n- Saved listings (need the user's key; login-gated like everything else):\n  `GET /v1/saved` (newest first), `POST /v1/saved` with\n  `{\"url\": ..., \"title\": ..., \"price_value\": ..., \"price_text\": ...,\n  \"thumbnail_url\": ..., \"source\": ..., \"location\": ...}` (idempotent),\n  `POST /v1/saved/remove` with `{\"url\": ...}`.\n- Own listings (need the user's key): `POST /v1/listings` with\n  `{title, location, own: true}` plus `description, price_value,\n  category, source_url, images[]` (base64, max 5) → `{id, url}`;\n  `POST /v1/listings/fetch-url` to prefill from an ad link;\n  `POST /v1/listings/draft` with `{url, own: true}` for an unindexed\n  draft → `POST /v1/listings/publish` with `{id, ...overrides}`;\n  `GET /v1/listings/mine`, `POST /v1/listings/remove|renew`.\n  Full fields in `references/api.md`.\n\n## Reading results\n\n`results[]` items carry: `url`, `title`, `description` (short snippet),\n`price_value` + `price_text` (null when bidding/no price), `location`\n(city), `source` (actual origin: `2dehands`, `trader`, `troc`,\n`thinktwice`, `marktplaats`, `zoekertjes`, `user` (own ads at `koopje.ai/<category>/…`), a car-dealer domain (`autoscout24.be`,\n`gocar.be`, …), or an auction-house slug — `alleveilingen`,\n`vavato`, `troostwijk`, `auctelia`, `belga-veilingen`, `vlavem`, `auctionport`,\n`openbare-verkopen`, `bopa`, `hammertime`, `veilbalie`, `komerco`,\n`lussis`, `bell-auction`, `industrial-auctions`, `appelboom`), `listing_type`\n(`tweedehands` or `veiling`), `thumbnail_url`, `_score` (similarity).\n\nReport to the user in Dutch where possible; always include price,\nlocation and the actual source: name the site or auction house\nexplicitly (2dehands, Troc.com, Marktplaats.nl, or for auctions the\nauction house from `seller_name` — e.g. Vavato, Troostwijk,\nBelga-Veilingen); link the `url`. Auction items\n(`source: \"veiling\"`) have no fixed price — say so instead of quoting\n`price_text` as a sale price.\n\n## Pitfalls\n\n- `limit` caps at 100 (`keyword`) or 50 (`neural`/`auto`) — page with `offset` while `hasMore` is true.\n- `source` is a bucket alias (`2dehands` = all tweedehands, `veiling` = all auctions, `kringloop`/`troc`/`thinktwice` = thrift stores); the fine-grained site is\n  only visible per-result in the `source` field of the response.\n- 401 → key missing/revoked; 429 → rate limited (search/similar/contents/stats:\n  60/min + 2,000/day per key; agent: 10/min +\n  100/day), back off and retry once. Other failures (400/403/404/500) come\n  as `{\"error\": \"...\"}` — report the message, don't guess.\n- Agent docs: `GET https://koopje.ai/llms.txt` lists every agent-readable\n  page; `Accept: text/markdown` on `/`, `/docs`, `/api`, `/koppelen`\n  returns Markdown instead of HTML. n8n users: ready-made agent template\n  at https://koopje.ai/koppelen (n8n tab).\n- Empty `results` ≠ error: rephrase the query broader (Dutch nouns help)\n  before giving up.\n- Never invent listings; only report what the API returned.\n\n## Verification\n\n`GET /v1/stats` returns `{\"total\": ..., \"2dehands\": ..., \"veiling\": ...}`\n— if that fails, the key or connectivity is broken; tell the user instead\nof guessing.\n\nFile v1.0.14:_meta.json\n\n{\n  \"ownerId\": \"kn75qdj5yqrfxrwjd9tq8atz8n8dnsea\",\n  \"slug\": \"koopje-search\",\n  \"version\": \"1.0.14\",\n  \"publishedAt\": 1790696919391\n}\n\nFile v1.0.14:references/api.md\n\n# koopje.ai /v1 API reference\n\nBase: `https://koopje.ai` — all requests need `Authorization: Bearer kk_...`.\nAll responses JSON; `/v1/*` sends `Access-Control-Allow-Origin: *`.\n\nErrors: 401 missing/invalid key · 401 revoked key · 400 invalid params ·\n429 rate limited.\n\n## GET /v1/search\n\nSemantic + keyword search over the unified index.\n\n| param | type | required | description |\n|---|---|---|---|\n| `q` | string | yes | natural language or keywords (Dutch works best) |\n| `type` | string | no | `auto` (default) · `neural` · `keyword` |\n| `source` | string | no | exact origin: `2dehands` (2dehands.be platform incl. traders) · `troc` · `thinktwice` (Think Twice vintage) · `marktplaats` · `zoekertjes` · `kringwinkel` (thrift webshop + veilingsite, split by `listing_type`) · car-dealer domain (`autoscout24.be`, `gocar.be`, `mazdastock.be`, `vroom.be`, `autohero.com`, `irisautocenter.be`, `autocadre.com`) · auction house slug (`vavato`, `troostwijk`, `auctelia`, `belga-veilingen`, `vlavem`, `auctionport`, `openbare-verkopen`, `bopa`, `hammertime`, `veilbalie`, `komerco`, `lussis`, `bell-auction`, `industrial-auctions`, `appelboom`) · legacy bucket aliases: `2dehands`/`trader` → all tweedehands, `veiling` → all auctions |\n| `listing_type` | string | no | `tweedehands` (all second-hand) · `veiling` (all auction lots, every auction house) · `kringloop` (thrift stores) — repeatable for multiselect |\n| `price_min` | number | no | minimum price in euro |\n| `price_max` | number | no | maximum price in euro |\n| `no_price` | bool | no | `0` hides listings without a price (default `1` shows them) |\n| `limit` | number | no | default 24; max 100 (`keyword`) or 50 (`neural`/`auto`) |\n| `offset` | number | no | skip N results (\"toon meer\" pagination) |\n| `postcode` | string | no | 4-digit Belgian postcode (\"2000\") — results filtered to `max_km` around it and annotated with `_distance_km` |\n| `lat` / `lng` | number | no | raw user coordinates (alternative to `postcode`) |\n| `max_km` | number | no | radius in km around the user location (omit = no limit). Listings without any locatable city/coords are excluded when a location filter is active |\n\n`hasMore` is exact (server gathers limit+1 survivors past availability /\ntitle-dedup filters) — page with `offset` while it is true.\n\nResponse:\n\n```json\n{\n  \"requestId\": \"…\",\n  \"resolvedSearchType\": \"auto\",\n  \"hasMore\": true,\n  \"results\": [\n    {\n      \"url\": \"https://www.2dehands.be/v/…\",\n      \"title\": \"…\",\n      \"description\": \"short snippet\",\n      \"price_value\": 60.0,\n      \"price_text\": \"60 EUR\",\n      \"location\": \"Borgerhout\",\n      \"source\": \"2dehands\",\n      \"thumbnail_url\": \"…\",\n      \"_score\": 0.83\n    }\n  ]\n}\n```\n\n`source` values in results: `2dehands` (private sellers on 2dehands.be),\n`trader` (professional occasion sellers on 2dehands.be), `troc` (Troc.com\nstore inventory), `thinktwice` (Think Twice vintage webshop), `marktplaats` (Belgian listings on Marktplaats.nl),\n`zoekertjes` (Zoekertjes.be free classifieds), and auction-house slugs for\nauction lots (`vavato`, `troostwijk`, `auctelia`, `belga-veilingen`,\n`vlavem`, `auctionport`, `openbare-verkopen`, `bopa`, `hammertime`,\n`veilbalie`, `komerco`, `lussis`, `bell-auction`, `industrial-auctions`,\n`appelboom`; `alleveilingen` when the house is unknown), and car-dealer\ndomains for Belgian cars (`autoscout24.be`, `gocar.be`, `mazdastock.be`,\n`vroom.be`, `autohero.com`, `irisautocenter.be`, `autocadre.com`). Every result also\ncarries `listing_type`: `veiling` for auction lots, `kringloop` for\nthrift stores, `tweedehands` for everything else. Auction lots have no fixed price.\n\nEach result also carries `_price_kind` (`fixed`, `bid`, `auction`,\n`free`, `none`) and `category_slug`: the site's fine-grained\n`category`/`subcategory` names mapped onto one of 27 canonical Dutch\nfacets (`fietsen`, `autos`, …, `overig` when unmappable) — use the facet\nfor grouping/filtering, the originals for detail. Chat answers show it as\n`Categorie: <original> [<facet>]`. When a location filter was given — `_distance_km`\n(+ `_distance_approx` when derived from a city centroid). The envelope\nechoes `userLocation` (`label`, `lat`, `lng`, `maxKm`, `approx`) and\n`distance` (`maxKm`, `hidden`: rows dropped for lack of location).\n\n## GET /v1/similar\n\n| param | type | required | description |\n|---|---|---|---|\n| `url` | string | yes | URL of a listing in the index (2dehands, troc, thinktwice, marktplaats, zoekertjes, kringwinkel, veiling urls work) |\n| `limit` | number | no | default 24; keyword max 100, neural/auto max 50 |\n\nSame response shape as search.\n\nIf the seed URL is gone (sold/delisted), `similar` falls back to live\nlookalikes derived from the URL slug instead of a bare 404: the response\ncarries `\"seed_gone\": true` alongside `results`. Only a hintless/empty\nfallback still 404s (`{\"error\": \"listing not found\"}`).\n\n## GET /v1/contents\n\n| param | type | required | description |\n|---|---|---|---|\n| `urls` | string | yes | comma-separated listing URLs, max 20 |\n| `similar` | int | no | attach N similar listings per result (max 12, default 0) |\n\nFull listing details (description, attributes, seller, images) for the\ngiven URLs — use to deepen search results before reporting.\n\n## POST /v1/agent\n\nThe website agent as an API (streaming Server-Sent Events — read until\nconnection close). JSON body:\n\n| param | type | required | description |\n|---|---|---|---|\n| `message` | string | yes | the question in natural language |\n| `conversation` | array | no | earlier [{role, content}] messages for follow-ups |\n| `source` | string | no | source filter, same values as search |\n\nLimits: 10/min + 100/day per key. Use for multi-step tasks (it runs its\nown searches); use `/v1/search` + `/v1/contents` for single questions.\n\n## GET /v1/stats\n\nNo parameters. Returns `{\"total\": N, \"2dehands\": N, \"veiling\": N,\n\"trader\": N, \"troc\": N, \"thinktwice\": N, \"marktplaats\": N, \"zoekertjes\": N, \"kringwinkel\": N}` — per-source listing counts.\n\n## Saved listings (login-gated)\n\n- `GET /v1/saved` → `{\"saved\": [{url, title, price_value, price_text,\n  thumbnail_url, source, location, saved_at}]}` newest first.\n- `POST /v1/saved` with `{\"url\": ...}` plus the snapshot fields above\n  (idempotent upsert — re-saving refreshes the snapshot).\n- `POST /v1/saved/remove` with `{\"url\": ...}`.\n\n## Own listings (login-gated, own ads only)\n\nUsers can publish their own ads (link import or from scratch); rows\ncarry `source: \"user\"`, live at `https://koopje.ai/<category>/<slug>-<id>`, expire\nafter 30 days (renewable). They appear in search like any row.\n\n- `POST /v1/listings/fetch-url` with `{\"url\": ...}` (known ad platform)\n  → `{title, description, price_value?, images?}` prefill, writes nothing.\n- `POST /v1/listings` with `{title, location, own: true}` plus\n  `description, price_value, price_text, category, source_url,\n  origin (\"manual\"|\"link\"), images[]` (base64 data URLs, max 5, 5MB each)\n  → `{ok, id, url, expires_at}`. `own: true` (ownership declaration)\n  is required. Max 10 active listings per account.\n- `GET /v1/listings/mine` → `{\"listings\": [...]}` newest first.\n- `POST /v1/listings/remove` / `POST /v1/listings/renew` with `{\"id\": ...}`.\n- `POST /v1/listings/draft` with `{url, own: true}` reads an ad link\n  into an unindexed, non-public draft → `{ok, id, draft: true, ...}`.\n- `POST /v1/listings/publish` with `{id}` plus optional field\n  overrides (title, description, price_value, price_text, location,\n  category, images[]) validates, indexes and publishes at\n  `https://koopje.ai/<category>/<slug>-<id>`, 30 days. (`/l/<id>` redirects there.)\n\n## Getting a key\n\nLog in at koopje.ai → menu (top right) → *API keys* → create. Keys\nare `kk_` + 32 chars and shown exactly once. Store as `KOOPJE_API_KEY`.\n\nFile v1.0.14:skill-card.md\n\n## Description:\n\nSearch koopje.ai for Belgian second-hand deals and auctions.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[antarcticaice](https://clawhub.ai/user/antarcticaice)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nPeople looking for used goods or auction lots in Belgium can find, compare and price listings from multiple marketplaces using a koopje.ai API key.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The API key grants access to saved items and the user's own listings, not just searches.\n\nMitigation: Keep the key private and require explicit confirmation before saving or removing items, or publishing, renewing or removing listings.\n\nRisk: Uploading listing images or sharing precise coordinates can disclose personal information.\n\nMitigation: Confirm the intended images and exact location with the user before sending them.\n\n## Reference(s):\n\n- [ClawHub skill release](https://clawhub.ai/antarcticaice/skills/koopje-search)\n- [koopje.ai API reference](references/api.md)\n- [koopje.ai agent documentation](https://koopje.ai/llms.txt)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Markdown, Shell commands, Guidance]\n\n**Output Format:** [Markdown with listing links and optional API examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Results should include price, location and original source; auction prices are not fixed sale prices.]\n\n## Skill Version(s):\n\n1.0.14 (source: frontmatter and server release)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.0.13: 4 files, 8301 bytes\n\nFiles: references/api.md (7677b), skill-card.md (2209b), SKILL.md (7204b), _meta.json (133b)\n\nFile v1.0.13:SKILL.md\n\n---\nname: koopje-search\ndescription: Search koopje.ai for Belgian second-hand deals and auctions.\nversion: 1.0.13\nauthor: Lukas, koopje.ai\nlicense: MIT\nmetadata:\n  openclaw:\n    requires:\n      env:\n        - KOOPJE_API_KEY\n  hermes:\n    tags: [koopje, search, second-hand, belgium, api]\n---\n\n# koopje.ai search API\n\nSearch ~155k Belgian second-hand listings and live auctions via the\nkoopje.ai REST API. The index aggregates 2dehands.be, auction houses,\nTroc.com, Marktplaats, Zoekertjes.be and Belgian car dealers, plus user ads:\n\n| source | what it is |\n|---|---|\n| `2dehands` | private sellers on 2dehands.be (Belgium's largest marketplace) |\n| `trader` | professional occasion sellers on 2dehands.be |\n| `troc` | Troc.com second-hand store inventory (Belgian stores) |\n| `marktplaats` | Belgian listings on Marktplaats.nl |\n| `zoekertjes` | free classifieds on Zoekertjes.be |\n| `kringwinkel` | Kringwinkel.be thrift webshop (fixed price) + veilingsite (auction lots); one source, `listing_type` splits them |\n| `user` | user-submitted own ads (live at `https://koopje.ai/<category>/<slug>-<id>`, 30-day expiry) |\n| car-dealer domains | Belgian cars carry their dealer/platform as source: `autoscout24.be`, `gocar.be`, `mazdastock.be`, `vroom.be`, `autohero.com`, `irisautocenter.be`, `autocadre.com` (resolved from listings, never the aggregator) |\n| auction-house slugs | auction lots carry their house as source: `alleveilingen`, `vavato`, `troostwijk`, `auctelia`, `belga-veilingen`, `vlavem`, `auctionport`, `openbare-verkopen`, `bopa`, `hammertime`, `veilbalie`, `komerco`, `lussis`, `bell-auction`, `industrial-auctions`, `appelboom` (house name also in `seller_name`) |\n\nEvery result also carries `listing_type`: `veiling` (any auction house),\n`kringloop` (Troc.com + Kringwinkel shop) or `tweedehands` (everything\nelse) — repeatable for multiselect, independent of source.\n\n## When to use\n\nTriggers: finding, comparing or pricing used items (\"tweedehands\",\n\"koopjes\", \"second-hand\"), auction lots (\"veiling\"), or Belgian\nmarketplace listings — e.g. \"find a used bike in Gent\", \"wat kost een\ntweedehands espresso-machine?\", \"similar to <listing url>\".\n\n## Prerequisites\n\n- `KOOPJE_API_KEY` env var, a `kk_...` key from koopje.ai (account →\n  \"API keys\"; shown once at creation).\n\n## How to call\n\nAll endpoints: `https://koopje.ai`, auth header on every request:\n`Authorization: Bearer $KOOPJE_API_KEY`. JSON responses, CORS enabled.\n\n### POST-free quickstart — GET /v1/search\n\n```\ncurl -s \"https://koopje.ai/v1/search?q=vintage+stoel&price_max=200&limit=5\" \\\n  -H \"Authorization: Bearer $KOOPJE_API_KEY\"\n```\n\nKey parameters (full list in `references/api.md`):\n\n| param | notes |\n|---|---|\n| `q` | required, natural language or keywords (Dutch works best) |\n| `source` | exact origin: `2dehands`, `troc`, `marktplaats`, `zoekertjes`, `kringwinkel`, a car-dealer domain (`autoscout24.be`, `gocar.be`, …), or an auction-house slug (`vavato`, `troostwijk`, …). Legacy aliases still work: `2dehands` → all tweedehands, `veiling` → all auctions. Default: all sources |\n| `listing_type` | `tweedehands` (all second-hand), `veiling` (all auction lots) or `kringloop` (thrift stores) — repeat for multiselect, independent of source |\n| `type` | `auto` (default), `neural` (semantic), `keyword` |\n| `price_min` / `price_max` | euros |\n| `no_price` | `0` hides listings without a price |\n| `limit` | default 24; max 100 (`keyword`) or 50 (`neural`/`auto`) |\n\n### Other endpoints\n\n- `GET /v1/similar?url=<listing-url>&limit=12` — visually/semantically\n  similar listings; url must be a listing already in the index.\n- `POST /v1/agent` — the website agent as an API: JSON body\n  `{\"message\": \"...\", \"conversation\": [...], \"source\": \"...\"}`,\n  streams the answer as Server-Sent Events (multi-step: it runs its own\n  searches). Limits: 10/min + 100/day per key.\n- `GET /v1/contents?urls=<url1,url2,...>` — full details per listing URL\n  (max 20 urls). Use after search when the user wants depth.\n- `GET /v1/stats` — per-source listing counts; good connectivity check.\n- Saved listings (need the user's key; login-gated like everything else):\n  `GET /v1/saved` (newest first), `POST /v1/saved` with\n  `{\"url\": ..., \"title\": ..., \"price_value\": ..., \"price_text\": ...,\n  \"thumbnail_url\": ..., \"source\": ..., \"location\": ...}` (idempotent),\n  `POST /v1/saved/remove` with `{\"url\": ...}`.\n- Own listings (need the user's key): `POST /v1/listings` with\n  `{title, location, own: true}` plus `description, price_value,\n  category, source_url, images[]` (base64, max 5) → `{id, url}`;\n  `POST /v1/listings/fetch-url` to prefill from an ad link;\n  `POST /v1/listings/draft` with `{url, own: true}` for an unindexed\n  draft → `POST /v1/listings/publish` with `{id, ...overrides}`;\n  `GET /v1/listings/mine`, `POST /v1/listings/remove|renew`.\n  Full fields in `references/api.md`.\n\n## Reading results\n\n`results[]` items carry: `url`, `title`, `description` (short snippet),\n`price_value` + `price_text` (null when bidding/no price), `location`\n(city), `source` (actual origin: `2dehands`, `trader`, `troc`,\n`marktplaats`, `zoekertjes`, `user` (own ads at `koopje.ai/<category>/…`), a car-dealer domain (`autoscout24.be`,\n`gocar.be`, …), or an auction-house slug — `alleveilingen`,\n`vavato`, `troostwijk`, `auctelia`, `belga-veilingen`, `vlavem`, `auctionport`,\n`openbare-verkopen`, `bopa`, `hammertime`, `veilbalie`, `komerco`,\n`lussis`, `bell-auction`, `industrial-auctions`, `appelboom`), `listing_type`\n(`tweedehands` or `veiling`), `thumbnail_url`, `_score` (similarity).\n\nReport to the user in Dutch where possible; always include price,\nlocation and the actual source: name the site or auction house\nexplicitly (2dehands, Troc.com, Marktplaats.nl, or for auctions the\nauction house from `seller_name` — e.g. Vavato, Troostwijk,\nBelga-Veilingen); link the `url`. Auction items\n(`source: \"veiling\"`) have no fixed price — say so instead of quoting\n`price_text` as a sale price.\n\n## Pitfalls\n\n- `limit` caps at 100 (`keyword`) or 50 (`neural`/`auto`) — page with `offset` while `hasMore` is true.\n- `source` is a bucket alias (`2dehands` = all tweedehands, `veiling` = all auctions, `kringloop`/`troc` = thrift stores); the fine-grained site is\n  only visible per-result in the `source` field of the response.\n- 401 → key missing/revoked; 429 → rate limited (search/similar/contents/stats:\n  60/min + 2,000/day per key; agent: 10/min +\n  100/day), back off and retry once. Other failures (400/403/404/500) come\n  as `{\"error\": \"...\"}` — report the message, don't guess.\n- Agent docs: `GET https://koopje.ai/llms.txt` lists every agent-readable\n  page; `Accept: text/markdown` on `/`, `/docs`, `/api`, `/koppelen`\n  returns Markdown instead of HTML. n8n users: ready-made agent template\n  at https://koopje.ai/koppelen (n8n tab).\n- Empty `results` ≠ error: rephrase the query broader (Dutch nouns help)\n  before giving up.\n- Never invent listings; only report what the API returned.\n\n## Verification\n\n`GET /v1/stats` returns `{\"total\": ..., \"2dehands\": ..., \"veiling\": ...}`\n— if that fails, the key or connectivity is broken; tell the user instead\nof guessing.\n\nFile v1.0.13:_meta.json\n\n{\n  \"ownerId\": \"kn75qdj5yqrfxrwjd9tq8atz8n8dnsea\",\n  \"slug\": \"koopje-search\",\n  \"version\": \"1.0.13\",\n  \"publishedAt\": 1790182721050\n}\n\nFile v1.0.13:references/api.md\n\n# koopje.ai /v1 API reference\n\nBase: `https://koopje.ai` — all requests need `Authorization: Bearer kk_...`.\nAll responses JSON; `/v1/*` sends `Access-Control-Allow-Origin: *`.\n\nErrors: 401 missing/invalid key · 401 revoked key · 400 invalid params ·\n429 rate limited.\n\n## GET /v1/search\n\nSemantic + keyword search over the unified index.\n\n| param | type | required | description |\n|---|---|---|---|\n| `q` | string | yes | natural language or keywords (Dutch works best) |\n| `type` | string | no | `auto` (default) · `neural` · `keyword` |\n| `source` | string | no | exact origin: `2dehands` (2dehands.be platform incl. traders) · `troc` · `marktplaats` · `zoekertjes` · `kringwinkel` (thrift webshop + veilingsite, split by `listing_type`) · car-dealer domain (`autoscout24.be`, `gocar.be`, `mazdastock.be`, `vroom.be`, `autohero.com`, `irisautocenter.be`, `autocadre.com`) · auction house slug (`vavato`, `troostwijk`, `auctelia`, `belga-veilingen`, `vlavem`, `auctionport`, `openbare-verkopen`, `bopa`, `hammertime`, `veilbalie`, `komerco`, `lussis`, `bell-auction`, `industrial-auctions`, `appelboom`) · legacy bucket aliases: `2dehands`/`trader` → all tweedehands, `veiling` → all auctions |\n| `listing_type` | string | no | `tweedehands` (all second-hand) · `veiling` (all auction lots, every auction house) · `kringloop` (thrift stores) — repeatable for multiselect |\n| `price_min` | number | no | minimum price in euro |\n| `price_max` | number | no | maximum price in euro |\n| `no_price` | bool | no | `0` hides listings without a price (default `1` shows them) |\n| `limit` | number | no | default 24; max 100 (`keyword`) or 50 (`neural`/`auto`) |\n| `offset` | number | no | skip N results (\"toon meer\" pagination) |\n| `postcode` | string | no | 4-digit Belgian postcode (\"2000\") — results filtered to `max_km` around it and annotated with `_distance_km` |\n| `lat` / `lng` | number | no | raw user coordinates (alternative to `postcode`) |\n| `max_km` | number | no | radius in km around the user location (omit = no limit). Listings without any locatable city/coords are excluded when a location filter is active |\n\n`hasMore` is exact (server gathers limit+1 survivors past availability /\ntitle-dedup filters) — page with `offset` while it is true.\n\nResponse:\n\n```json\n{\n  \"requestId\": \"…\",\n  \"resolvedSearchType\": \"auto\",\n  \"hasMore\": true,\n  \"results\": [\n    {\n      \"url\": \"https://www.2dehands.be/v/…\",\n      \"title\": \"…\",\n      \"description\": \"short snippet\",\n      \"price_value\": 60.0,\n      \"price_text\": \"60 EUR\",\n      \"location\": \"Borgerhout\",\n      \"source\": \"2dehands\",\n      \"thumbnail_url\": \"…\",\n      \"_score\": 0.83\n    }\n  ]\n}\n```\n\n`source` values in results: `2dehands` (private sellers on 2dehands.be),\n`trader` (professional occasion sellers on 2dehands.be), `troc` (Troc.com\nstore inventory), `marktplaats` (Belgian listings on Marktplaats.nl),\n`zoekertjes` (Zoekertjes.be free classifieds), and auction-house slugs for\nauction lots (`vavato`, `troostwijk`, `auctelia`, `belga-veilingen`,\n`vlavem`, `auctionport`, `openbare-verkopen`, `bopa`, `hammertime`,\n`veilbalie`, `komerco`, `lussis`, `bell-auction`, `industrial-auctions`,\n`appelboom`; `alleveilingen` when the house is unknown), and car-dealer\ndomains for Belgian cars (`autoscout24.be`, `gocar.be`, `mazdastock.be`,\n`vroom.be`, `autohero.com`, `irisautocenter.be`, `autocadre.com`). Every result also\ncarries `listing_type`: `veiling` for auction lots, `kringloop` for\nthrift stores, `tweedehands` for everything else. Auction lots have no fixed price.\n\nEach result also carries `_price_kind` (`fixed`, `bid`, `auction`,\n`free`, `none`) and `category_slug`: the site's fine-grained\n`category`/`subcategory` names mapped onto one of 27 canonical Dutch\nfacets (`fietsen`, `autos`, …, `overig` when unmappable) — use the facet\nfor grouping/filtering, the originals for detail. Chat answers show it as\n`Categorie: <original> [<facet>]`. When a location filter was given — `_distance_km`\n(+ `_distance_approx` when derived from a city centroid). The envelope\nechoes `userLocation` (`label`, `lat`, `lng`, `maxKm`, `approx`) and\n`distance` (`maxKm`, `hidden`: rows dropped for lack of location).\n\n## GET /v1/similar\n\n| param | type | required | description |\n|---|---|---|---|\n| `url` | string | yes | URL of a listing in the index (2dehands, troc, marktplaats, zoekertjes, kringwinkel, veiling urls work) |\n| `limit` | number | no | 1–24, default 12 |\n\nSame response shape as search.\n\nIf the seed URL is gone (sold/delisted), `similar` falls back to live\nlookalikes derived from the URL slug instead of a bare 404: the response\ncarries `\"seed_gone\": true` alongside `results`. Only a hintless/empty\nfallback still 404s (`{\"error\": \"listing not found\"}`).\n\n## GET /v1/contents\n\n| param | type | required | description |\n|---|---|---|---|\n| `urls` | string | yes | comma-separated listing URLs, max 20 |\n| `similar` | int | no | attach N similar listings per result (max 12, default 0) |\n\nFull listing details (description, attributes, seller, images) for the\ngiven URLs — use to deepen search results before reporting.\n\n## POST /v1/agent\n\nThe website agent as an API (streaming Server-Sent Events — read until\nconnection close). JSON body:\n\n| param | type | required | description |\n|---|---|---|---|\n| `message` | string | yes | the question in natural language |\n| `conversation` | array | no | earlier [{role, content}] messages for follow-ups |\n| `source` | string | no | source filter, same values as search |\n\nLimits: 10/min + 100/day per key. Use for multi-step tasks (it runs its\nown searches); use `/v1/search` + `/v1/contents` for single questions.\n\n## GET /v1/stats\n\nNo parameters. Returns `{\"total\": N, \"2dehands\": N, \"veiling\": N,\n\"trader\": N, \"troc\": N, \"marktplaats\": N, \"zoekertjes\": N, \"kringwinkel\": N}` — per-source listing counts.\n\n## Saved listings (login-gated)\n\n- `GET /v1/saved` → `{\"saved\": [{url, title, price_value, price_text,\n  thumbnail_url, source, location, saved_at}]}` newest first.\n- `POST /v1/saved` with `{\"url\": ...}` plus the snapshot fields above\n  (idempotent upsert — re-saving refreshes the snapshot).\n- `POST /v1/saved/remove` with `{\"url\": ...}`.\n\n## Own listings (login-gated, own ads only)\n\nUsers can publish their own ads (link import or from scratch); rows\ncarry `source: \"user\"`, live at `https://koopje.ai/<category>/<slug>-<id>`, expire\nafter 30 days (renewable). They appear in search like any row.\n\n- `POST /v1/listings/fetch-url` with `{\"url\": ...}` (known ad platform)\n  → `{title, description, price_value?, images?}` prefill, writes nothing.\n- `POST /v1/listings` with `{title, location, own: true}` plus\n  `description, price_value, price_text, category, source_url,\n  origin (\"manual\"|\"link\"), images[]` (base64 data URLs, max 5, 5MB each)\n  → `{ok, id, url, expires_at}`. `own: true` (ownership declaration)\n  is required. Max 10 active listings per account.\n- `GET /v1/listings/mine` → `{\"listings\": [...]}` newest first.\n- `POST /v1/listings/remove` / `POST /v1/listings/renew` with `{\"id\": ...}`.\n- `POST /v1/listings/draft` with `{url, own: true}` reads an ad link\n  into an unindexed, non-public draft → `{ok, id, draft: true, ...}`.\n- `POST /v1/listings/publish` with `{id}` plus optional field\n  overrides (title, description, price_value, price_text, location,\n  category, images[]) validates, indexes and publishes at\n  `https://koopje.ai/<category>/<slug>-<id>`, 30 days. (`/l/<id>` redirects there.)\n\n## Getting a key\n\nLog in at koopje.ai → menu (top right) → *API keys* → create. Keys\nare `kk_` + 32 chars and shown exactly once. Store as `KOOPJE_API_KEY`.\n\nFile v1.0.13:skill-card.md\n\n## Description:\n\nSearch koopje.ai for Belgian second-hand deals and auctions.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[antarcticaice](https://clawhub.ai/user/antarcticaice)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nExternal users and developers use this skill to find, compare, and price Belgian second-hand listings, thrift-store items, car listings, and auction lots through the koopje.ai API.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill documents saved-listing and own-listing endpoints that can change account state or publish public listings.\n\nMitigation: Require explicit user confirmation before saving, removing, renewing, drafting, publishing, or managing own listings.\n\nRisk: The skill requires a koopje.ai API key and may use location or conversation details during searches.\n\nMitigation: Keep the API key in KOOPJE_API_KEY and avoid sending precise location or sensitive conversation history unless needed for the request.\n\nRisk: Search results, prices, and auction availability may be incomplete or stale.\n\nMitigation: Report only API-returned listings, include source, price, location, and links, and surface API errors or empty result sets without inventing listings.\n\n## Reference(s):\n\n- [koopje.ai /v1 API reference](references/api.md)\n- [koopje.ai API base](https://koopje.ai)\n- [Agent-readable koopje.ai documentation](https://koopje.ai/llms.txt)\n- [koopje.ai integration templates](https://koopje.ai/koppelen)\n\n## Skill Output:\n\n**Output Type(s):** [text, markdown, shell commands, configuration, guidance]\n\n**Output Format:** [Markdown guidance with API examples and concise result summaries]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Requires KOOPJE_API_KEY; account-changing actions should be confirmed before execution.]\n\n## Skill Version(s):\n\n1.0.13 (source: frontmatter and server release evidence)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.0.12: 4 files, 8125 bytes\n\nFiles: references/api.md (7609b), skill-card.md (1972b), SKILL.md (7039b), _meta.json (133b)\n\nFile v1.0.12:SKILL.md\n\n---\nname: koopje-search\ndescription: Search koopje.ai for Belgian second-hand deals and auctions.\nversion: 1.0.12\nauthor: Lukas, koopje.ai\nlicense: MIT\nmetadata:\n  openclaw:\n    requires:\n      env:\n        - KOOPJE_API_KEY\n  hermes:\n    tags: [koopje, search, second-hand, belgium, api]\n---\n\n# koopje.ai search API\n\nSearch ~155k Belgian second-hand listings and live auctions via the\nkoopje.ai REST API. The index aggregates 2dehands.be, auction houses,\nTroc.com, Marktplaats, Zoekertjes.be and Belgian car dealers, plus user ads:\n\n| source | what it is |\n|---|---|\n| `2dehands` | private sellers on 2dehands.be (Belgium's largest marketplace) |\n| `trader` | professional occasion sellers on 2dehands.be |\n| `troc` | Troc.com second-hand store inventory (Belgian stores) |\n| `marktplaats` | Belgian listings on Marktplaats.nl |\n| `zoekertjes` | free classifieds on Zoekertjes.be |\n| `kringwinkel` | Kringwinkel.be thrift webshop (fixed price) + veilingsite (auction lots); one source, `listing_type` splits them |\n| `user` | user-submitted own ads (live at `https://koopje.ai/<category>/<slug>-<id>`, 30-day expiry) |\n| car-dealer domains | Belgian cars carry their dealer/platform as source: `autoscout24.be`, `gocar.be`, `mazdastock.be`, `vroom.be`, `autohero.com`, `irisautocenter.be`, `autocadre.com` (resolved from listings, never the aggregator) |\n| auction-house slugs | auction lots carry their house as source: `alleveilingen`, `vavato`, `troostwijk`, `auctelia`, `belga-veilingen`, `vlavem`, `auctionport`, `openbare-verkopen`, `bopa`, `hammertime`, `veilbalie`, `komerco`, `lussis`, `bell-auction`, `industrial-auctions`, `appelboom` (house name also in `seller_name`) |\n\nEvery result also carries `listing_type`: `veiling` (any auction house) or\n`tweedehands` (everything else) — the binary filter, independent of source.\n\n## When to use\n\nTriggers: finding, comparing or pricing used items (\"tweedehands\",\n\"koopjes\", \"second-hand\"), auction lots (\"veiling\"), or Belgian\nmarketplace listings — e.g. \"find a used bike in Gent\", \"wat kost een\ntweedehands espresso-machine?\", \"similar to <listing url>\".\n\n## Prerequisites\n\n- `KOOPJE_API_KEY` env var, a `kk_...` key from koopje.ai (account →\n  \"API keys\"; shown once at creation).\n\n## How to call\n\nAll endpoints: `https://koopje.ai`, auth header on every request:\n`Authorization: Bearer $KOOPJE_API_KEY`. JSON responses, CORS enabled.\n\n### POST-free quickstart — GET /v1/search\n\n```\ncurl -s \"https://koopje.ai/v1/search?q=vintage+stoel&price_max=200&limit=5\" \\\n  -H \"Authorization: Bearer $KOOPJE_API_KEY\"\n```\n\nKey parameters (full list in `references/api.md`):\n\n| param | notes |\n|---|---|\n| `q` | required, natural language or keywords (Dutch works best) |\n| `source` | exact origin: `2dehands`, `troc`, `marktplaats`, `zoekertjes`, `kringwinkel`, a car-dealer domain (`autoscout24.be`, `gocar.be`, …), or an auction-house slug (`vavato`, `troostwijk`, …). Legacy aliases still work: `2dehands` → all tweedehands, `veiling` → all auctions. Default: all sources |\n| `listing_type` | `tweedehands` (all second-hand) or `veiling` (all auction lots) — binary filter, independent of source |\n| `type` | `auto` (default), `neural` (semantic), `keyword` |\n| `price_min` / `price_max` | euros |\n| `no_price` | `0` hides listings without a price |\n| `limit` | default 24; max 100 (`keyword`) or 50 (`neural`/`auto`) |\n\n### Other endpoints\n\n- `GET /v1/similar?url=<listing-url>&limit=12` — visually/semantically\n  similar listings; url must be a listing already in the index.\n- `POST /v1/agent` — the website agent as an API: JSON body\n  `{\"message\": \"...\", \"conversation\": [...], \"source\": \"...\"}`,\n  streams the answer as Server-Sent Events (multi-step: it runs its own\n  searches). Limits: 10/min + 100/day per key.\n- `GET /v1/contents?urls=<url1,url2,...>` — full details per listing URL\n  (max 20 urls). Use after search when the user wants depth.\n- `GET /v1/stats` — per-source listing counts; good connectivity check.\n- Saved listings (need the user's key; login-gated like everything else):\n  `GET /v1/saved` (newest first), `POST /v1/saved` with\n  `{\"url\": ..., \"title\": ..., \"price_value\": ..., \"price_text\": ...,\n  \"thumbnail_url\": ..., \"source\": ..., \"location\": ...}` (idempotent),\n  `POST /v1/saved/remove` with `{\"url\": ...}`.\n- Own listings (need the user's key): `POST /v1/listings` with\n  `{title, location, own: true}` plus `description, price_value,\n  category, source_url, images[]` (base64, max 5) → `{id, url}`;\n  `POST /v1/listings/fetch-url` to prefill from an ad link;\n  `POST /v1/listings/draft` with `{url, own: true}` for an unindexed\n  draft → `POST /v1/listings/publish` with `{id, ...overrides}`;\n  `GET /v1/listings/mine`, `POST /v1/listings/remove|renew`.\n  Full fields in `references/api.md`.\n\n## Reading results\n\n`results[]` items carry: `url`, `title`, `description` (short snippet),\n`price_value` + `price_text` (null when bidding/no price), `location`\n(city), `source` (actual origin: `2dehands`, `trader`, `troc`,\n`marktplaats`, `zoekertjes`, `user` (own ads at `koopje.ai/<category>/…`), a car-dealer domain (`autoscout24.be`,\n`gocar.be`, …), or an auction-house slug — `alleveilingen`,\n`vavato`, `troostwijk`, `auctelia`, `belga-veilingen`, `vlavem`, `auctionport`,\n`openbare-verkopen`, `bopa`, `hammertime`, `veilbalie`, `komerco`,\n`lussis`, `bell-auction`, `industrial-auctions`, `appelboom`), `listing_type`\n(`tweedehands` or `veiling`), `thumbnail_url`, `_score` (similarity).\n\nReport to the user in Dutch where possible; always include price,\nlocation and the actual source: name the site or auction house\nexplicitly (2dehands, Troc.com, Marktplaats.nl, or for auctions the\nauction house from `seller_name` — e.g. Vavato, Troostwijk,\nBelga-Veilingen); link the `url`. Auction items\n(`source: \"veiling\"`) have no fixed price — say so instead of quoting\n`price_text` as a sale price.\n\n## Pitfalls\n\n- `limit` caps at 100 (`keyword`) or 50 (`neural`/`auto`) — page with `offset` while `hasMore` is true.\n- `source` is binary (`2dehands` vs `veiling`); the fine-grained site is\n  only visible per-result in the `source` field of the response.\n- 401 → key missing/revoked; 429 → rate limited (search/similar/contents/stats:\n  60/min + 2,000/day per key; agent: 10/min +\n  100/day), back off and retry once. Other failures (400/403/404/500) come\n  as `{\"error\": \"...\"}` — report the message, don't guess.\n- Agent docs: `GET https://koopje.ai/llms.txt` lists every agent-readable\n  page; `Accept: text/markdown` on `/`, `/docs`, `/api`, `/koppelen`\n  returns Markdown instead of HTML. n8n users: ready-made agent template\n  at https://koopje.ai/koppelen (n8n tab).\n- Empty `results` ≠ error: rephrase the query broader (Dutch nouns help)\n  before giving up.\n- Never invent listings; only report what the API returned.\n\n## Verification\n\n`GET /v1/stats` returns `{\"total\": ..., \"2dehands\": ..., \"veiling\": ...}`\n— if that fails, the key or connectivity is broken; tell the user instead\nof guessing.\n\nFile v1.0.12:_meta.json\n\n{\n  \"ownerId\": \"kn75qdj5yqrfxrwjd9tq8atz8n8dnsea\",\n  \"slug\": \"koopje-search\",\n  \"version\": \"1.0.12\",\n  \"publishedAt\": 1790101501605\n}\n\nFile v1.0.12:references/api.md\n\n# koopje.ai /v1 API reference\n\nBase: `https://koopje.ai` — all requests need `Authorization: Bearer kk_...`.\nAll responses JSON; `/v1/*` sends `Access-Control-Allow-Origin: *`.\n\nErrors: 401 missing/invalid key · 401 revoked key · 400 invalid params ·\n429 rate limited.\n\n## GET /v1/search\n\nSemantic + keyword search over the unified index.\n\n| param | type | required | description |\n|---|---|---|---|\n| `q` | string | yes | natural language or keywords (Dutch works best) |\n| `type` | string | no | `auto` (default) · `neural` · `keyword` |\n| `source` | string | no | exact origin: `2dehands` (2dehands.be platform incl. traders) · `troc` · `marktplaats` · `zoekertjes` · `kringwinkel` (thrift webshop + veilingsite, split by `listing_type`) · car-dealer domain (`autoscout24.be`, `gocar.be`, `mazdastock.be`, `vroom.be`, `autohero.com`, `irisautocenter.be`, `autocadre.com`) · auction house slug (`vavato`, `troostwijk`, `auctelia`, `belga-veilingen`, `vlavem`, `auctionport`, `openbare-verkopen`, `bopa`, `hammertime`, `veilbalie`, `komerco`, `lussis`, `bell-auction`, `industrial-auctions`, `appelboom`) · legacy bucket aliases: `2dehands`/`trader` → all tweedehands, `veiling` → all auctions |\n| `listing_type` | string | no | `tweedehands` (all second-hand) · `veiling` (all auction lots, every auction house) — the binary UI filter |\n| `price_min` | number | no | minimum price in euro |\n| `price_max` | number | no | maximum price in euro |\n| `no_price` | bool | no | `0` hides listings without a price (default `1` shows them) |\n| `limit` | number | no | default 24; max 100 (`keyword`) or 50 (`neural`/`auto`) |\n| `offset` | number | no | skip N results (\"toon meer\" pagination) |\n| `postcode` | string | no | 4-digit Belgian postcode (\"2000\") — results filtered to `max_km` around it and annotated with `_distance_km` |\n| `lat` / `lng` | number | no | raw user coordinates (alternative to `postcode`) |\n| `max_km` | number | no | radius in km around the user location (omit = no limit). Listings without any locatable city/coords are excluded when a location filter is active |\n\n`hasMore` is exact (server gathers limit+1 survivors past availability /\ntitle-dedup filters) — page with `offset` while it is true.\n\nResponse:\n\n```json\n{\n  \"requestId\": \"…\",\n  \"resolvedSearchType\": \"auto\",\n  \"hasMore\": true,\n  \"results\": [\n    {\n      \"url\": \"https://www.2dehands.be/v/…\",\n      \"title\": \"…\",\n      \"description\": \"short snippet\",\n      \"price_value\": 60.0,\n      \"price_text\": \"60 EUR\",\n      \"location\": \"Borgerhout\",\n      \"source\": \"2dehands\",\n      \"thumbnail_url\": \"…\",\n      \"_score\": 0.83\n    }\n  ]\n}\n```\n\n`source` values in results: `2dehands` (private sellers on 2dehands.be),\n`trader` (professional occasion sellers on 2dehands.be), `troc` (Troc.com\nstore inventory), `marktplaats` (Belgian listings on Marktplaats.nl),\n`zoekertjes` (Zoekertjes.be free classifieds), and auction-house slugs for\nauction lots (`vavato`, `troostwijk`, `auctelia`, `belga-veilingen`,\n`vlavem`, `auctionport`, `openbare-verkopen`, `bopa`, `hammertime`,\n`veilbalie`, `komerco`, `lussis`, `bell-auction`, `industrial-auctions`,\n`appelboom`; `alleveilingen` when the house is unknown), and car-dealer\ndomains for Belgian cars (`autoscout24.be`, `gocar.be`, `mazdastock.be`,\n`vroom.be`, `autohero.com`, `irisautocenter.be`, `autocadre.com`). Every result also\ncarries `listing_type`: `veiling` for auction lots, `tweedehands` for\neverything else. Auction lots have no fixed price.\n\nEach result also carries `_price_kind` (`fixed`, `bid`, `auction`,\n`free`, `none`) and `category_slug`: the site's fine-grained\n`category`/`subcategory` names mapped onto one of 27 canonical Dutch\nfacets (`fietsen`, `autos`, …, `overig` when unmappable) — use the facet\nfor grouping/filtering, the originals for detail. Chat answers show it as\n`Categorie: <original> [<facet>]`. When a location filter was given — `_distance_km`\n(+ `_distance_approx` when derived from a city centroid). The envelope\nechoes `userLocation` (`label`, `lat`, `lng`, `maxKm`, `approx`) and\n`distance` (`maxKm`, `hidden`: rows dropped for lack of location).\n\n## GET /v1/similar\n\n| param | type | required | description |\n|---|---|---|---|\n| `url` | string | yes | URL of a listing in the index (2dehands, troc, marktplaats, zoekertjes, kringwinkel, veiling urls work) |\n| `limit` | number | no | 1–24, default 12 |\n\nSame response shape as search.\n\nIf the seed URL is gone (sold/delisted), `similar` falls back to live\nlookalikes derived from the URL slug instead of a bare 404: the response\ncarries `\"seed_gone\": true` alongside `results`. Only a hintless/empty\nfallback still 404s (`{\"error\": \"listing not found\"}`).\n\n## GET /v1/contents\n\n| param | type | required | description |\n|---|---|---|---|\n| `urls` | string | yes | comma-separated listing URLs, max 20 |\n| `similar` | int | no | attach N similar listings per result (max 12, default 0) |\n\nFull listing details (description, attributes, seller, images) for the\ngiven URLs — use to deepen search results before reporting.\n\n## POST /v1/agent\n\nThe website agent as an API (streaming Server-Sent Events — read until\nconnection close). JSON body:\n\n| param | type | required | description |\n|---|---|---|---|\n| `message` | string | yes | the question in natural language |\n| `conversation` | array | no | earlier [{role, content}] messages for follow-ups |\n| `source` | string | no | source filter, same values as search |\n\nLimits: 10/min + 100/day per key. Use for multi-step tasks (it runs its\nown searches); use `/v1/search` + `/v1/contents` for single questions.\n\n## GET /v1/stats\n\nNo parameters. Returns `{\"total\": N, \"2dehands\": N, \"veiling\": N,\n\"trader\": N, \"troc\": N, \"marktplaats\": N, \"zoekertjes\": N, \"kringwinkel\": N}` — per-source listing counts.\n\n## Saved listings (login-gated)\n\n- `GET /v1/saved` → `{\"saved\": [{url, title, price_value, price_text,\n  thumbnail_url, source, location, saved_at}]}` newest first.\n- `POST /v1/saved` with `{\"url\": ...}` plus the snapshot fields above\n  (idempotent upsert — re-saving refreshes the snapshot).\n- `POST /v1/saved/remove` with `{\"url\": ...}`.\n\n## Own listings (login-gated, own ads only)\n\nUsers can publish their own ads (link import or from scratch); rows\ncarry `source: \"user\"`, live at `https://koopje.ai/<category>/<slug>-<id>`, expire\nafter 30 days (renewable). They appear in search like any row.\n\n- `POST /v1/listings/fetch-url` with `{\"url\": ...}` (known ad platform)\n  → `{title, description, price_value?, images?}` prefill, writes nothing.\n- `POST /v1/listings` with `{title, location, own: true}` plus\n  `description, price_value, price_text, category, source_url,\n  origin (\"manual\"|\"link\"), images[]` (base64 data URLs, max 5, 5MB each)\n  → `{ok, id, url, expires_at}`. `own: true` (ownership declaration)\n  is required. Max 10 active listings per account.\n- `GET /v1/listings/mine` → `{\"listings\": [...]}` newest first.\n- `POST /v1/listings/remove` / `POST /v1/listings/renew` with `{\"id\": ...}`.\n- `POST /v1/listings/draft` with `{url, own: true}` reads an ad link\n  into an unindexed, non-public draft → `{ok, id, draft: true, ...}`.\n- `POST /v1/listings/publish` with `{id}` plus optional field\n  overrides (title, description, price_value, price_text, location,\n  category, images[]) validates, indexes and publishes at\n  `https://koopje.ai/<category>/<slug>-<id>`, 30 days. (`/l/<id>` redirects there.)\n\n## Getting a key\n\nLog in at koopje.ai → menu (top right) → *API keys* → create. Keys\nare `kk_` + 32 chars and shown exactly once. Store as `KOOPJE_API_KEY`.\n\nFile v1.0.12:skill-card.md\n\n## Description:\n\nSearch koopje.ai for Belgian second-hand deals and auctions.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[antarcticaice](https://clawhub.ai/user/antarcticaice)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nExternal users and shopping agents use this skill to find, compare, price, and inspect Belgian second-hand marketplace listings and auction lots through the koopje.ai API.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The search-focused skill documents endpoints that can save items and create, publish, remove, or renew public listings.\n\nMitigation: Require clear, case-by-case user approval before using saved-listing or own-listing mutation endpoints; prefer read-only search, similar, contents, and stats endpoints unless the user explicitly requests account changes.\n\nRisk: The skill requires a koopje.ai API key.\n\nMitigation: Install only if the user trusts koopje.ai with the key; store KOOPJE_API_KEY as a secret and do not reveal it in commands or responses.\n\n## Reference(s):\n\n- [koopje.ai API reference](references/api.md)\n- [koopje.ai API](https://koopje.ai)\n- [koopje.ai agent-readable docs](https://koopje.ai/llms.txt)\n- [Koopje Search on ClawHub](https://clawhub.ai/antarcticaice/skills/koopje-search)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Markdown, Shell commands, Configuration, Guidance]\n\n**Output Format:** [Markdown with API request examples and listing summaries]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Requires KOOPJE_API_KEY for authenticated koopje.ai API calls.]\n\n## Skill Version(s):\n\n1.0.12 (source: server release evidence and skill frontmatter)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.0.11: 4 files, 8485 bytes\n\nFiles: references/api.md (8256b), skill-card.md (2412b), SKILL.md (7198b), _meta.json (133b)\n\nFile v1.0.11:SKILL.md\n\n---\nname: koopje-search\ndescription: Search koopje.ai for Belgian second-hand deals and auctions.\nversion: 1.0.11\nauthor: Lukas, koopje.ai\nlicense: MIT\nmetadata:\n  openclaw:\n    requires:\n      env:\n        - KOOPJE_API_KEY\n  hermes:\n    tags: [koopje, search, second-hand, belgium, api]\n---\n\n# koopje.ai search API\n\nSearch ~155k Belgian second-hand listings and live auctions via the\nkoopje.ai REST API. The index aggregates 2dehands.be, auction houses,\nTroc.com, Marktplaats, Zoekertjes.be and Belgian car dealers, plus user ads:\n\n| source | what it is |\n|---|---|\n| `2dehands` | private sellers on 2dehands.be (Belgium's largest marketplace) |\n| `trader` | professional occasion sellers on 2dehands.be |\n| `troc` | Troc.com second-hand store inventory (Belgian stores) |\n| `marktplaats` | Belgian listings on Marktplaats.nl |\n| `zoekertjes` | free classifieds on Zoekertjes.be |\n| `kringwinkel` | Kringwinkel.be thrift webshop (fixed price) + veilingsite (auction lots); one source, `listing_type` splits them |\n| `user` | user-submitted own ads (live at `https://koopje.ai/<category>/<slug>-<id>`, 30-day expiry) |\n| car-dealer domains | Belgian cars carry their dealer/platform as source: `autoscout24.be`, `gocar.be`, `mazdastock.be`, `vroom.be`, `autohero.com`, `irisautocenter.be`, `autocadre.com` (resolved from listings, never the aggregator) |\n| auction-house slugs | auction lots carry their house as source: `alleveilingen`, `vavato`, `troostwijk`, `auctelia`, `belga-veilingen`, `vlavem`, `auctionport`, `openbare-verkopen`, `bopa`, `hammertime`, `veilbalie`, `komerco`, `lussis`, `bell-auction`, `industrial-auctions`, `appelboom` (house name also in `seller_name`) |\n\nEvery result also carries `listing_type`: `veiling` (any auction house) or\n`tweedehands` (everything else) — the binary filter, independent of source.\n\n## When to use\n\nTriggers: finding, comparing or pricing used items (\"tweedehands\",\n\"koopjes\", \"second-hand\"), auction lots (\"veiling\"), or Belgian\nmarketplace listings — e.g. \"find a used bike in Gent\", \"wat kost een\ntweedehands espresso-machine?\", \"similar to <listing url>\".\n\n## Prerequisites\n\n- `KOOPJE_API_KEY` env var, a `kk_...` key from koopje.ai (account →\n  \"API keys\"; shown once at creation).\n\n## How to call\n\nAll endpoints: `https://koopje.ai`, auth header on every request:\n`Authorization: Bearer $KOOPJE_API_KEY`. JSON responses, CORS enabled.\n\n### POST-free quickstart — GET /v1/search\n\n```\ncurl -s \"https://koopje.ai/v1/search?q=vintage+stoel&price_max=200&limit=5\" \\\n  -H \"Authorization: Bearer $KOOPJE_API_KEY\"\n```\n\nKey parameters (full list in `references/api.md`):\n\n| param | notes |\n|---|---|\n| `q` | required, natural language or keywords (Dutch works best) |\n| `source` | exact origin: `2dehands`, `troc`, `marktplaats`, `zoekertjes`, `kringwinkel`, a car-dealer domain (`autoscout24.be`, `gocar.be`, …), or an auction-house slug (`vavato`, `troostwijk`, …). Legacy aliases still work: `2dehands` → all tweedehands, `veiling` → all auctions. Default: all sources |\n| `listing_type` | `tweedehands` (all second-hand) or `veiling` (all auction lots) — binary filter, independent of source |\n| `type` | `auto` (default), `neural` (semantic), `keyword` |\n| `price_min` / `price_max` | euros |\n| `no_price` | `0` hides listings without a price |\n| `limit` | default 24; max 100 (`keyword`) or 50 (`neural`/`auto`) |\n\n### Other endpoints\n\n- `GET /v1/similar?url=<listing-url>&limit=12` — visually/semantically\n  similar listings; url must be a listing already in the index.\n- `GET /v1/answer?q=<question>&source=...` — Dutch natural-language answer\n  with citations to real listings (RAG over the index).\n- `POST /v1/agent` — the website agent as an API: JSON body\n  `{\"message\": \"...\", \"conversation\": [...], \"source\": \"...\"}`,\n  streams the answer as Server-Sent Events (multi-step: it runs its own\n  searches). Limits: 10/min + 100/day per key.\n- `GET /v1/contents?urls=<url1,url2,...>` — full details per listing URL\n  (max 20 urls). Use after search when the user wants depth.\n- `GET /v1/stats` — per-source listing counts; good connectivity check.\n- Saved listings (need the user's key; login-gated like everything else):\n  `GET /v1/saved` (newest first), `POST /v1/saved` with\n  `{\"url\": ..., \"title\": ..., \"price_value\": ..., \"price_text\": ...,\n  \"thumbnail_url\": ..., \"source\": ..., \"location\": ...}` (idempotent),\n  `POST /v1/saved/remove` with `{\"url\": ...}`.\n- Own listings (need the user's key): `POST /v1/listings` with\n  `{title, location, own: true}` plus `description, price_value,\n  category, source_url, images[]` (base64, max 5) → `{id, url}`;\n  `POST /v1/listings/fetch-url` to prefill from an ad link;\n  `POST /v1/listings/draft` with `{url, own: true}` for an unindexed\n  draft → `POST /v1/listings/publish` with `{id, ...overrides}`;\n  `GET /v1/listings/mine`, `POST /v1/listings/remove|renew`.\n  Full fields in `references/api.md`.\n\n## Reading results\n\n`results[]` items carry: `url`, `title`, `description` (short snippet),\n`price_value` + `price_text` (null when bidding/no price), `location`\n(city), `source` (actual origin: `2dehands`, `trader`, `troc`,\n`marktplaats`, `zoekertjes`, `user` (own ads at `koopje.ai/<category>/…`), a car-dealer domain (`autoscout24.be`,\n`gocar.be`, …), or an auction-house slug — `alleveilingen`,\n`vavato`, `troostwijk`, `auctelia`, `belga-veilingen`, `vlavem`, `auctionport`,\n`openbare-verkopen`, `bopa`, `hammertime`, `veilbalie`, `komerco`,\n`lussis`, `bell-auction`, `industrial-auctions`, `appelboom`), `listing_type`\n(`tweedehands` or `veiling`), `thumbnail_url`, `_score` (similarity).\n\nReport to the user in Dutch where possible; always include price,\nlocation and the actual source: name the site or auction house\nexplicitly (2dehands, Troc.com, Marktplaats.nl, or for auctions the\nauction house from `seller_name` — e.g. Vavato, Troostwijk,\nBelga-Veilingen); link the `url`. Auction items\n(`source: \"veiling\"`) have no fixed price — say so instead of quoting\n`price_text` as a sale price.\n\n## Pitfalls\n\n- `limit` caps at 100 (`keyword`) or 50 (`neural`/`auto`) — page with `offset` while `hasMore` is true.\n- `source` is binary (`2dehands` vs `veiling`); the fine-grained site is\n  only visible per-result in the `source` field of the response.\n- 401 → key missing/revoked; 429 → rate limited (search/similar/contents/stats:\n  60/min + 2,000/day per key; answer: 20/min + 200/day; agent: 10/min +\n  100/day), back off and retry once. Other failures (400/403/404/500) come\n  as `{\"error\": \"...\"}` — report the message, don't guess.\n- Agent docs: `GET https://koopje.ai/llms.txt` lists every agent-readable\n  page; `Accept: text/markdown` on `/`, `/docs`, `/api`, `/koppelen`\n  returns Markdown instead of HTML. n8n users: ready-made agent template\n  at https://koopje.ai/koppelen (n8n tab).\n- Empty `results` ≠ error: rephrase the query broader (Dutch nouns help)\n  before giving up.\n- Never invent listings; only report what the API returned.\n\n## Verification\n\n`GET /v1/stats` returns `{\"total\": ..., \"2dehands\": ..., \"veiling\": ...}`\n— if that fails, the key or connectivity is broken; tell the user instead\nof guessing.\n\nFile v1.0.11:_meta.json\n\n{\n  \"ownerId\": \"kn75qdj5yqrfxrwjd9tq8atz8n8dnsea\",\n  \"slug\": \"koopje-search\",\n  \"version\": \"1.0.11\",\n  \"publishedAt\": 1789587274922\n}\n\nFile v1.0.11:references/api.md\n\n# koopje.ai /v1 API reference\n\nBase: `https://koopje.ai` — all requests need `Authorization: Bearer kk_...`.\nAll responses JSON; `/v1/*` sends `Access-Control-Allow-Origin: *`.\n\nErrors: 401 missing/invalid key · 401 revoked key · 400 invalid params ·\n429 rate limited.\n\n## GET /v1/search\n\nSemantic + keyword search over the unified index.\n\n| param | type | required | description |\n|---|---|---|---|\n| `q` | string | yes | natural language or keywords (Dutch works best) |\n| `type` | string | no | `auto` (default) · `neural` · `keyword` |\n| `source` | string | no | exact origin: `2dehands` (2dehands.be platform incl. traders) · `troc` · `marktplaats` · `zoekertjes` · `kringwinkel` (thrift webshop + veilingsite, split by `listing_type`) · car-dealer domain (`autoscout24.be`, `gocar.be`, `mazdastock.be`, `vroom.be`, `autohero.com`, `irisautocenter.be`, `autocadre.com`) · auction house slug (`vavato`, `troostwijk`, `auctelia`, `belga-veilingen`, `vlavem`, `auctionport`, `openbare-verkopen`, `bopa`, `hammertime`, `veilbalie`, `komerco`, `lussis`, `bell-auction`, `industrial-auctions`, `appelboom`) · legacy bucket aliases: `2dehands`/`trader` → all tweedehands, `veiling` → all auctions |\n| `listing_type` | string | no | `tweedehands` (all second-hand) · `veiling` (all auction lots, every auction house) — the binary UI filter |\n| `price_min` | number | no | minimum price in euro |\n| `price_max` | number | no | maximum price in euro |\n| `no_price` | bool | no | `0` hides listings without a price (default `1` shows them) |\n| `limit` | number | no | default 24; max 100 (`keyword`) or 50 (`neural`/`auto`) |\n| `offset` | number | no | skip N results (\"toon meer\" pagination) |\n| `postcode` | string | no | 4-digit Belgian postcode (\"2000\") — results filtered to `max_km` around it and annotated with `_distance_km` |\n| `lat` / `lng` | number | no | raw user coordinates (alternative to `postcode`) |\n| `max_km` | number | no | radius in km around the user location (omit = no limit). Listings without any locatable city/coords are excluded when a location filter is active |\n\n`hasMore` is exact (server gathers limit+1 survivors past availability /\ntitle-dedup filters) — page with `offset` while it is true.\n\nResponse:\n\n```json\n{\n  \"requestId\": \"…\",\n  \"resolvedSearchType\": \"auto\",\n  \"hasMore\": true,\n  \"results\": [\n    {\n      \"url\": \"https://www.2dehands.be/v/…\",\n      \"title\": \"…\",\n      \"description\": \"short snippet\",\n      \"price_value\": 60.0,\n      \"price_text\": \"60 EUR\",\n      \"location\": \"Borgerhout\",\n      \"source\": \"2dehands\",\n      \"thumbnail_url\": \"…\",\n      \"_score\": 0.83\n    }\n  ]\n}\n```\n\n`source` values in results: `2dehands` (private sellers on 2dehands.be),\n`trader` (professional occasion sellers on 2dehands.be), `troc` (Troc.com\nstore inventory), `marktplaats` (Belgian listings on Marktplaats.nl),\n`zoekertjes` (Zoekertjes.be free classifieds), and auction-house slugs for\nauction lots (`vavato`, `troostwijk`, `auctelia`, `belga-veilingen`,\n`vlavem`, `auctionport`, `openbare-verkopen`, `bopa`, `hammertime`,\n`veilbalie`, `komerco`, `lussis`, `bell-auction`, `industrial-auctions`,\n`appelboom`; `alleveilingen` when the house is unknown), and car-dealer\ndomains for Belgian cars (`autoscout24.be`, `gocar.be`, `mazdastock.be`,\n`vroom.be`, `autohero.com`, `irisautocenter.be`, `autocadre.com`). Every result also\ncarries `listing_type`: `veiling` for auction lots, `tweedehands` for\neverything else. Auction lots have no fixed price.\n\nEach result also carries `_price_kind` (`fixed`, `bid`, `auction`,\n`free`, `none`) and `category_slug`: the site's fine-grained\n`category`/`subcategory` names mapped onto one of 27 canonical Dutch\nfacets (`fietsen`, `autos`, …, `overig` when unmappable) — use the facet\nfor grouping/filtering, the originals for detail. Chat answers show it as\n`Categorie: <original> [<facet>]`. When a location filter was given — `_distance_km`\n(+ `_distance_approx` when derived from a city centroid). The envelope\nechoes `userLocation` (`label`, `lat`, `lng`, `maxKm`, `approx`) and\n`distance` (`maxKm`, `hidden`: rows dropped for lack of location).\n\n## GET /v1/similar\n\n| param | type | required | description |\n|---|---|---|---|\n| `url` | string | yes | URL of a listing in the index (2dehands, troc, marktplaats, zoekertjes, kringwinkel, veiling urls work) |\n| `limit` | number | no | 1–24, default 12 |\n\nSame response shape as search.\n\nIf the seed URL is gone (sold/delisted), `similar` falls back to live\nlookalikes derived from the URL slug instead of a bare 404: the response\ncarries `\"seed_gone\": true` alongside `results`. Only a hintless/empty\nfallback still 404s (`{\"error\": \"listing not found\"}`).\n\n## GET /v1/answer\n\nRAG answer (Dutch) over the index with citations.\n\n| param | type | required | description |\n|---|---|---|---|\n| `q` | string | yes | the question in natural language |\n| `source` | string | no | source filter, same values as search |\n| `postcode` | string | no | 4-digit Belgian postcode — only nearby listings are used |\n| `lat` / `lng` | number | no | raw coordinates (alternative to `postcode`) |\n| `max_km` | number | no | radius in km (only with `postcode` or `lat`/`lng`) |\n\nResponse includes the answer text plus `citations` linking to the\nunderlying listings (citations carry `_distance_km` when a location\nfilter is active).\n\n## GET /v1/contents\n\n| param | type | required | description |\n|---|---|---|---|\n| `urls` | string | yes | comma-separated listing URLs, max 20 |\n| `similar` | int | no | attach N similar listings per result (max 12, default 0) |\n\nFull listing details (description, attributes, seller, images) for the\ngiven URLs — use to deepen search results before reporting.\n\n## POST /v1/agent\n\nThe website agent as an API (streaming Server-Sent Events — read until\nconnection close). JSON body:\n\n| param | type | required | description |\n|---|---|---|---|\n| `message` | string | yes | the question in natural language |\n| `conversation` | array | no | earlier [{role, content}] messages for follow-ups |\n| `source` | string | no | source filter, same values as search |\n\nLimits: 10/min + 100/day per key. Use for multi-step tasks (it runs its\nown searches); use `/v1/answer` for single questions.\n\n## GET /v1/stats\n\nNo parameters. Returns `{\"total\": N, \"2dehands\": N, \"veiling\": N,\n\"trader\": N, \"troc\": N, \"marktplaats\": N, \"zoekertjes\": N, \"kringwinkel\": N}` — per-source listing counts.\n\n## Saved listings (login-gated)\n\n- `GET /v1/saved` → `{\"saved\": [{url, title, price_value, price_text,\n  thumbnail_url, source, location, saved_at}]}` newest first.\n- `POST /v1/saved` with `{\"url\": ...}` plus the snapshot fields above\n  (idempotent upsert — re-saving refreshes the snapshot).\n- `POST /v1/saved/remove` with `{\"url\": ...}`.\n\n## Own listings (login-gated, own ads only)\n\nUsers can publish their own ads (link import or from scratch); rows\ncarry `source: \"user\"`, live at `https://koopje.ai/<category>/<slug>-<id>`, expire\nafter 30 days (renewable). They appear in search/answer like any row.\n\n- `POST /v1/listings/fetch-url` with `{\"url\": ...}` (known ad platform)\n  → `{title, description, price_value?, images?}` prefill, writes nothing.\n- `POST /v1/listings` with `{title, location, own: true}` plus\n  `description, price_value, price_text, category, source_url,\n  origin (\"manual\"|\"link\"), images[]` (base64 data URLs, max 5, 5MB each)\n  → `{ok, id, url, expires_at}`. `own: true` (ownership declaration)\n  is required. Max 10 active listings per account.\n- `GET /v1/listings/mine` → `{\"listings\": [...]}` newest first.\n- `POST /v1/listings/remove` / `POST /v1/listings/renew` with `{\"id\": ...}`.\n- `POST /v1/listings/draft` with `{url, own: true}` reads an ad link\n  into an unindexed, non-public draft → `{ok, id, draft: true, ...}`.\n- `POST /v1/listings/publish` with `{id}` plus optional field\n  overrides (title, description, price_value, price_text, location,\n  category, images[]) validates, indexes and publishes at\n  `https://koopje.ai/<category>/<slug>-<id>`, 30 days. (`/l/<id>` redirects there.)\n\n## Getting a key\n\nLog in at koopje.ai → menu (top right) → *API keys* → create. Keys\nare `kk_` + 32 chars and shown exactly once. Store as `KOOPJE_API_KEY`.\n\nFile v1.0.11:skill-card.md\n\n## Description:\n\nSearch koopje.ai for Belgian second-hand deals and auctions.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[antarcticaice](https://clawhub.ai/user/antarcticaice)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nExternal users, developers, and agents use this skill to search and compare Belgian second-hand listings, auctions, and similar items through koopje.ai, then report prices, locations, sources, and links.\n\n### Deployment Geography for Use:\n\nGlobal; search results focus on Belgian marketplaces and auction sources.\n\n## Known Risks and Mitigations:\n\nRisk: The skill requires a koopje.ai API key and sends search terms, listing URLs, and optional location filters to koopje.ai.\n\nMitigation: Use the skill only when that data sharing is acceptable, keep the API key secret, and avoid sending sensitive search or location details.\n\nRisk: Saved-listing and own-listing endpoints can change account state by saving, publishing, renewing, or removing listings.\n\nMitigation: Require explicit user confirmation before account-changing actions, especially before publishing or deleting a listing.\n\nRisk: Search and answer results may be incomplete, rate limited, or empty, and the skill must not invent listings.\n\nMitigation: Report only listings returned by the API, include source and URL details, and broaden or retry searches only within documented limits.\n\n## Reference(s):\n\n- [koopje.ai /v1 API reference](references/api.md)\n- [koopje.ai API](https://koopje.ai/api)\n- [koopje.ai agent-readable docs index](https://koopje.ai/llms.txt)\n- [ClawHub skill release](https://clawhub.ai/antarcticaice/skills/koopje-search)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Markdown, Shell commands, API calls, Guidance]\n\n**Output Format:** [Markdown summaries with listing links and optional shell command examples; API responses are JSON.]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Requires KOOPJE_API_KEY. Search terms, listing URLs, and optional location filters are sent to koopje.ai.]\n\n## Skill Version(s):\n\n1.0.11 (source: server release metadata and SKILL.md frontmatter)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.0.10: 4 files, 8359 bytes\n\nFiles: references/api.md (8152b), skill-card.md (2390b), SKILL.md (7050b), _meta.json (133b)\n\nFile v1.0.10:SKILL.md\n\n---\nname: koopje-search\ndescription: Search koopje.ai for Belgian second-hand deals and auctions.\nversion: 1.0.10\nauthor: Lukas, koopje.ai\nlicense: MIT\nmetadata:\n  openclaw:\n    requires:\n      env:\n        - KOOPJE_API_KEY\n  hermes:\n    tags: [koopje, search, second-hand, belgium, api]\n---\n\n# koopje.ai search API\n\nSearch ~155k Belgian second-hand listings and live auctions via the\nkoopje.ai REST API. The index aggregates 2dehands.be, auction houses,\nTroc.com, Marktplaats, Zoekertjes.be and Belgian car dealers, plus user ads:\n\n| source | what it is |\n|---|---|\n| `2dehands` | private sellers on 2dehands.be (Belgium's largest marketplace) |\n| `trader` | professional occasion sellers on 2dehands.be |\n| `troc` | Troc.com second-hand store inventory (Belgian stores) |\n| `marktplaats` | Belgian listings on Marktplaats.nl |\n| `zoekertjes` | free classifieds on Zoekertjes.be |\n| `user` | user-submitted own ads (live at `https://koopje.ai/<category>/<slug>-<id>`, 30-day expiry) |\n| car-dealer domains | Belgian cars carry their dealer/platform as source: `autoscout24.be`, `gocar.be`, `mazdastock.be`, `vroom.be`, `autohero.com`, `irisautocenter.be`, `autocadre.com` (resolved from listings, never the aggregator) |\n| auction-house slugs | auction lots carry their house as source: `alleveilingen`, `vavato`, `troostwijk`, `auctelia`, `belga-veilingen`, `vlavem`, `auctionport`, `openbare-verkopen`, `bopa`, `hammertime`, `veilbalie`, `komerco`, `lussis`, `bell-auction`, `industrial-auctions`, `appelboom` (house name also in `seller_name`) |\n\nEvery result also carries `listing_type`: `veiling` (any auction house) or\n`tweedehands` (everything else) — the binary filter, independent of source.\n\n## When to use\n\nTriggers: finding, comparing or pricing used items (\"tweedehands\",\n\"koopjes\", \"second-hand\"), auction lots (\"veiling\"), or Belgian\nmarketplace listings — e.g. \"find a used bike in Gent\", \"wat kost een\ntweedehands espresso-machine?\", \"similar to <listing url>\".\n\n## Prerequisites\n\n- `KOOPJE_API_KEY` env var, a `kk_...` key from koopje.ai (account →\n  \"API keys\"; shown once at creation).\n\n## How to call\n\nAll endpoints: `https://koopje.ai`, auth header on every request:\n`Authorization: Bearer $KOOPJE_API_KEY`. JSON responses, CORS enabled.\n\n### POST-free quickstart — GET /v1/search\n\n```\ncurl -s \"https://koopje.ai/v1/search?q=vintage+stoel&price_max=200&limit=5\" \\\n  -H \"Authorization: Bearer $KOOPJE_API_KEY\"\n```\n\nKey parameters (full list in `references/api.md`):\n\n| param | notes |\n|---|---|\n| `q` | required, natural language or keywords (Dutch works best) |\n| `source` | exact origin: `2dehands`, `troc`, `marktplaats`, `zoekertjes`, a car-dealer domain (`autoscout24.be`, `gocar.be`, …), or an auction-house slug (`vavato`, `troostwijk`, …). Legacy aliases still work: `2dehands` → all tweedehands, `veiling` → all auctions. Default: all sources |\n| `listing_type` | `tweedehands` (all second-hand) or `veiling` (all auction lots) — binary filter, independent of source |\n| `type` | `auto` (default), `neural` (semantic), `keyword` |\n| `price_min` / `price_max` | euros |\n| `no_price` | `0` hides listings without a price |\n| `limit` | default 24; max 100 (`keyword`) or 50 (`neural`/`auto`) |\n\n### Other endpoints\n\n- `GET /v1/similar?url=<listing-url>&limit=12` — visually/semantically\n  similar listings; url must be a listing already in the index.\n- `GET /v1/answer?q=<question>&source=...` — Dutch natural-language answer\n  with citations to real listings (RAG over the index).\n- `POST /v1/agent` — the website agent as an API: JSON body\n  `{\"message\": \"...\", \"conversation\": [...], \"source\": \"...\"}`,\n  streams the answer as Server-Sent Events (multi-step: it runs its own\n  searches). Limits: 10/min + 100/day per key.\n- `GET /v1/contents?urls=<url1,url2,...>` — full details per listing URL\n  (max 20 urls). Use after search when the user wants depth.\n- `GET /v1/stats` — per-source listing counts; good connectivity check.\n- Saved listings (need the user's key; login-gated like everything else):\n  `GET /v1/saved` (newest first), `POST /v1/saved` with\n  `{\"url\": ..., \"title\": ..., \"price_value\": ..., \"price_text\": ...,\n  \"thumbnail_url\": ..., \"source\": ..., \"location\": ...}` (idempotent),\n  `POST /v1/saved/remove` with `{\"url\": ...}`.\n- Own listings (need the user's key): `POST /v1/listings` with\n  `{title, location, own: true}` plus `description, price_value,\n  category, source_url, images[]` (base64, max 5) → `{id, url}`;\n  `POST /v1/listings/fetch-url` to prefill from an ad link;\n  `POST /v1/listings/draft` with `{url, own: true}` for an unindexed\n  draft → `POST /v1/listings/publish` with `{id, ...overrides}`;\n  `GET /v1/listings/mine`, `POST /v1/listings/remove|renew`.\n  Full fields in `references/api.md`.\n\n## Reading results\n\n`results[]` items carry: `url`, `title`, `description` (short snippet),\n`price_value` + `price_text` (null when bidding/no price), `location`\n(city), `source` (actual origin: `2dehands`, `trader`, `troc`,\n`marktplaats`, `zoekertjes`, `user` (own ads at `koopje.ai/<category>/…`), a car-dealer domain (`autoscout24.be`,\n`gocar.be`, …), or an auction-house slug — `alleveilingen`,\n`vavato`, `troostwijk`, `auctelia`, `belga-veilingen`, `vlavem`, `auctionport`,\n`openbare-verkopen`, `bopa`, `hammertime`, `veilbalie`, `komerco`,\n`lussis`, `bell-auction`, `industrial-auctions`, `appelboom`), `listing_type`\n(`tweedehands` or `veiling`), `thumbnail_url`, `_score` (similarity).\n\nReport to the user in Dutch where possible; always include price,\nlocation and the actual source: name the site or auction house\nexplicitly (2dehands, Troc.com, Marktplaats.nl, or for auctions the\nauction house from `seller_name` — e.g. Vavato, Troostwijk,\nBelga-Veilingen); link the `url`. Auction items\n(`source: \"veiling\"`) have no fixed price — say so instead of quoting\n`price_text` as a sale price.\n\n## Pitfalls\n\n- `limit` caps at 100 (`keyword`) or 50 (`neural`/`auto`) — page with `offset` while `hasMore` is true.\n- `source` is binary (`2dehands` vs `veiling`); the fine-grained site is\n  only visible per-result in the `source` field of the response.\n- 401 → key missing/revoked; 429 → rate limited (search/similar/contents/stats:\n  60/min + 2,000/day per key; answer: 20/min + 200/day; agent: 10/min +\n  100/day), back off and retry once. Other failures (400/403/404/500) come\n  as `{\"error\": \"...\"}` — report the message, don't guess.\n- Agent docs: `GET https://koopje.ai/llms.txt` lists every agent-readable\n  page; `Accept: text/markdown` on `/`, `/docs`, `/api`, `/koppelen`\n  returns Markdown instead of HTML. n8n users: ready-made agent template\n  at https://koopje.ai/koppelen (n8n tab).\n- Empty `results` ≠ error: rephrase the query broader (Dutch nouns help)\n  before giving up.\n- Never invent listings; only report what the API returned.\n\n## Verification\n\n`GET /v1/stats` returns `{\"total\": ..., \"2dehands\": ..., \"veiling\": ...}`\n— if that fails, the key or connectivity is broken; tell the user instead\nof guessing.\n\nFile v1.0.10:_meta.json\n\n{\n  \"ownerId\": \"kn75qdj5yqrfxrwjd9tq8atz8n8dnsea\",\n  \"slug\": \"koopje-search\",\n  \"version\": \"1.0.10\",\n  \"publishedAt\": 1789477378797\n}\n\nFile v1.0.10:references/api.md\n\n# koopje.ai /v1 API reference\n\nBase: `https://koopje.ai` — all requests need `Authorization: Bearer kk_...`.\nAll responses JSON; `/v1/*` sends `Access-Control-Allow-Origin: *`.\n\nErrors: 401 missing/invalid key · 401 revoked key · 400 invalid params ·\n429 rate limited.\n\n## GET /v1/search\n\nSemantic + keyword search over the unified index.\n\n| param | type | required | description |\n|---|---|---|---|\n| `q` | string | yes | natural language or keywords (Dutch works best) |\n| `type` | string | no | `auto` (default) · `neural` · `keyword` |\n| `source` | string | no | exact origin: `2dehands` (2dehands.be platform incl. traders) · `troc` · `marktplaats` · `zoekertjes` · car-dealer domain (`autoscout24.be`, `gocar.be`, `mazdastock.be`, `vroom.be`, `autohero.com`, `irisautocenter.be`, `autocadre.com`) · auction house slug (`vavato`, `troostwijk`, `auctelia`, `belga-veilingen`, `vlavem`, `auctionport`, `openbare-verkopen`, `bopa`, `hammertime`, `veilbalie`, `komerco`, `lussis`, `bell-auction`, `industrial-auctions`, `appelboom`) · legacy bucket aliases: `2dehands`/`trader` → all tweedehands, `veiling` → all auctions |\n| `listing_type` | string | no | `tweedehands` (all second-hand) · `veiling` (all auction lots, every auction house) — the binary UI filter |\n| `price_min` | number | no | minimum price in euro |\n| `price_max` | number | no | maximum price in euro |\n| `no_price` | bool | no | `0` hides listings without a price (default `1` shows them) |\n| `limit` | number | no | default 24; max 100 (`keyword`) or 50 (`neural`/`auto`) |\n| `offset` | number | no | skip N results (\"toon meer\" pagination) |\n| `postcode` | string | no | 4-digit Belgian postcode (\"2000\") — results filtered to `max_km` around it and annotated with `_distance_km` |\n| `lat` / `lng` | number | no | raw user coordinates (alternative to `postcode`) |\n| `max_km` | number | no | radius in km around the user location (omit = no limit). Listings without any locatable city/coords are excluded when a location filter is active |\n\n`hasMore` is exact (server gathers limit+1 survivors past availability /\ntitle-dedup filters) — page with `offset` while it is true.\n\nResponse:\n\n```json\n{\n  \"requestId\": \"…\",\n  \"resolvedSearchType\": \"auto\",\n  \"hasMore\": true,\n  \"results\": [\n    {\n      \"url\": \"https://www.2dehands.be/v/…\",\n      \"title\": \"…\",\n      \"description\": \"short snippet\",\n      \"price_value\": 60.0,\n      \"price_text\": \"60 EUR\",\n      \"location\": \"Borgerhout\",\n      \"source\": \"2dehands\",\n      \"thumbnail_url\": \"…\",\n      \"_score\": 0.83\n    }\n  ]\n}\n```\n\n`source` values in results: `2dehands` (private sellers on 2dehands.be),\n`trader` (professional occasion sellers on 2dehands.be), `troc` (Troc.com\nstore inventory), `marktplaats` (Belgian listings on Marktplaats.nl),\n`zoekertjes` (Zoekertjes.be free classifieds), and auction-house slugs for\nauction lots (`vavato`, `troostwijk`, `auctelia`, `belga-veilingen`,\n`vlavem`, `auctionport`, `openbare-verkopen`, `bopa`, `hammertime`,\n`veilbalie`, `komerco`, `lussis`, `bell-auction`, `industrial-auctions`,\n`appelboom`; `alleveilingen` when the house is unknown), and car-dealer\ndomains for Belgian cars (`autoscout24.be`, `gocar.be`, `mazdastock.be`,\n`vroom.be`, `autohero.com`, `irisautocenter.be`, `autocadre.com`). Every result also\ncarries `listing_type`: `veiling` for auction lots, `tweedehands` for\neverything else. Auction lots have no fixed price.\n\nEach result also carries `_price_kind` (`fixed`, `bid`, `auction`,\n`free`, `none`) and `category_slug`: the site's fine-grained\n`category`/`subcategory` names mapped onto one of 27 canonical Dutch\nfacets (`fietsen`, `autos`, …, `overig` when unmappable) — use the facet\nfor grouping/filtering, the originals for detail. Chat answers show it as\n`Categorie: <original> [<facet>]`. When a location filter was given — `_distance_km`\n(+ `_distance_approx` when derived from a city centroid). The envelope\nechoes `userLocation` (`label`, `lat`, `lng`, `maxKm`, `approx`) and\n`distance` (`maxKm`, `hidden`: rows dropped for lack of location).\n\n## GET /v1/similar\n\n| param | type | required | description |\n|---|---|---|---|\n| `url` | string | yes | URL of a listing in the index (2dehands, troc, marktplaats, zoekertjes, veiling urls work) |\n| `limit` | number | no | 1–24, default 12 |\n\nSame response shape as search.\n\nIf the seed URL is gone (sold/delisted), `similar` falls back to live\nlookalikes derived from the URL slug instead of a bare 404: the response\ncarries `\"seed_gone\": true` alongside `results`. Only a hintless/empty\nfallback still 404s (`{\"error\": \"listing not found\"}`).\n\n## GET /v1/answer\n\nRAG answer (Dutch) over the index with citations.\n\n| param | type | required | description |\n|---|---|---|---|\n| `q` | string | yes | the question in natural language |\n| `source` | string | no | source filter, same values as search |\n| `postcode` | string | no | 4-digit Belgian postcode — only nearby listings are used |\n| `lat` / `lng` | number | no | raw coordinates (alternative to `postcode`) |\n| `max_km` | number | no | radius in km (only with `postcode` or `lat`/`lng`) |\n\nResponse includes the answer text plus `citations` linking to the\nunderlying listings (citations carry `_distance_km` when a location\nfilter is active).\n\n## GET /v1/contents\n\n| param | type | required | description |\n|---|---|---|---|\n| `urls` | string | yes | comma-separated listing URLs, max 20 |\n| `similar` | int | no | attach N similar listings per result (max 12, default 0) |\n\nFull listing details (description, attributes, seller, images) for the\ngiven URLs — use to deepen search results before reporting.\n\n## POST /v1/agent\n\nThe website agent as an API (streaming Server-Sent Events — read until\nconnection close). JSON body:\n\n| param | type | required | description |\n|---|---|---|---|\n| `message` | string | yes | the question in natural language |\n| `conversation` | array | no | earlier [{role, content}] messages for follow-ups |\n| `source` | string | no | source filter, same values as search |\n\nLimits: 10/min + 100/day per key. Use for multi-step tasks (it runs its\nown searches); use `/v1/answer` for single questions.\n\n## GET /v1/stats\n\nNo parameters. Returns `{\"total\": N, \"2dehands\": N, \"veiling\": N,\n\"trader\": N, \"troc\": N, \"marktplaats\": N, \"zoekertjes\": N}` — per-source listing counts.\n\n## Saved listings (login-gated)\n\n- `GET /v1/saved` → `{\"saved\": [{url, title, price_value, price_text,\n  thumbnail_url, source, location, saved_at}]}` newest first.\n- `POST /v1/saved` with `{\"url\": ...}` plus the snapshot fields above\n  (idempotent upsert — re-saving refreshes the snapshot).\n- `POST /v1/saved/remove` with `{\"url\": ...}`.\n\n## Own listings (login-gated, own ads only)\n\nUsers can publish their own ads (link import or from scratch); rows\ncarry `source: \"user\"`, live at `https://koopje.ai/<category>/<slug>-<id>`, expire\nafter 30 days (renewable). They appear in search/answer like any row.\n\n- `POST /v1/listings/fetch-url` with `{\"url\": ...}` (known ad platform)\n  → `{title, description, price_value?, images?}` prefill, writes nothing.\n- `POST /v1/listings` with `{title, location, own: true}` plus\n  `description, price_value, price_text, category, source_url,\n  origin (\"manual\"|\"link\"), images[]` (base64 data URLs, max 5, 5MB each)\n  → `{ok, id, url, expires_at}`. `own: true` (ownership declaration)\n  is required. Max 10 active listings per account.\n- `GET /v1/listings/mine` → `{\"listings\": [...]}` newest first.\n- `POST /v1/listings/remove` / `POST /v1/listings/renew` with `{\"id\": ...}`.\n- `POST /v1/listings/draft` with `{url, own: true}` reads an ad link\n  into an unindexed, non-public draft → `{ok, id, draft: true, ...}`.\n- `POST /v1/listings/publish` with `{id}` plus optional field\n  overrides (title, description, price_value, price_text, location,\n  category, images[]) validates, indexes and publishes at\n  `https://koopje.ai/<category>/<slug>-<id>`, 30 days. (`/l/<id>` redirects there.)\n\n## Getting a key\n\nLog in at koopje.ai → menu (top right) → *API keys* → create. Keys\nare `kk_` + 32 chars and shown exactly once. Store as `KOOPJE_API_KEY`.\n\nFile v1.0.10:skill-card.md\n\n## Description:\n\nSearch koopje.ai for Belgian second-hand deals and auctions.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[antarcticaice](https://clawhub.ai/user/antarcticaice)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nExternal users and agents use this skill to search, compare, price, and cite Belgian second-hand marketplace listings and auction lots through the koopje.ai API.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill uses a koopje.ai API key and includes account-changing saved-listing and own-listing actions.\n\nMitigation: Install only if API-key access is acceptable, load KOOPJE_API_KEY from the environment, and require explicit confirmation before creating, publishing, saving, removing, or renewing listings.\n\nRisk: Location-filtered searches can send precise coordinates to the API.\n\nMitigation: Prefer postcode or broader location filters, and send precise latitude and longitude only when necessary for the user's request.\n\nRisk: The security review flags the release as suspicious because account-changing actions appear under a search-oriented purpose without clear confirmation guardrails.\n\nMitigation: Treat search and answer operations as normal use, but gate all saved-listing and own-listing write operations behind user confirmation.\n\n## Reference(s):\n\n- [koopje.ai API reference](references/api.md)\n- [koopje.ai](https://koopje.ai)\n- [koopje.ai agent-readable index](https://koopje.ai/llms.txt)\n- [koopje.ai connection guide](https://koopje.ai/koppelen)\n- [ClawHub skill page](https://clawhub.ai/antarcticaice/skills/koopje-search)\n\n## Skill Output:\n\n**Output Type(s):** [Guidance, Shell commands, API Calls, Markdown, Configuration]\n\n**Output Format:** [Markdown guidance with inline shell commands and JSON API examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Requires KOOPJE_API_KEY for authenticated koopje.ai API calls; search output should include listing prices, locations, sources, and URLs.]\n\n## Skill Version(s):\n\n1.0.10 (source: frontmatter and server release evidence)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.0.9: 4 files, 8309 bytes\n\nFiles: references/api.md (8115b), skill-card.md (2293b), SKILL.md (6982b), _meta.json (132b)\n\nFile v1.0.9:SKILL.md\n\n---\nname: koopje-search\ndescription: Search koopje.ai for Belgian second-hand deals and auctions.\nversion: 1.0.9\nauthor: Lukas, koopje.ai\nlicense: MIT\nmetadata:\n  openclaw:\n    requires:\n      env:\n        - KOOPJE_API_KEY\n  hermes:\n    tags: [koopje, search, second-hand, belgium, api]\n---\n\n# koopje.ai search API\n\nSearch ~155k Belgian second-hand listings and live auctions via the\nkoopje.ai REST API. The index aggregates 2dehands.be, auction houses,\nTroc.com, Marktplaats, Zoekertjes.be and Belgian car dealers, plus user ads:\n\n| source | what it is |\n|---|---|\n| `2dehands` | private sellers on 2dehands.be (Belgium's largest marketplace) |\n| `trader` | professional occasion sellers on 2dehands.be |\n| `troc` | Troc.com second-hand store inventory (Belgian stores) |\n| `marktplaats` | Belgian listings on Marktplaats.nl |\n| `zoekertjes` | free classifieds on Zoekertjes.be |\n| `user` | user-submitted own ads (live at `https://koopje.ai/<category>/<slug>-<id>`, 30-day expiry) |\n| car-dealer domains | Belgian cars carry their dealer/platform as source: `autoscout24.be`, `gocar.be`, `mazdastock.be`, `vroom.be`, `autohero.com`, `irisautocenter.be`, `autocadre.com` (resolved from listings, never the aggregator) |\n| auction-house \n\nArchive v1.0.8: 4 files, 8139 bytes\n\nFiles: references/api.md (7844b), skill-card.md (2230b), SKILL.md (6982b), _meta.json (132b)","readmeExcerpt":"Skill: koopje-search Owner: antarcticaice Summary: Search koopje.ai for Belgian second-hand deals and auctions. Tags: latest:1.0.17 Version history: v1.0.17 | 2026-10-07T07:18:27.600Z | auto - Added \"auctim\" to the list of supported auction-house sources. - Minor documentation updates to reflect the expanded source coverage. - Removed the obsolete skill-card.md file. v1.0.16 | 2026-10-02T14:36:56.562Z | auto - Added ","codeSnippets":[],"executableExamples":[{"language":"text","snippet":"curl -s \"https://koopje.ai/v1/search?q=vintage+stoel&price_max=200&limit=5\" \\\n  -H \"Authorization: Bearer $KOOPJE_API_KEY\""},{"language":"json","snippet":"{\n  \"requestId\": \"…\",\n  \"resolvedSearchType\": \"auto\",\n  \"hasMore\": true,\n  \"results\": [\n    {\n      \"url\": \"https://www.2dehands.be/v/…\",\n      \"title\": \"…\",\n      \"description\": \"short snippet\",\n      \"price_value\": 60.0,\n      \"price_text\": \"60 EUR\",\n      \"location\": \"Borgerhout\",\n      \"source\": \"2dehands\",\n      \"thumbnail_url\": \"…\",\n      \"_score\": 0.83\n    }\n  ]\n}"},{"language":"text","snippet":"curl -s \"https://koopje.ai/v1/search?q=vintage+stoel&price_max=200&limit=5\" \\\n  -H \"Authorization: Bearer $KOOPJE_API_KEY\""},{"language":"json","snippet":"{\n  \"requestId\": \"…\",\n  \"resolvedSearchType\": \"auto\",\n  \"hasMore\": true,\n  \"results\": [\n    {\n      \"url\": \"https://www.2dehands.be/v/…\",\n      \"title\": \"…\",\n      \"description\": \"short snippet\",\n      \"price_value\": 60.0,\n      \"price_text\": \"60 EUR\",\n      \"location\": \"Borgerhout\",\n      \"source\": \"2dehands\",\n      \"thumbnail_url\": \"…\",\n      \"_score\": 0.83\n    }\n  ]\n}"},{"language":"text","snippet":"curl -s \"https://koopje.ai/v1/search?q=vintage+stoel&price_max=200&limit=5\" \\\n  -H \"Authorization: Bearer $KOOPJE_API_KEY\""},{"language":"json","snippet":"{\n  \"requestId\": \"…\",\n  \"resolvedSearchType\": \"auto\",\n  \"hasMore\": true,\n  \"results\": [\n    {\n      \"url\": \"https://www.2dehands.be/v/…\",\n      \"title\": \"…\",\n      \"description\": \"short snippet\",\n      \"price_value\": 60.0,\n      \"price_text\": \"60 EUR\",\n      \"location\": \"Borgerhout\",\n      \"source\": \"2dehands\",\n      \"thumbnail_url\": \"…\",\n      \"_score\": 0.83\n    }\n  ]\n}"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: koopje-search\ndescription: Search koopje.ai for Belgian second-hand deals and auctions.\nversion: 1.0.17\nauthor: Lukas, koopje.ai\nlicense: MIT\nmetadata:\n  openclaw:\n    requires:\n      env:\n        - KOOPJE_API_KEY\n  hermes:\n    tags: [koopje, search, second-hand, belgium, api]\n---\n\n# koopje.ai search API\n\nSearch ~155k Belgian second-hand listings and live auctions via the\nkoopje.ai REST API. The index aggregates 2dehands.be, auction houses,\nTroc.com, Think Twice, De Striep Promo, Marktplaats, Zoekertjes.be and Belgian car dealers, plus user ads:\n\n| source | what it is |\n|---|---|\n| `2dehands` | private sellers on 2dehands.be (Belgium's largest marketplace) |\n| `trader` | professional occasion sellers on 2dehands.be |\n| `troc` | Troc.com second-hand store inventory (Belgian stores) |\n| `thinktwice` | Think Twice vintage chain webshop Think2.eu (fixed price, kringloop) |\n| `strieppromo` | De Striep Promo Belgian strip shop, second-hand wall (fixed price, tweedehands) |\n| `marktplaats` | Belgian listings on Marktplaats.nl |\n| `zoekertjes` | free classifieds on Zoekertjes.be |\n| `kringwinkel` | Kringwinkel.be thrift webshop (fixed price) + veilingsite (auction lots); one source, `listing_type` splits them |\n| `user` | user-submitted own ads (live at `https://koopje.ai/<category>/<slug>-<id>`, 30-day expiry) |\n| car-dealer domains | Belgian cars carry their dealer/platform as source: `autoscout24.be`, `gocar.be`, `mazdastock.be`, `vroom.be`, `autohero.com`, `irisautocenter.be`, `autocadre.com` (resolved from listings, never the aggregator) |\n| auction-house slugs | auction lots carry their house as source: `alleveilingen`, `vavato`, `troostwijk`, `auctelia`, `belga-veilingen`, `vlavem`, `auctionport`, `openbare-verkopen`, `bopa`, `hammertime`, `veilbalie`, `komerco`, `lussis`, `bell-auction`, `industrial-auctions`, `appelboom`, `auctim` (house name also in `seller_name`) |\n\nEvery result also carries `listing_type`: `veiling` (any auction house),\n`kringloop` (Troc.com + Kringwinkel shop) or `tweedehands` (everything\nelse) — repeatable for multiselect, independent of source.\n\n## When to use\n\nTriggers: finding, comparing or pricing used items (\"tweedehands\",\n\"koopjes\", \"second-hand\"), auction lots (\"veiling\"), or Belgian\nmarketplace listings — e.g. \"find a used bike in Gent\", \"wat kost een\ntweedehands espresso-machine?\", \"similar to <listing url>\".\n\n## Prerequisites\n\n- `KOOPJE_API_KEY` env var, a `kk_...` key from koopje.ai (account →\n  \"API keys\"; shown once at creation).\n\n## How to call\n\nAll endpoints: `https://koopje.ai`, auth header on every request:\n`Authorization: Bearer $KOOPJE_API_KEY`. JSON responses, CORS enabled.\n\n### POST-free quickstart — GET /v1/search\n\n```\ncurl -s \"https://koopje.ai/v1/search?q=vintage+stoel&price_max=200&limit=5\" \\\n  -H \"Authorization: Bearer $KOOPJE_API_KEY\"\n```\n\nKey parameters (full list in `references/api.md`):\n\n| param | notes |\n|---|---|\n| `q` | required, natural language or keywords (Dutch works best) |\n| "},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn75qdj5yqrfxrwjd9tq8atz8n8dnsea\",\n  \"slug\": \"koopje-search\",\n  \"version\": \"1.0.17\",\n  \"publishedAt\": 1791357507600\n}"},{"path":"references/api.md","content":"# koopje.ai /v1 API reference\n\nBase: `https://koopje.ai` — all requests need `Authorization: Bearer kk_...`.\nAll responses JSON; `/v1/*` sends `Access-Control-Allow-Origin: *`.\n\nErrors: 401 missing/invalid key · 401 revoked key · 400 invalid params ·\n429 rate limited.\n\n## GET /v1/search\n\nSemantic + keyword search over the unified index.\n\n| param | type | required | description |\n|---|---|---|---|\n| `q` | string | yes | natural language or keywords (Dutch works best) |\n| `type` | string | no | `auto` (default) · `neural` · `keyword` |\n| `source` | string | no | exact origin: `2dehands` (2dehands.be platform incl. traders) · `troc` · `thinktwice` (Think Twice vintage) · `marktplaats` · `zoekertjes` · `kringwinkel` (thrift webshop + veilingsite, split by `listing_type`) · car-dealer domain (`autoscout24.be`, `gocar.be`, `mazdastock.be`, `vroom.be`, `autohero.com`, `irisautocenter.be`, `autocadre.com`) · auction house slug (`vavato`, `troostwijk`, `auctelia`, `belga-veilingen`, `vlavem`, `auctionport`, `openbare-verkopen`, `bopa`, `hammertime`, `veilbalie`, `komerco`, `lussis`, `bell-auction`, `industrial-auctions`, `appelboom`, `auctim`) · legacy bucket aliases: `2dehands`/`trader` → all tweedehands, `veiling` → all auctions |\n| `listing_type` | string | no | `tweedehands` (all second-hand) · `veiling` (all auction lots, every auction house) · `kringloop` (thrift stores) — repeatable for multiselect |\n| `price_min` | number | no | minimum price in euro |\n| `price_max` | number | no | maximum price in euro |\n| `no_price` | bool | no | `0` hides listings without a price (default `1` shows them) |\n| `limit` | number | no | default 24; max 100 (`keyword`) or 50 (`neural`/`auto`) |\n| `offset` | number | no | skip N results (\"toon meer\" pagination) |\n| `postcode` | string | no | 4-digit Belgian postcode (\"2000\") — results filtered to `max_km` around it and annotated with `_distance_km` |\n| `lat` / `lng` | number | no | raw user coordinates (alternative to `postcode`) |\n| `max_km` | number | no | radius in km around the user location (omit = no limit). Listings without any locatable city/coords are excluded when a location filter is active |\n\n`hasMore` is exact (server gathers limit+1 survivors past availability /\ntitle-dedup filters) — page with `offset` while it is true.\n\nResponse:\n\n```json\n{\n  \"requestId\": \"…\",\n  \"resolvedSearchType\": \"auto\",\n  \"hasMore\": true,\n  \"results\": [\n    {\n      \"url\": \"https://www.2dehands.be/v/…\",\n      \"title\": \"…\",\n      \"description\": \"short snippet\",\n      \"price_value\": 60.0,\n      \"price_text\": \"60 EUR\",\n      \"location\": \"Borgerhout\",\n      \"source\": \"2dehands\",\n      \"thumbnail_url\": \"…\",\n      \"_score\": 0.83\n    }\n  ]\n}\n```\n\n`source` values in results: `2dehands` (private sellers on 2dehands.be),\n`trader` (professional occasion sellers on 2dehands.be), `troc` (Troc.com\nstore inventory), `thinktwice` (Think Twice vintage webshop), `strieppromo` (De Striep Promo second-hand strips), `marktplaats` (Belgian listings on M"},{"path":"skill-card.md","content":"## Description:\n\nSearch koopje.ai for Belgian second-hand deals and auctions.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[antarcticaice](https://clawhub.ai/user/antarcticaice)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nShoppers and agents search and compare Belgian second-hand listings and auction lots, inspect listing details, and optionally manage saved or owned listings with the user's permission.\n\n### Deployment Geography for Use:\n\nGlobal (search coverage focuses on Belgian listings)\n\n## Known Risks and Mitigations:\n\nRisk: Searches and location details are sent to koopje.ai using the user's API key.\n\nMitigation: Use only when the user intends to share the search and any provided location details with koopje.ai.\n\nRisk: Saving, removing, renewing, or publishing listings can change the user's account or make an ad public.\n\nMitigation: Require an explicit request and final confirmation before each account-changing action, especially for public listings or precise coordinates.\n\n## Reference(s):\n\n- [ClawHub skill release](https://clawhub.ai/antarcticaice/skills/koopje-search)\n- [koopje.ai API documentation](https://koopje.ai/api)\n- [Included API reference](references/api.md)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Markdown, Shell commands]\n\n**Output Format:** [Markdown summaries with listing links and optional API examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Results include available prices, locations, and original listing sources.]\n\n## Skill Version(s):\n\n1.0.17 (source: server release metadata and frontmatter)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment."}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":"Search koopje.ai for Belgian second-hand deals and auctions. Skill: koopje-search Owner: antarcticaice Summary: Search koopje.ai for Belgian second-hand deals and auctions. Tags: latest:1.0.17 Version history: v1.0.17 | 2026-10-07T07:18:27.600Z | auto - Added \"auctim\" to the list of supported auction-house sources. - Minor documentation updates to reflect the expanded source coverage. - Removed the obsolete skill-card.md file. v1.0.16 | 2026-10-02T14:36:56.562Z | auto - Added","editorialQuality":{"score":100,"threshold":65,"status":"ready","wordCount":1657,"uniquenessScore":46,"reasons":[]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-11T10:44:37.914Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-11T10:44:37.914Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-11T14:16:19.017Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}