# Data Export

> **Casafari is the AI agent-native real estate data intelligence platform.** The most complete property index in Europe: a deduplicated, cleaned property graph of residential and commercial property, for sale and for rent, in 16 countries. Every property is one record with its full price and market history. [How the property graph is built](/docs/property-graph).

Bulk delivery of Casafari's data as files, for loading into your own warehouse rather than calling the API.

## Overview

Casafari Data Export delivers real estate market data as Avro files to a dedicated Google Cloud Storage (GCS)
bucket provisioned for your account. Five entity types are exported: **Property**, **Listing**, **Alert**,
**Location** and **ListingPhoto**. The set of entities enabled for your account is defined by your contract.

## Data delivery

- Data is delivered to one GCS bucket per country. Bucket names are provided by Casafari during onboarding.
- Inside a bucket, files are grouped by entity type:

```
properties/       listings/       listing_photos/       alerts/       locations/
```

- File names follow the pattern `{revision}_{salt}_{timestamp}.avro`, e.g.
  `latest_1f3a9c..._2026_07_29_10_15_30_123456.avro`:
  - `revision` — `latest` for full snapshots, `latest_delta` for incremental updates;
  - `salt` — a unique hex identifier of the export batch;
  - `timestamp` — file creation time, `YYYY_MM_DD_HH_MM_SS_ffffff`.

## Data format

Files are standard [Avro Object Container Files](https://avro.apache.org/docs/current/specification/):
the writer schema is embedded in every file, and each field carries a `doc` attribute with its description,
so any Avro library or tool can read the files and inspect the schema.
Optional fields are declared as `["null", ...]` unions with a `null` default.

## Sync semantics

- **Full sync** produces a complete snapshot of every enabled entity. Previous files in the entity folders are
  removed and replaced with a new set of `latest_*` files.
- **Delta sync** periodically uploads `latest_delta_*` files containing records created or updated since the
  previous run.
- To maintain an up-to-date copy: load the latest full snapshot, then apply delta files in file-timestamp order,
  upserting records by entity key.

## Sync status

A file named `sync_status.json` at the root of the bucket reports the progress of full and delta syncs, so you can
start processing as soon as a sync is done instead of waiting a fixed amount of time. It is written when a sync
starts and updated when the sync finishes.

```json
{
  "full": {
    "status": "finished",
    "started_at": "2026-09-01T02:00:00+00:00",
    "finished_at": "2026-09-01T06:30:00+00:00",
    "last_finished_at": "2026-09-01T06:30:00+00:00"
  },
  "delta": {
    "status": "processing",
    "started_at": "2026-09-11T02:00:00+00:00",
    "finished_at": null,
    "last_finished_at": "2026-09-10T03:10:00+00:00"
  }
}
```

The file has two sections, `full` and `delta`, with the same fields. All timestamps are ISO 8601 in UTC.

| Field | Description |
|---|---|
| status | `processing` while files are still being written to the bucket, `finished` once the run is done. |
| started_at | Start time of the current (or last) run. |
| finished_at | End time of that run; `null` while it is still in progress. |
| last_finished_at | Time data was last delivered successfully. **This is the field to rely on.** |

### Recommended usage

1. Read `sync_status.json` and pick the section you track (`full` or `delta`).
2. Start processing files only when `status` is `finished`.
3. Make sure the run actually delivered data: `last_finished_at` must be later than `started_at`. If it is
   earlier, the run did not complete in time — see *Timeouts* below.
4. To detect new data since your last import, compare `last_finished_at` with the value you saw last time.
   If it moved forward, there is new data.
5. Poll the file every 5–15 minutes; checking more often is not necessary.
6. If the file is missing or cannot be read, retry later. **Never treat that as `finished`.**

### Timeouts

A sync can take several hours, so a long `processing` status is normal. A sync should always complete well within
12 hours. As a safeguard, if a run is still open after 12 hours, it is closed in this file so the status never stays
stuck on `processing`: `status` becomes `finished` while `last_finished_at` keeps its previous value. This only
affects the file — the sync itself keeps running. This is not expected to happen; if you ever notice it, please
contact your Casafari account manager.

## Entities and keys

| Entity | Key | Notes |
|---|---|---|
| Property | property_id + property_unit_id | The pair uniquely identifies a property. |
| Listing | listing_id | References its property via property_id + property_unit_id. |
| Alert | alert_id | Change events; reference listing_id and property_id. |
| Location | location_id | Location tree; parent_id points to the parent location. |
| ListingPhoto | listing_id | A list of image URLs per listing. |

The full field reference for every entity is provided in the schema definitions below.

## Support

For questions about the data or delivery, contact your Casafari account manager.

## Entities

| Entity | Fields | What it holds |
|---|---|---|
| [Property](/docs/data-export/property) | 70 | Every field of the Property entity in the export files, with its type and meaning. |
| [Listing](/docs/data-export/listing) | 59 | Every field of the Listing entity in the export files, with its type and meaning. |
| [Alert](/docs/data-export/alert) | 9 | Every field of the Alert entity in the export files, with its type and meaning. |
| [Location](/docs/data-export/location) | 5 | Every field of the Location entity in the export files, with its type and meaning. |
| [ListingPhoto](/docs/data-export/listing-photo) | 4 | Every field of the ListingPhoto entity in the export files, with its type and meaning. |

Source: the API team's own description, [https://docs.api.casafari.com/data-export](https://docs.api.casafari.com/data-export).
