Connector spec v1.1.0

What a VOR-Ready feed looks like.

AssetDNA turns a property system's day-to-day records into a verifiable operating record — an append-only, independently checkable history a lender or valuer can re-verify without trusting either of us. This page is the whole inbound contract: assetdna.connector.v1. Build against it, check yourself below, and your feed is VOR-Ready — no meeting required.

Check your feed

Paste a batch. The validator below is the same code our adapter runs, so a pass here is a pass in production — and it runs in your browser, so you can test with real data before any data-sharing agreement exists.

Start from the export you already get

Your system already produces an export — a tenancy list, a bookings file, a rent roll, a payments run. Mapping one onto connector.v1 is a short piece of work we do with you, against the contract published on this page, and you keep the result. Send us a header line and we will tell you what it takes.

Talk to us about your system →

Everything below needs none of that: paste a connector.v1 batch and the same validator our adapter runs checks it in this browser — no account, no upload, no agreement.

Checked entirely in this browser — nothing is sent to AssetDNA. Paste a real batch if you like.

The envelope

FieldTypeMeaning
format"assetdna.connector.v1"Format discriminator. Version-suffixed; a breaking change mints a new value and both stay accepted.
sourcestringYour system's registered slug. Determines the corroboration grade the facts earn — see the source table below. An unregistered source still validates; it is graded conservatively until we classify it together.
externalPropertyIdstringThe property's id in YOUR system. We map it to ours at connection time, so you never need to hold an AssetDNA identifier.
generatedAtstring (ISO-8601)When you produced the batch. Must carry an explicit offset (Z or ±hh:mm) — a timestamp without one is ambiguous, and this is a record of when things happened.
nextCursorstring | nullOpaque cursor to the next page, or null/omitted when the set is complete. Batches are capped at 1000 records per array.
leasesobject[]Current lease roster: id, unitLabel, tenantName, startDate, endDate, rentAmount, rentPeriod, bondAmount, status.
transactionsobject[]Financial movements: id, type, amount, date, unitLabel.

format, source, externalPropertyId and generatedAt are required on every batch; at least one of leases or transactions must be present. The authoritative definition is the JSON Schema (draft 2020-12).

Four rules that shape everything else

Transport is yours to choose

The contract is the payload, not the endpoint. Satisfy it over a REST endpoint we poll, a scheduled file drop — or push it yourself: POST a batch to /api/v1/ingest with an org API key (Authorization: Bearer, or x-assetdna-key). The declared source must match a connector the operator has registered in-app — a payload can never enrol its own source — and replaying a batch appends nothing (ids are the idempotency key).

ids are the idempotency key

Every record carries a stable id from your system. Re-sending a batch is safe: an id we already hold updates the record rather than duplicating it. Ids must be unique within one batch — a repeat means the sender can't say which is current, so the validator flags it.

Nothing is ever deleted

The record is append-only. A correction is a new event that supersedes an earlier one; the earlier one stays visible with its original timestamp. If your system hard-deletes, send the correction — don't stop sending the row.

Conformance is not a truth claim

Passing this check means your feed is well-formed and machine-consumable. It does not mean the facts are true, and a property system's feed never counts as independent corroboration of its own assertions. That honesty is the product; see the grading table below.

What your records become

Each record maps to exactly one typed ledger event. A transaction type we don't recognise falls back to GL_TRANSACTION_SYNCED rather than being dropped — unmapped data is a conversation, never a silent loss.

LEASE_SYNCEDRENT_RECEIVEDBOND_HELDBOND_RELEASEDMAINTENANCE_INVOICEDGL_TRANSACTION_SYNCED

How your facts get graded

Everything we receive is sealed on receipt — hash-chained, so it can't be altered afterwards, by you or by us. But sealing proves “unchanged since we took it”, never “true at source”. So a fact is separately graded by who is asserting it: a property system's own feed cannot corroborate the property system's own claim, no matter how clean the JSON is. A bank feed or a meter can.

sourceKindIndependent corroboration?
yardiPMSNo — sealed, but the system's own assertion
yardi_commercialPMSNo — sealed, but the system's own assertion
starrezPMSNo — sealed, but the system's own assertion
mewsPMSNo — sealed, but the system's own assertion
xeroFINANCIALYes — independent of the property system
bank_feedFINANCIALYes — independent of the property system
iot_metersIOTYes — independent of the property system
bmsBMSYes — independent of the property system
backofficeOWNERYes — independent of the property system
externalEXTERNALYes — independent of the property system
pms_genericPMSNo — sealed, but the system's own assertion

Not listed? Send the feed anyway. It validates and seals exactly the same; it is simply graded conservatively until we classify the source together during onboarding.

Versioning promise

assetdna.connector.v1 is frozen: fields may be added, never removed or changed in meaning. A breaking change mints assetdna.connector.v2 alongside it, and v1 feeds keep being accepted — a partner should never have to re-integrate because we changed our mind.