Fișier de Context LLM
O referință de integrare pe o singură pagină concepută pentru a fi lipită într-un asistent IA (Claude, GPT-4, Gemini, etc.) ca context înainte de a-i cere să implementeze o integrare cu API Qarta.
Conține tot ce are nevoie un LLM pentru a scrie cod corect prima dată: URL de bază, formatul exact al header-ului de autentificare, ambele formate de formă, diferențele de filtre V1/V2, toate cele 36 de endpoint-uri, formate de ieșire, formate de eroare, reguli de paginare și un tabel cu greșeli comune.
Cum să o folosești
- Descarcă sau copiază conținutul fișierului mai jos
- Lipește-l la începutul promptului tău, înainte de cererea de implementare
- LLM-ul o va folosi ca referință autoritară în loc să ghicească
Exemplu de prompt:
<context>
[lipește conținutul CLAUDE.md aici]
</context>
Folosind API-ul documentat mai sus, scrie o funcție Python care primește
un poligon GeoJSON și returnează toate punctele de portofoliu din el ca DataFrame.
Descarcă
Descarcă CLAUDE.md
Conținutul fișierului
Copiază markdown-ul brut de mai jos folosind butonul din dreapta sus al blocului de cod.
# Qarta API — Integration Reference
You are implementing an integration against the **Qarta API** (also called the Layers API), a geospatial intelligence platform by Quarticle. This file contains everything you need to implement correctly. Do not guess — use the facts below.
---
## Base URL and Authentication
```
Base URL: https://graph.quarticle.ro
Auth: Authorization: <api_key>
```
**Do NOT add a `Bearer` prefix.** The raw API key goes directly in the `Authorization` header.
```bash
curl https://graph.quarticle.ro/graph/api/v1/places/geocode?q=London \
-H "Authorization: YOUR_API_KEY"
```
---
## The `source` Parameter
All portfolio, entries, points, accumulation, and risk endpoints require a `source` parameter. It identifies which data layer/portfolio to query — a string identifier provisioned to the account (e.g., `"portfolio_01"`).
Discover available sources by calling the provision endpoint first:
```bash
GET /graph/api/v1/reports/portfolio/provision
```
Response structure:
```json
{
"provisioning": {
"portfolio_01": {
"columns": [
{ "field": "insured_value", "type": "number" },
{ "field": "property_type", "type": "string" }
],
"filters": [
{ "field": "oe_id", "label": "Organization", "required": true, "values": ["org_1"] }
],
"reports": { "accumulation": { "enabled": true } }
}
}
}
```
Use the key (`"portfolio_01"`) as the `source` value in all subsequent calls.
---
## Shape Formats
There are **two distinct shape formats** — do not mix them up.
### Polygon shapes (for `/selection` endpoints)
Standard GeoJSON Feature. Coordinates are `[longitude, latitude]` arrays (longitude first).
```json
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [[
[-74.0200, 40.7000],
[-74.0000, 40.7000],
[-74.0000, 40.7300],
[-74.0200, 40.7300],
[-74.0200, 40.7000]
]]
},
"properties": {}
}
```
Rules:
- First and last coordinate must be identical (closes the polygon)
- Minimum 4 coordinate pairs (3 unique + 1 closing)
- `MultiPolygon` is also supported
- Coordinate system: WGS84 / EPSG:4326 only
### Buffer shapes (for `/buffer-selection` and `/buffer` endpoints)
**Not GeoJSON.** Uses a different format with named `{lat, long}` objects. Coordinates are **latitude first** in named fields (opposite order from GeoJSON).
```json
{
"shape": {
"type": "circle",
"coordinates": [{ "lat": 40.7128, "long": -74.0060 }]
},
"radiuses": [1000, 5000, 10000]
}
```
Rules:
- `radiuses` is at the **request body level**, not inside the shape object
- Values are in **meters**
- Multiple radii return one result set per radius
- `coordinates` uses `{ "lat": ..., "long": ... }` — not arrays, not GeoJSON order
---
## Filters: V1 vs V2
### V1 filters — simple flat array
```json
{
"source": "portfolio_01",
"filters": [
{ "field": "oe_id", "value": "my_org" },
{ "field": "property_type", "value": "residential" }
]
}
```
All filters are AND-combined. No nesting.
### V2 filters — recursive nested tree
```json
{
"source": "portfolio_01",
"filters_v2": [
{
"field": "property_type",
"value": "residential",
"filters": [
{ "field": "occupancy", "value": "occupied" }
]
}
]
}
```
### ⚠️ V2 search endpoint exception
The V2 search endpoints (`/graph/api/v2/reports/portfolio/entries/selection/search` and the points equivalent) use `"filters"` as the body key — **not** `"filters_v2"`. All other V2 endpoints use `"filters_v2"`.
---
## All Endpoints
### Location Services (no `source` required)
| Method | Path | Description |
|--------|------|-------------|
| GET | `/graph/api/v1/places/autocomplete?q=` | Address suggestions |
| GET | `/graph/api/v1/places/geocode?q=` | Address → coordinates |
| GET | `/graph/api/v1/places/geocode/reverse?lat=&lon=` | Coordinates → address |
Geocode response:
```json
{ "lat": 51.5034, "lon": -0.1276, "label": "10 Downing St...", "geocodingQuality": "rooftop" }
```
### Portfolio — Provision
| Method | Path | Description |
|--------|------|-------------|
| GET | `/graph/api/v1/reports/portfolio/provision?source=` | Source config, columns, filters |
| GET | `/graph/api/v1/reports/portfolio/provision/filters?source=` | Filter hierarchy |
### Portfolio — V1 Selection (POST, body uses `filters`)
| Method | Path | Description |
|--------|------|-------------|
| POST | `/graph/api/v1/reports/portfolio/points/selection` | GeoJSON points in polygon |
| POST | `/graph/api/v1/reports/portfolio/points/buffer-selection` | GeoJSON points in buffer |
| POST | `/graph/api/v1/reports/portfolio/entries/selection` | Detailed records in polygon |
| POST | `/graph/api/v1/reports/portfolio/entries/buffer-selection` | Detailed records in buffer |
| GET | `/graph/api/v1/reports/portfolio/entries/selection/search` | Search entries (query params) |
| GET | `/graph/api/v1/reports/portfolio/points/attributes?source=&value=` | Attributes for a point |
### Portfolio — V1 Accumulation (POST, body uses `filters`)
| Method | Path | Description |
|--------|------|-------------|
| POST | `/graph/api/v1/reports/portfolio/accumulation/selection` | Aggregate metrics in polygon |
| POST | `/graph/api/v1/reports/portfolio/accumulation/buffer` | Aggregate metrics in buffer |
| POST | `/graph/api/v1/reports/portfolio/accumulation/layer` | Layer-level data retrieval |
### Portfolio — V2 (POST, body uses `filters_v2` except search)
Replace `/v1/` with `/v2/` for all selection and accumulation endpoints above. Search endpoints become POST:
| Method | Path |
|--------|------|
| POST | `/graph/api/v2/reports/portfolio/entries/selection/search` |
| POST | `/graph/api/v2/reports/portfolio/points/selection/search` |
### Risk Reporting
| Method | Path | Description |
|--------|------|-------------|
| POST | `/graph/api/v1/reports/risk/point` | Risk report for a point (PDF/HTML) |
| POST | `/graph/api/v1/reports/portfolio/risk/point-buffer` | Risk report with buffer accumulation |
### Point Enrichment
| Method | Path | Description |
|--------|------|-------------|
| GET | `/graph/featureinfo/risk-lookup/api/v1/bfi/single?lat=&lng=&layers=&operation=` | Single point |
| POST | `/graph/featureinfo/enrichment/api/v1/bfi/batch` | Batch enrichment |
### Web Services (WMS / WFS)
| Method | Path | Key params |
|--------|------|------------|
| GET | `/graph/layers/wms?SERVICE=WMS&REQUEST=GetCapabilities` | Capabilities XML |
| GET | `/graph/layers/wms?SERVICE=WMS&REQUEST=GetMap&...` | Map tile (PNG) |
| GET | `/graph/layers/wms?SERVICE=WMS&REQUEST=GetFeatureInfo&...` | Feature info at pixel |
| GET | `/graph/layers/wms?SERVICE=WMS&REQUEST=GetLegendGraphic&LAYER=` | Legend image |
| GET | `/graph/layers/wms?SERVICE=WMS&REQUEST=DescribeLayer&LAYERS=` | Layer description |
| GET | `/graph/layers/wfs?SERVICE=WFS&REQUEST=GetFeature&TYPENAMES=` | Feature data |
WMS map tiles use **Web Mercator (EPSG:3857)** for the `SRS`/`CRS` and `BBOX` parameters. WFS feature queries use EPSG:4326.
### Live Events
| Method | Path |
|--------|------|
| POST | `/graph/api/v1/live-events/footprints/:footprint/enrich/entries` |
---
## Output Formats
Control the response format with the `Accept` header:
| Accept header | Format | Supported by |
|---------------|--------|--------------|
| `application/json` | JSON (default) | All endpoints |
| `text/csv` | CSV | entries and points endpoints |
| `application/pdf` | PDF | risk report endpoints |
| `text/html` | HTML | risk report endpoints |
| `image/png` | PNG image | WMS GetMap, GetLegendGraphic |
| `application/xml` | XML | WMS/WFS GetCapabilities |
---
## Pagination
Used on entries endpoints with `columns`, `limit`, and `page`:
```json
{
"source": "portfolio_01",
"shape": { ... },
"columns": ["id", "name", "value"],
"limit": 100,
"page": 0
}
```
- `page` is **0-indexed**
- Increment `page` until the response returns fewer items than `limit`
---
## Error Response Formats
Two formats exist — which one you receive depends on the endpoint:
```json
{ "message": "Error description" }
```
```json
{ "errorMessage": { "message": "Error description" } }
```
Handle both. HTTP status codes:
| Code | Meaning |
|------|---------|
| 400 | Invalid parameters or malformed body |
| 401 | Missing or invalid API key |
| 403 | Invalid shape geometry or insufficient permissions |
| 500 | Server error — retry with exponential backoff |
A 403 on a spatial endpoint usually means the GeoJSON shape is invalid (wrong coordinate order, unclosed polygon, wrong CRS).
---
## Python SDK
A fully-typed SDK is available at `sdks/layers/` in this repository (also downloadable as `layers-sdk-python.zip`).
**Requirements:** Python ≥ 3.10, `httpx ≥ 0.27`, `pydantic ≥ 2.0`
**Installation:**
```bash
pip install . # from the unzipped SDK directory
# or
pip install httpx pydantic && # place layers_sdk/ in your project
```
**Client setup:**
```python
from layers_sdk import LayersClient
client = LayersClient(base_url="https://graph.quarticle.ro", api_key="YOUR_API_KEY")
```
**Service map:**
| `client.*` | Covers |
|------------|--------|
| `location` | `autocomplete()`, `geocode()`, `reverse_geocode()` |
| `reports_v1` | V1 portfolio — uses `PortfolioFilter` |
| `reports_v2` | V2 portfolio — uses `RequestFilter` |
| `risk` | `point_risk()`, `point_buffer_risk()`, V2 variants |
| `enrichment` | `enrich_single()`, `enrich_batch()` |
| `wms` | `get_map()`, `get_capabilities()`, `get_feature_info()`, `get_legend_graphic()` |
| `wfs` | `get_feature()` |
**Key model imports:**
```python
from layers_sdk import (
LayersClient,
Feature, Geometry, GeometryType, # polygon shapes
Buffer, Coordinates, # buffer shapes
PortfolioFilter, # V1 filters
RequestFilter, # V2 filters
PointRiskRequestPayload, PointRiskLayers, # risk reports
PointRequest, # batch enrichment
)
from layers_sdk.exceptions import BadRequestError, ForbiddenError, ServerError
```
**Prefer the SDK over raw HTTP** for any Python integration — it handles model validation, serialisation, and raises typed exceptions.
---
## Common Mistakes to Avoid
| Mistake | Correct behaviour |
|---------|-------------------|
| Adding `Bearer ` prefix to the API key | Send the raw key value directly |
| Using `[lat, lon]` coordinate order in GeoJSON | GeoJSON is always `[lon, lat]` |
| Using GeoJSON format for buffer shapes | Buffer shapes use `{type: "circle", coordinates: [{lat, long}]}` |
| Putting `radiuses` inside the shape object | `radiuses` is a top-level request body field |
| Using `filters_v2` in V2 search endpoint body | V2 search uses `filters`, not `filters_v2` |
| Using `GET /v1/status` to test connectivity | That endpoint does not exist — use geocode instead |
| Forgetting to close polygon rings | First and last coordinate must be identical |
| Using UTM or Web Mercator coordinates in shapes | Shapes always use WGS84 / EPSG:4326 |
| Expecting a single error response format | Handle both `{message}` and `{errorMessage: {message}}` |