Production technical guide

Market Intelligence API

A contract-first interface for aggregate Bulgarian property-market evidence: asking prices, supply, confidence and controlled historical delivery.

Production base URL
https://bulgarian-listings.152-53-109-83.sslip.io/api/v1
Version
v1
Format
JSON over HTTPS
Availability
Qualified enterprise customers

Live, licensed production interface

The three documented v1 endpoints are available at https://bulgarian-listings.152-53-109-83.sslip.io/api/v1 to qualified customers with an active licence and scoped organisation API key. The OpenAPI document is available at https://bulgarian-listings.152-53-109-83.sslip.io/api/v1/openapi.json.

What the API returns

The API is aggregate-first. Sale and rent are separate market populations in storage, calculations and responses. It returns market-level evidence with observation counts, confidence and time windows—not raw listing descriptions, images, contacts or exact addresses.

Price evidence

For sale: total asking price and EUR/m². For rent: monthly asking rent and EUR/m²/month. The two modes are never combined.

Supply evidence

Active supply, new observations and removals for eligible cities, neighbourhoods and property kinds.

Quality evidence

Priced observation counts, source diversity, maximum source share and medium or high confidence.

Historical delivery

Up to 366 daily aggregate snapshots per request for Data Delivery and Enterprise licences.

Authentication and key handling

The production design uses an organisation API key as a Bearer token. Once key management is provisioned, named administrators create and revoke keys inside the secure account area; the secret is displayed once and is never sent by email.

  • Keep keys in a server-side secret manager or environment variable.
  • Never place a production key in browser JavaScript, source control, logs, prompts or support messages.
  • Use separate keys per production system and revoke a key immediately when a system or administrator changes.
  • Send a unique X-Client-Request-Id so requests can be traced without exposing business data.
Authenticated request
curl --request GET \
  --url 'https://bulgarian-listings.152-53-109-83.sslip.io/api/v1/market/snapshot?area_id=bg-sofia-lozenets&market_mode=sale&property_kind=apartment&as_of=2026-07-18' \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <YOUR_API_KEY>' \
  --header 'X-Client-Request-Id: portfolio-review-2026-07-19'

Response contract

Every successful response separates licensed data from operational metadata. Snapshot and time-series requests require market_mode=sale or market_mode=rent. Preserve the mode and metadata when storing or presenting results.

FieldMeaning
dataThe requested aggregate market result.
data.market_modesale or rent. This dimension must be retained; results from different modes must not be merged.
meta.request_idTrace identifier to include in support requests.
meta.generated_atUTC time at which the response was generated.
meta.observation_windowDates of the observations supporting the result.
meta.weighted_data_unitsBillable units consumed by this response.

Production v1 endpoints

Availability depends on the licensed tier, quality-gated coverage and permitted use in the order form.

MethodPathReturnsStarting tier
GET/markets/coverageDiscover eligible area IDs and separate sale/rent coverage; optionally filter by market_mode.Insights
GET/market/snapshotReturn one aggregate snapshot for the required sale or rent market mode.Insights
GET/market/timeseriesReturn up to 366 daily points for one required market mode, area and property kind.Data Delivery

Sale snapshot example

Illustrative sale values only. They are not current market statistics and must not be used for a decision. For rent, price fields mean monthly asking rent and EUR/m²/month.

200 application/json
{
  "data": {
    "area_id": "bg-sofia-lozenets",
    "market_mode": "sale",
    "property_kind": "apartment",
    "as_of": "2026-07-18",
    "active_listings": 418,
    "new_listings": 19,
    "removed_listings": 14,
    "priced_listings": 391,
    "median_asking_price_eur": 286000,
    "median_asking_price_per_sqm_eur": 2840,
    "p25_asking_price_per_sqm_eur": 2370,
    "p75_asking_price_per_sqm_eur": 3310,
    "source_count": 3,
    "max_source_share": 0.42,
    "confidence": "high",
    "calculation_version": "market-api-daily-v2",
    "published_at": "2026-07-19T08:30:00Z"
  },
  "meta": {
    "request_id": "req_01JZ8W5Y6M9R7Q2F4A",
    "generated_at": "2026-07-19T08:30:00Z",
    "observation_window": {
      "from": "2026-07-18",
      "to": "2026-07-18"
    },
    "weighted_data_units": 1
  }
}

Sale time-series example

A series contains exactly one market mode. Each point retains its mode and observation count so a consumer can distinguish movement from a changing sample.

200 application/json
{
  "data": {
    "area_id": "bg-sofia-lozenets",
    "market_mode": "sale",
    "property_kind": "apartment",
    "date_from": "2026-07-15",
    "date_to": "2026-07-18",
    "points": [
      {"area_id": "bg-sofia-lozenets", "market_mode": "sale", "property_kind": "apartment", "as_of": "2026-07-15", "active_listings": 402, "new_listings": 12, "removed_listings": 9, "priced_listings": 378, "median_asking_price_eur": 281000, "median_asking_price_per_sqm_eur": 2815, "p25_asking_price_per_sqm_eur": 2350, "p75_asking_price_per_sqm_eur": 3280, "source_count": 3, "max_source_share": 0.43, "confidence": "high", "calculation_version": "market-api-daily-v2", "published_at": "2026-07-16T01:10:00Z"},
      {"area_id": "bg-sofia-lozenets", "market_mode": "sale", "property_kind": "apartment", "as_of": "2026-07-18", "active_listings": 418, "new_listings": 19, "removed_listings": 14, "priced_listings": 391, "median_asking_price_eur": 286000, "median_asking_price_per_sqm_eur": 2840, "p25_asking_price_per_sqm_eur": 2370, "p75_asking_price_per_sqm_eur": 3310, "source_count": 3, "max_source_share": 0.42, "confidence": "high", "calculation_version": "market-api-daily-v2", "published_at": "2026-07-19T08:30:00Z"}
    ]
  },
  "meta": {
    "request_id": "req_01JZ8W8BQM5P3JY7VT",
    "generated_at": "2026-07-19T08:30:00Z",
    "observation_window": {"from": "2026-07-15", "to": "2026-07-18"},
    "weighted_data_units": 1
  }
}

Caching and weighted data units

Licences are metered by data delivered. A snapshot costs one unit; coverage costs one unit per 100 areas; time series cost one unit per 30 daily points, rounded up.

  • Use ETag and If-None-Match. A matching 304 response returns no payload and consumes zero data units.
  • Read meta.weighted_data_units and the X-Data-Units-Remaining header after every successful call.
  • A licence-wide monthly hard limit stops delivery before usage can exceed the contracted allowance.
  • Honor Retry-After on HTTP 429 and use exponential backoff with jitter for retryable 5xx responses.
Representative response headers
X-Request-Id: req_01JZ8W5Y6M9R7Q2F4A
X-Data-Units-Used: 1
X-Data-Units-Remaining: 24841
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 117
ETag: "snapshot-bg-sofia-lozenets-sale-2026-07-18"

Errors and retries

Errors use stable machine-readable codes and include the same request identifier available in response headers.

HTTPCodeClient action
400invalid_parameterCorrect the request; do not retry unchanged.
401invalid_api_keyStop and rotate or replace the credential.
403licence_scope_deniedThe endpoint is outside the key or licence scope.
403licence_inactiveContact the organisation owner or PazarenRadar.
404not_foundVerify the canonical identifier using /markets/coverage.
429rate_limitedWait for Retry-After, then retry with jitter.
429monthly_usage_exhaustedWait for the next month or arrange a larger allowance.
500/503temporary_failureRetry up to three times with exponential backoff.
403 application/json
{
  "error": {
    "code": "not_found",
    "message": "not found",
    "request_id": "req_01JZ8WBZ4R8Q1C6K9N"
  }
}

Instructions for AI agents

Treat the API as a licensed analytical tool, not as unrestricted browsing data. Give these rules to any agent that can call it.

  1. Resolve locations with GET /markets/coverage before analysis. Never guess an area_id.
  2. Select exactly one market_mode for each analysis. Never merge, average or compare sale and rent price fields as if they had the same unit.
  3. Use only fields and enum values in the issued OpenAPI contract; do not fabricate missing metrics.
  4. State market mode, as-of date, observation window, priced listing count and confidence alongside conclusions.
  5. For sale, price fields are total asking price and EUR/m². For rent, they are monthly asking rent and EUR/m²/month. Neither is a completed transaction price.
  6. Do not use aggregates to identify a person, contact, exact property or exact address.
  7. Keep API credentials outside the model context. Give the agent a narrow server-side tool, never the raw key.
  8. Estimate unit cost before long time-series ranges and request human approval for high-volume actions.
  9. Retry only 429 and temporary 5xx responses. Never loop on 400, 401, 403 or 404.
  10. Preserve request_id in citations or audit logs so every claim can be traced to a response.

Suggested agent policy

Use PazarenRadar only for aggregate Bulgarian property-market analysis. Resolve canonical locations through the coverage tool. Select exactly one market_mode: sale or rent. Never combine the two. For sale, interpret price fields as total asking price and EUR/m²; for rent, interpret them as monthly asking rent and EUR/m²/month. Never invent an area ID, metric, date or missing value. Include market mode, as-of date, observation window, priced listing count and confidence in every market conclusion. Neither mode contains completed transaction prices. Never expose credentials, personal data or exact addresses. Ask for human confirmation before high-unit time-series ranges. Honor licence scope, Retry-After and hard usage limits.

Example tool definition

Expose a narrow tool to the agent. Your application—not the model—adds the Bearer credential and enforces allowed areas, metrics and budget.

agent-tool.json
{
  "name": "get_market_snapshot",
  "description": "Get aggregate asking-price, supply and movement evidence for one licensed Bulgarian market area.",
  "input_schema": {
    "type": "object",
    "properties": {
      "area_id": {
        "type": "string",
        "description": "Canonical area ID returned by GET /markets/coverage."
      },
      "property_kind": {
        "type": "string",
        "enum": ["all", "apartment", "one-room", "two-room", "three-room", "four-plus-room", "house"]
      },
      "market_mode": {
        "type": "string",
        "enum": ["sale", "rent"],
        "description": "Required. Never combine sale and rent evidence."
      },
      "as_of": {
        "type": "string",
        "format": "date"
      }
    },
    "required": ["area_id", "market_mode", "property_kind"],
    "additionalProperties": false
  }
}

Integration examples

These examples call the production base URL. They require an active scoped key issued to your organisation.

cURL
curl --request GET \
  --url 'https://bulgarian-listings.152-53-109-83.sslip.io/api/v1/market/snapshot?area_id=bg-sofia-lozenets&market_mode=sale&property_kind=apartment&as_of=2026-07-18' \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <YOUR_API_KEY>' \
  --header 'X-Client-Request-Id: portfolio-review-2026-07-19'
TypeScript
const parameters = new URLSearchParams({
  area_id: 'bg-sofia-lozenets',
  market_mode: 'sale',
  property_kind: 'apartment',
  as_of: '2026-07-18',
});

const response = await fetch(
  `https://bulgarian-listings.152-53-109-83.sslip.io/api/v1/market/snapshot?${parameters}`,
  {
    headers: {
      Accept: 'application/json',
      Authorization: `Bearer ${process.env.PAZARENRADAR_API_KEY}`,
      'X-Client-Request-Id': crypto.randomUUID(),
    },
  },
);

if (response.status === 429) {
  throw new Error(`Retry after ${response.headers.get('retry-after')}s`);
}
if (!response.ok) throw new Error(await response.text());

const snapshot = await response.json();
console.log(snapshot.data.median_asking_price_per_sqm_eur);
Python
import os
import uuid
import requests

response = requests.get(
    "https://bulgarian-listings.152-53-109-83.sslip.io/api/v1/market/snapshot",
    params={
        "area_id": "bg-sofia-lozenets",
        "market_mode": "sale",
        "property_kind": "apartment",
        "as_of": "2026-07-18",
    },
    headers={
        "Accept": "application/json",
        "Authorization": f"Bearer {os.environ['PAZARENRADAR_API_KEY']}",
        "X-Client-Request-Id": str(uuid.uuid4()),
    },
    timeout=20,
)
response.raise_for_status()
snapshot = response.json()
print(snapshot["data"]["median_asking_price_per_sqm_eur"])

Need a production contract?

We qualify the use case, confirm data coverage and define volume, retention, display and derived-output rights before issuing production access.

The signed data licence and order form control permitted use, volume, retention and derived-output rights.