---
title: "Kleinanzeigen API: Search German Classifieds as JSON"
description: "Search Kleinanzeigen ads by query, city, category and price range with one GET call. Parameters, a real response and the cost: 1 credit per call."
url: https://perceptlayer.com/blog/kleinanzeigen-api-search-json
---

[Blog](https://perceptlayer.com/blog) / [API guides](https://perceptlayer.com/blog/category/api-guides)

# Kleinanzeigen API: Search German Classifieds as JSON

16 Oct 2026 Perceptlayer 7 min read

To get Kleinanzeigen listings as JSON, call `GET /v1/kleinanzeigen/search` with a `query` and, optionally, `location`, `category`, `price_min`, `price_max` and `page`. Each ad comes back with its id, title, price, location, image and a description excerpt. A successful call costs 1 credit, a failed call costs nothing, and a daily check of one search is 30 credits a month.

## Key takeaways

-   `GET /v1/kleinanzeigen/search` needs one parameter, `query`; `location`, `category`, `price_min`, `price_max` and `page` narrow it.
-   Each result has a numeric `price_numeric` next to the display string `price`, so you can compare prices without parsing "399 €".
-   `meta.has_next_page` tells you whether to request `page=2`; every page is a separate 1-credit call.
-   The Kleinanzeigen API has 3 endpoints (Search, Details, Shipping Options), each 1 credit.
-   A daily check of one search over 2 pages is 60 calls × 1 credit = 60 credits a month, well inside the 1,000 free credits.

## Which Kleinanzeigen endpoints can you call?

The [Kleinanzeigen API](https://perceptlayer.com/apis/kleinanzeigen) has three endpoints, all `GET`, all 1 credit per successful call. Search finds ads by keyword, Details returns one ad by its id, and Shipping Options takes no parameters at all. For monitoring, Search does nearly all the work, and you reach for Details only when a result is worth a closer look.

| Method | Path | Returns | Credits | Required | Optional |
| --- | --- | --- | --- | --- | --- |
| GET | `/v1/kleinanzeigen/search` | Search | 1 | `query` | `page`, `location`, `category`, `price_min`, `price_max` |
| GET | `/v1/kleinanzeigen/details` | Details | 1 | `ad_id` | none |
| GET | `/v1/kleinanzeigen/shipping-options` | Shipping Options | 1 | none | none |

The pages for [Search](https://perceptlayer.com/apis/kleinanzeigen/search), [Details](https://perceptlayer.com/apis/kleinanzeigen/details) and [Shipping Options](https://perceptlayer.com/apis/kleinanzeigen/shipping-options) each have a playground where you can run a real call with your key. Kleinanzeigen sits in the [Marketplaces](https://perceptlayer.com/verticals/marketplaces) area of the catalogue, alongside sources like [Vinted](https://perceptlayer.com/blog/vinted-api-search-items-json) and [Craigslist](https://perceptlayer.com/blog/craigslist-api-postings-json).

## How do you authenticate and make the first request?

Send your key in the `X-API-Key` header. Keys start with `sk_live_`, and you get one by [signing up](https://perceptlayer.com/signup) and verifying an email address. There's no credit card, and the free tier gives you 1,000 credits every month. Where a header isn't possible, the `api_key` query parameter works too. The [authentication docs](https://docs.perceptlayer.com/authentication) cover both.

Here is a search for iPhones in Berlin, in the category `elektronik`, priced between 50 and 500:

```bash
curl "https://api.perceptlayer.com/v1/kleinanzeigen/search?query=iphone&page=1&location=Berlin&category=elektronik&price_min=50&price_max=500" \
  -H "X-API-Key: $API_KEY"
```

Every successful response carries an `X-Credits-Used` header (1 here) and `X-Credits-Remaining`, the balance after the call. Check them once while testing so you know what a run costs before you schedule it.

## Which parameters does the search endpoint take?

Search takes one required parameter and five optional ones. `query` is a string of up to 500 characters. `location` and `category` are strings of up to 100 characters. `price_min`, `price_max` and `page` are integers. Nothing else about them is documented, so test unusual values in the playground before you build on them.

| Parameter | Type | Required | Notes |
| --- | --- | --- | --- |
| `query` | string | yes | Up to 500 characters |
| `page` | integer | no | Request `page=2` and onward while `has_next_page` is true |
| `location` | string | no | Up to 100 characters; `Berlin` in the example |
| `category` | string | no | Up to 100 characters; `elektronik` in the example |
| `price_min` | integer | no | Lower price bound |
| `price_max` | integer | no | Upper price bound |

Invalid input returns a 422 with the code `invalid_parameters` and costs nothing. See the [errors docs](https://docs.perceptlayer.com/errors) for the error codes.

## What does a search response look like?

A search returns `success`, a `data` array of ads and a `meta` object that echoes your filters and reports paging. This is a trimmed excerpt of a recorded response for the request above; the ad itself is cut to the fields you'd store.

```json
{
  "success": true,
  "data": [
    {
      "id": "3547273212",
      "title": "Apple iPhone 13 Pro Max 256GB Silber/Weiß Zustand Sehr gut OVP",
      "url": "https://www.kleinanzeigen.de/s-anzeige/apple-iphone-13-pro-max-256gb-silber-weiss-zustand-sehr-gut-ovp/3547273212-173-3473",
      "price": "399 €",
      "price_numeric": 399,
      "location": "13187 Pankow",
      "description": "Hallo zusammen, ich verkaufe mein iPhone 13 Pro Max mit 256 GB in der Farbe Silber/Weiß. Das..."
    },
    …
  ],
  "meta": {
    "query": "iphone",
    "page": 1,
    "location": "Berlin",
    "category": "elektronik",
    "results_count": 27,
    "has_next_page": true,
    "duration_ms": 1327.64
  }
}
```

Three fields matter for monitoring. `id` identifies the ad across runs. `price_numeric` is a number, so you can sort and compare. `has_next_page` says whether another page exists. Note that `id` is a string here, while `ad_id` on the Details endpoint is an integer, so convert it with `int()` before you pass it on.

The `title` and `description` fields come back in German, as the sellers wrote them. The description is an excerpt that ends in an ellipsis, not the full ad text.

## How do you monitor local prices with a script?

A price monitor needs three things: a fixed set of searches, a store of what you've already seen, and a rule for what counts as news. The script below runs one search, walks the pages, compares each ad with a local JSON file and prints new ads and price drops. It uses only the endpoint, parameters and fields shown above.

```python
import json
import os
import time
from pathlib import Path

import requests

BASE = "https://api.perceptlayer.com/v1/kleinanzeigen/search"
HEADERS = {"X-API-Key": os.environ["API_KEY"]}
STATE = Path("seen.json")
PARAMS = {
    "query": "iphone",
    "location": "Berlin",
    "category": "elektronik",
    "price_min": 50,
    "price_max": 500,
}
MAX_PAGES = 2

seen = json.loads(STATE.read_text()) if STATE.exists() else {}

page = 1
while page <= MAX_PAGES:
    resp = requests.get(BASE, headers=HEADERS, params={**PARAMS, "page": page}, timeout=30)
    if resp.status_code in (429, 503):
        time.sleep(int(resp.headers.get("Retry-After", "5")))
        continue
    resp.raise_for_status()
    body = resp.json()

    for ad in body["data"]:
        price = ad.get("price_numeric")
        if price is None:
            continue
        old = seen.get(ad["id"])
        if old is None:
            print(f"NEW   {price:>5} EUR  {ad['title']}  {ad['url']}")
        elif price < old["price"]:
            print(f"DROP  {old['price']} -> {price} EUR  {ad['title']}  {ad['url']}")
        seen[ad["id"]] = {"price": price, "title": ad["title"]}

    if not body["meta"]["has_next_page"]:
        break
    page += 1

STATE.write_text(json.dumps(seen, ensure_ascii=False))
```

Run it once to build the baseline; every NEW line on that first run is just the current inventory. After that, only changes print. Because `seen.json` keeps every ad it has met, an ad that disappears from the results simply stops updating. If you want a closer look at a stored ad, the Details endpoint takes its id as `ad_id`.

The script uses the [requests library](https://requests.readthedocs.io/) and waits and retries on 429 and 503 using the `Retry-After` header, and it raises on other errors. Requests have no idempotency key, so a call that timed out on your side may still have been billed. For proper retry rules see [handling web data API errors in Python](https://perceptlayer.com/blog/handle-web-data-api-errors-python).

### How do you run it every day?

Cron is enough. A line like `0 7 * * * cd /path/to/monitor && python monitor.py` runs the check at 07:00 daily. If you want queues or hosted workflows instead, [scheduling web data pulls](https://perceptlayer.com/blog/schedule-web-data-pulls-cron-queue) compares the options. To turn the printed lines into an agent that reasons about them, see [building a price tracking agent in Python](https://perceptlayer.com/blog/price-tracking-agent-python).

## What does a daily check cost?

Each page you fetch is one call, and each call is 1 credit, so cost is searches × pages × days. Failed calls return `X-Credits-Used: 0` and are never billed. The table works the arithmetic for a 30-day month; credits are the unit, and the [pricing page](https://perceptlayer.com/pricing) shows what credits cost.

| Setup | Calls a day | Calls × 1 credit, 30 days | Credits a month |
| --- | --- | --- | --- |
| 1 search, 1 page | 1 | 30 × 1 | 30 |
| 1 search, 2 pages | 2 | 60 × 1 | 60 |
| 5 searches, 2 pages each | 10 | 300 × 1 | 300 |
| 20 searches, 3 pages each | 60 | 1,800 × 1 | 1,800 |

The first three setups fit inside the 1,000 free credits a month. The fourth exceeds them by 800 credits, which the smallest prepaid pack, the 10,000-credit Starter, covers many times over. Purchased credits last 12 months, and there's no subscription. A Details call per new ad adds 1 credit each, so budget for it separately. The [credits docs](https://docs.perceptlayer.com/credits) explain how debits work.

Speed isn't a constraint at this scale. Free accounts get 1 request a second, and a daily job makes a handful of calls. If you ever fan out many searches at once, read the [rate limits](https://docs.perceptlayer.com/rate-limits) first.

## When is the official site a better fit?

If you only want to browse or watch a handful of searches yourself, the [Kleinanzeigen site](https://www.kleinanzeigen.de/) itself is the simpler tool, with no code to maintain. The API earns its place when you need the data in your own system: price history across weeks, joins with other sources, or an agent that acts on new ads.

Two limits are worth stating. Data is collected from publicly available sources and returned as found at the time of the call, so a listing can change or vanish between your check and a human's click. And Search gives you an excerpt of the description, not the full text. If you combine Kleinanzeigen with other marketplaces, [deduplicating listings across sources](https://perceptlayer.com/blog/deduplicate-listings-across-sources) covers matching ads that have no shared id.

Next step: [get a free API key](https://perceptlayer.com/signup), then paste the cURL call above into your terminal and read `X-Credits-Used` in the response headers. The [Kleinanzeigen Search page](https://perceptlayer.com/apis/kleinanzeigen/search) lets you try other filters in the playground first.

## APIs in this post

-   [Kleinanzeigen **1 credit per call** · 3 endpoints](https://perceptlayer.com/apis/kleinanzeigen)

## Frequently asked questions

### Is there an official Kleinanzeigen API?

Check Kleinanzeigen's own site for any official or partner interface; it isn't something we document here. The Perceptlayer Kleinanzeigen API is a separate route to the data and gives you three endpoints (Search, Details and Shipping Options) as JSON with one `X-API-Key` header. Each successful call costs 1 credit, and the free tier includes 1,000 credits every month with no credit card.

### How much does a Kleinanzeigen search cost?

One search call costs 1 credit, and each extra page is another call. Checking one search over 2 pages daily is 60 calls × 1 credit = 60 credits in a month. Failed calls cost nothing and return `X-Credits-Used: 0`. Credits are prepaid, and the [pricing page](https://perceptlayer.com/pricing) shows what a pack of credits costs.

### How do I get the next page of results?

Read `meta.has_next_page` in the response. When it is true, repeat the same request with `page` increased by one. Each page is its own 1-credit call, so cap the number of pages in your script to keep a daily run's cost fixed, as the example does with `MAX_PAGES`.

### What happens if a call fails or I hit the rate limit?

Errors return an HTTP status and a JSON body with `code`, `message` and `request_id`, and nothing is debited. A 429 `rate_limited` or 503 `temporarily_unavailable` response includes a `Retry-After` header with the seconds to wait. A 402 `insufficient_credits` means the prepaid balance is empty; there is no automatic top-up.

### Can an AI agent search Kleinanzeigen?

Yes. The MCP server at `https://api.perceptlayer.com/mcp` exposes `search_endpoints`, `get_endpoint` and `call_endpoint`. An agent can look up the Search endpoint for free, then call it with a `query`; only the call itself spends 1 credit on success. The [AI agents docs](https://docs.perceptlayer.com/ai-agents) show the setup.

kleinanzeigen classifieds germany price monitoring marketplaces

## More from the blog

1.  [API guides](https://perceptlayer.com/blog/category/api-guides) 3 Jul 2026 Updated 26 Oct 2026 Perceptlayer 8 min read
    
    ## [Craigslist API: Get Classified Postings as JSON](https://perceptlayer.com/blog/craigslist-api-postings-json)
    
    Search Craigslist postings by site, category and price as JSON, then poll for new ones. A real response, the parameters and the credit cost.
    
2.  [API guides](https://perceptlayer.com/blog/category/api-guides) 14 Oct 2026 Perceptlayer 6 min read
    
    ## [Vinted API: Search Second-Hand Items as JSON](https://perceptlayer.com/blog/vinted-api-search-items-json)
    
    Search Vinted as JSON with 14 optional parameters, then price-check one query across 19 countries. Each call costs 1 credit; failed calls cost nothing.
    
3.  [API guides](https://perceptlayer.com/blog/category/api-guides) 21 Aug 2026 Updated 26 Oct 2026 Perceptlayer 7 min read
    
    ## [Walmart Product Search API: Prices and Product Data](https://perceptlayer.com/blog/walmart-product-search-api)
    
    Search Walmart by keyword and get price, rating, seller and stock as JSON with GET /v1/walmart/search. Parameters, a real response and a credit count.
