Bulk import
Import is for putting a portfolio into Skautik and keeping it there. One listing is a POST to properties; four hundred, refreshed nightly, is this.
One transfer
curl -sS -X POST "https://api.skautik.com/v1/api/imports?format=csv&mode=incremental" \
-H "Authorization: Bearer $SKAUTIK_API_KEY" \
-H "Idempotency-Key: 6f1c2a7e-4d90-4a1b-9f33-0c2f5b8e77aa" \
-F "file=@listings.csv"The response is a run you can poll:
{
"data": {
"id": "imp_3d9b7e2145",
"format": "csv",
"mode": "incremental",
"status": "queued",
"dry_run": false
}
}GET /v1/api/imports/{import_id} reports progress and, when it finishes, counts:
{
"counts": { "read": 412, "created": 37, "updated": 361, "withdrawn": 9 }
}GET /v1/api/imports/{import_id}/records is the row-by-row account, including
every rejection with the reason. It is the first place to look when the counts
are not what you expected.
The two modes
incremental updates what the file contains and leaves everything else
alone. This is the default, and the right choice for a partial feed: a file of
this week's changes, or one branch's listings.
full_sync treats the file as the complete truth for that source. Anything
this source published before and that is absent from the file is withdrawn.
The default is incremental for one reason: a mode that removes things should not be something you get by omission. A truncated upload in full sync mode withdraws a portfolio.
Always dry run a new mapping
curl -sS -X POST "https://api.skautik.com/v1/api/imports?format=csv&mode=full_sync&dry_run=true" \
-H "Authorization: Bearer $SKAUTIK_API_KEY" \
-F "file=@listings.csv"A dry run parses everything, validates everything, and reports exactly the counts and per-record outcomes a real run would produce, while writing nothing. On a full sync it will tell you how many properties would be withdrawn, which is the number worth looking at before you find out the other way.
Identity, and why external_id matters
Every import format has a field that identifies a record in your system, and
Skautik keys on it. Send the same external_id twice and the second run updates
the first record; send a new one each time and you publish the same property
repeatedly.
That field is the whole of the reconciliation story. It is echoed back on every property, so you never need a table mapping our identifiers to yours.
If your export has no stable per-record identifier, fix that before importing. Anything else, including matching on address, will eventually merge two flats in one building or split one flat into two records.
Standing sources
A one-off upload is fine for a migration. For a feed, create a source once and let it run:
curl -sS -X POST "https://api.skautik.com/v1/api/import-sources" \
-H "Authorization: Bearer $SKAUTIK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Nightly listing sync",
"format": "csv",
"delivery": { "type": "fetch", "url": "https://partner.example.com/exports/latest.csv" },
"schedule": "15 3 * * *",
"deletion_policy": "withdraw",
"mapping": { "Objektnummer": "external_id", "Kaufpreis": "price" }
}'delivery.typeisfetchwhen we pull from a URL on a schedule, or a drop when you push to us.scheduleis cron, in UTC. Nightly at a quiet hour beats hourly: a feed polled more often than it changes is just load.mappingtranslates your column names to ours, so you do not have to rename anything at your end.deletion_policydecides what an absent record means for this source.
last_delivery_at and next_expected_at on the source are what to alert on. A
feed that silently stops is the failure worth catching, and it looks exactly like
a feed with no changes unless you watch those two fields.
Records owned by a source
A property that arrived through an import belongs to that import. Its source
says so, and the write endpoints refuse to change it with 409 managed_by_import.
That is deliberate. If both the feed and the API could edit a record, the next run of the feed would silently undo the edit, and nobody would know which system was authoritative. Change it in the system that feeds the import.
Formats
Import formats covers each one Skautik reads, how it identifies a record, and how removal works within it. In most cases you already produce one of them for a listing portal, and can send that unchanged.
If your system exports something not on the list, send a sample rather than writing a converter. Property exchange formats are a small, well-known set.
A checklist for a first import
- Dry run, and read the record-level outcomes rather than only the counts.
- Confirm
external_idis stable and unique in your source. - Start
incremental; move tofull_synconly once the file is genuinely complete. - Send an
Idempotency-Key, so a timeout does not become a second import. - Watch
next_expected_atonce it is a standing source.