Skip to main content

API reference

Every operation of the partner API v1, generated from the same registry the API validates with.

Base URL
https://novikvadrat.rs/api/partners/v1

Every request is signed (NK-SIG-1)

Five headers on every call: an Ed25519 signature over the method, host, path and query, a timestamp, a nonce and the body digest. How to sign a request

Download openapi.json

Operations

Ping

GET/ping

Prove the signature works and read the app, key and limits.

Signed request; five headers

Responses

200 OK.

Unknown fields are rejected.

Response 200 of ping
FieldTypeRequiredConstraintsDescription
appobjectYes—Unknown fields are rejected.
app.idstring (uuid)Yes—
app.environmentstring (enum)sandboxliveYes—
app.namestringYes—
key_idstringYes—
partnerobjectYes—Unknown fields are rejected.
partner.idstring (uuid)Yes—
partner.namestringYes—
server_timestring (date-time)Yes—
limitsobjectYes—Unknown fields are rejected.
limits.rate_limit_per_minuteintegerYes≥ -9007199254740991 · ≤ 9007199254740991
limits.connection_items_per_hourintegerYes≥ -9007199254740991 · ≤ 9007199254740991
limits.max_batch_itemsintegerYes≥ -9007199254740991 · ≤ 9007199254740991

scrolls →

Examples

Request · ping
GET /api/partners/v1/ping
NK-Key-Id: nkp_sandbox_7f3k9q2m4x8c1v6b
NK-Timestamp: 1791792000
NK-Nonce: <16–64 random bytes, base64url>
Content-Digest: sha-256=:47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=:
NK-Signature: v1=<86 base64url characters, no padding>

Errors

No errors beyond the signed-request checks.

Errors on every endpoint (14)
Errors on every endpoint, ping
CodeHTTPWhen it happensWhat to do
ingest_disabled503Novi Kvadrat switched ingestion off.Retry later with backoff.
body_too_large413The body is over 4 MiB (checked first).Split the batch.
signature_missing401A signing header is absent or malformed.Send all five headers.
key_invalid401Unknown or revoked key.Register a new key.
key_expired401The key is past its 365 days.Register a new key.
app_suspended403Staff suspended the app.Write to partners@novikvadrat.rs.
account_blocked403Staff suspended or archived the organization.Write to partners@novikvadrat.rs.
ip_allowlist_empty403A live app without addresses.Edit the allowlist.
ip_not_allowed403The caller is not listed, or its address can't be determined.Edit the allowlist.
digest_mismatch400The body changed after hashing.Hash the exact bytes you send.
timestamp_out_of_window401The clock is off by more than 300 s.Sync the clock (NTP).
signature_invalid401The base string or the key does not match.Compare with the test vector.
nonce_reused401A nonce sent twice within 15 minutes.A fresh random nonce per request.
rate_limited429Over the per-minute budget (replays count too).Wait Retry-After.

scrolls →

Connections

POST/connections

Redeem a connect code an agency generated.

Signed request; five headers

Request body

Unknown fields are rejected.

Request body of connections.redeem
FieldTypeRequiredConstraintsDescription
connect_codestringYesmin length 12 · max length 32

scrolls →

Responses

201 Created.

Unknown fields are rejected.

Response 201 of connections.redeem
FieldTypeRequiredConstraintsDescription
connectionobjectYes—Unknown fields are rejected.
connection.idstring (uuid)Yes—
connection.statusstring (enum)certifyingactivepausedrevokedYes—
connection.environmentstring (enum)sandboxliveYes—
connection.agencyobjectYes—Unknown fields are rejected.
connection.agency.namestringYes—
connection.agency.register_numberstring | nullYes—
connection.agency.verification_statusstring (enum)unverifiedpendingverifiedrejectedYes—
connection.agency.listing_quotaobjectYes—Unknown fields are rejected.
connection.agency.listing_quota.usedintegerYes≥ 0 · ≤ 9007199254740991
connection.agency.listing_quota.limitinteger | nullYes≥ -9007199254740991 · ≤ 9007199254740991
connection.agency.photo_limitintegerYes≥ 0 · ≤ 9007199254740991
connection.created_atstringYes—
connection.redeemed_atstring | nullYes—
connection.certified_atstring | nullYes—
connection.pausedobject | nullYes—Unknown fields are rejected.
connection.paused.atstringYes—
connection.paused.bystring (enum)agencystaffYes—
connection.paused.reasonstring | nullYes—
connection.countsobjectYes—Unknown fields are rejected.
connection.counts.liveintegerYes≥ 0 · ≤ 9007199254740991
connection.counts.pausedintegerYes≥ 0 · ≤ 9007199254740991
connection.counts.reviewintegerYes≥ 0 · ≤ 9007199254740991
connection.counts.failedintegerYes≥ 0 · ≤ 9007199254740991
connection.last_push_atstring | nullYes—

scrolls →

  • 400 body_invalid: The body is not a JSON object. The body is the error envelope.
  • 404 connect_code_invalid: An unknown, expired, used or other app's code. The body is the error envelope.
  • 422 agency_not_eligible: details.reason is register_number_missing or account_blocked. validation_failed: The payload is invalid (details array). The body is the error envelope.

Examples

Request · connections.redeem
POST /api/partners/v1/connections
NK-Key-Id: nkp_sandbox_7f3k9q2m4x8c1v6b
NK-Timestamp: 1791792000
NK-Nonce: <16–64 random bytes, base64url>
Content-Digest: sha-256=:<base64 SHA-256 of the exact body bytes>:
NK-Signature: v1=<86 base64url characters, no padding>
Content-Type: application/json

{
  "connect_code": "NK-7Q4M-X2PA-9KDF"
}

Errors

Errors of connections.redeem
CodeHTTPWhen it happensWhat to do
body_invalid400The body is not a JSON object.Send valid JSON.
connect_code_invalid404An unknown, expired, used or other app's code.Ask for a new code.
agency_not_eligible422details.reason is register_number_missing or account_blocked.The agency fixes its profile.
validation_failed422The payload is invalid (details array).Fix the fields at the pointers.

scrolls →

Errors on every endpoint (14)
Errors on every endpoint, connections.redeem
CodeHTTPWhen it happensWhat to do
ingest_disabled503Novi Kvadrat switched ingestion off.Retry later with backoff.
body_too_large413The body is over 4 MiB (checked first).Split the batch.
signature_missing401A signing header is absent or malformed.Send all five headers.
key_invalid401Unknown or revoked key.Register a new key.
key_expired401The key is past its 365 days.Register a new key.
app_suspended403Staff suspended the app.Write to partners@novikvadrat.rs.
account_blocked403Staff suspended or archived the organization.Write to partners@novikvadrat.rs.
ip_allowlist_empty403A live app without addresses.Edit the allowlist.
ip_not_allowed403The caller is not listed, or its address can't be determined.Edit the allowlist.
digest_mismatch400The body changed after hashing.Hash the exact bytes you send.
timestamp_out_of_window401The clock is off by more than 300 s.Sync the clock (NTP).
signature_invalid401The base string or the key does not match.Compare with the test vector.
nonce_reused401A nonce sent twice within 15 minutes.A fresh random nonce per request.
rate_limited429Over the per-minute budget (replays count too).Wait Retry-After.

scrolls →

Detail codes

Detail codes of connections.redeem
Detail codeMeaningExample pointer
unknown_fieldA key the schema doesn't know./structure/balcon
requiredA required field is missing./title/sr
invalid_typeThe wrong JSON type./structure/rooms
too_smallBelow a minimum (length or value)./description/sr
too_bigAbove a maximum (length or value)./price/amount
invalid_enumA value outside the vocabulary./structure/heating
invalid_formatA malformed id, URL, date or pattern./photos/0/url

scrolls →

GET/connections

List this app's connections.

Signed request; five headers

Parameters

Parameters of connections.list
NameInTypeRequiredDescription
statusqueryenum: certifying, active, paused, revokedNo
limitquerystring, pattern ^\d{1,3}$No
cursorquerystringNo

scrolls →

Responses

200 OK.

Unknown fields are rejected.

Response 200 of connections.list
FieldTypeRequiredConstraintsDescription
connectionsarray of objectYes—
connections[].idstring (uuid)Yes—
connections[].statusstring (enum)certifyingactivepausedrevokedYes—
connections[].environmentstring (enum)sandboxliveYes—
connections[].agencyobjectYes—Unknown fields are rejected.
connections[].agency.namestringYes—
connections[].agency.register_numberstring | nullYes—
connections[].agency.verification_statusstring (enum)unverifiedpendingverifiedrejectedYes—
connections[].agency.listing_quotaobjectYes—Unknown fields are rejected.
connections[].agency.listing_quota.usedintegerYes≥ 0 · ≤ 9007199254740991
connections[].agency.listing_quota.limitinteger | nullYes≥ -9007199254740991 · ≤ 9007199254740991
connections[].agency.photo_limitintegerYes≥ 0 · ≤ 9007199254740991
connections[].created_atstringYes—
connections[].redeemed_atstring | nullYes—
connections[].certified_atstring | nullYes—
connections[].pausedobject | nullYes—Unknown fields are rejected.
connections[].paused.atstringYes—
connections[].paused.bystring (enum)agencystaffYes—
connections[].paused.reasonstring | nullYes—
connections[].countsobjectYes—Unknown fields are rejected.
connections[].counts.liveintegerYes≥ 0 · ≤ 9007199254740991
connections[].counts.pausedintegerYes≥ 0 · ≤ 9007199254740991
connections[].counts.reviewintegerYes≥ 0 · ≤ 9007199254740991
connections[].counts.failedintegerYes≥ 0 · ≤ 9007199254740991
connections[].last_push_atstring | nullYes—
next_cursorstring | nullYes—

scrolls →

  • 422 validation_failed: The payload is invalid (details array). The body is the error envelope.

Examples

Request · connections.list
GET /api/partners/v1/connections
NK-Key-Id: nkp_sandbox_7f3k9q2m4x8c1v6b
NK-Timestamp: 1791792000
NK-Nonce: <16–64 random bytes, base64url>
Content-Digest: sha-256=:47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=:
NK-Signature: v1=<86 base64url characters, no padding>

Errors

Errors of connections.list
CodeHTTPWhen it happensWhat to do
validation_failed422The payload is invalid (details array).Fix the fields at the pointers.

scrolls →

Errors on every endpoint (14)
Errors on every endpoint, connections.list
CodeHTTPWhen it happensWhat to do
ingest_disabled503Novi Kvadrat switched ingestion off.Retry later with backoff.
body_too_large413The body is over 4 MiB (checked first).Split the batch.
signature_missing401A signing header is absent or malformed.Send all five headers.
key_invalid401Unknown or revoked key.Register a new key.
key_expired401The key is past its 365 days.Register a new key.
app_suspended403Staff suspended the app.Write to partners@novikvadrat.rs.
account_blocked403Staff suspended or archived the organization.Write to partners@novikvadrat.rs.
ip_allowlist_empty403A live app without addresses.Edit the allowlist.
ip_not_allowed403The caller is not listed, or its address can't be determined.Edit the allowlist.
digest_mismatch400The body changed after hashing.Hash the exact bytes you send.
timestamp_out_of_window401The clock is off by more than 300 s.Sync the clock (NTP).
signature_invalid401The base string or the key does not match.Compare with the test vector.
nonce_reused401A nonce sent twice within 15 minutes.A fresh random nonce per request.
rate_limited429Over the per-minute budget (replays count too).Wait Retry-After.

scrolls →

Detail codes

Detail codes of connections.list
Detail codeMeaningExample pointer
unknown_fieldA key the schema doesn't know./structure/balcon
requiredA required field is missing./title/sr
invalid_typeThe wrong JSON type./structure/rooms
too_smallBelow a minimum (length or value)./description/sr
too_bigAbove a maximum (length or value)./price/amount
invalid_enumA value outside the vocabulary./structure/heating
invalid_formatA malformed id, URL, date or pattern./photos/0/url

scrolls →

GET/connections/{id}

One connection with counts and the agency summary.

Signed request; five headers

Parameters

Parameters of connections.get
NameInTypeRequiredDescription
idpathstring (uuid)YesThe connection id.

scrolls →

Responses

200 OK.

Unknown fields are rejected.

Response 200 of connections.get
FieldTypeRequiredConstraintsDescription
connectionobjectYes—Unknown fields are rejected.
connection.idstring (uuid)Yes—
connection.statusstring (enum)certifyingactivepausedrevokedYes—
connection.environmentstring (enum)sandboxliveYes—
connection.agencyobjectYes—Unknown fields are rejected.
connection.agency.namestringYes—
connection.agency.register_numberstring | nullYes—
connection.agency.verification_statusstring (enum)unverifiedpendingverifiedrejectedYes—
connection.agency.listing_quotaobjectYes—Unknown fields are rejected.
connection.agency.listing_quota.usedintegerYes≥ 0 · ≤ 9007199254740991
connection.agency.listing_quota.limitinteger | nullYes≥ -9007199254740991 · ≤ 9007199254740991
connection.agency.photo_limitintegerYes≥ 0 · ≤ 9007199254740991
connection.created_atstringYes—
connection.redeemed_atstring | nullYes—
connection.certified_atstring | nullYes—
connection.pausedobject | nullYes—Unknown fields are rejected.
connection.paused.atstringYes—
connection.paused.bystring (enum)agencystaffYes—
connection.paused.reasonstring | nullYes—
connection.countsobjectYes—Unknown fields are rejected.
connection.counts.liveintegerYes≥ 0 · ≤ 9007199254740991
connection.counts.pausedintegerYes≥ 0 · ≤ 9007199254740991
connection.counts.reviewintegerYes≥ 0 · ≤ 9007199254740991
connection.counts.failedintegerYes≥ 0 · ≤ 9007199254740991
connection.last_push_atstring | nullYes—

scrolls →

  • 404 connection_not_found: Unknown id, or another app's connection. The body is the error envelope.

Examples

Request · connections.get
GET /api/partners/v1/connections/{id}
NK-Key-Id: nkp_sandbox_7f3k9q2m4x8c1v6b
NK-Timestamp: 1791792000
NK-Nonce: <16–64 random bytes, base64url>
Content-Digest: sha-256=:47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=:
NK-Signature: v1=<86 base64url characters, no padding>

Errors

Errors of connections.get
CodeHTTPWhen it happensWhat to do
connection_not_found404Unknown id, or another app's connection.Check the id and the key environment.

scrolls →

Errors on every endpoint (14)
Errors on every endpoint, connections.get
CodeHTTPWhen it happensWhat to do
ingest_disabled503Novi Kvadrat switched ingestion off.Retry later with backoff.
body_too_large413The body is over 4 MiB (checked first).Split the batch.
signature_missing401A signing header is absent or malformed.Send all five headers.
key_invalid401Unknown or revoked key.Register a new key.
key_expired401The key is past its 365 days.Register a new key.
app_suspended403Staff suspended the app.Write to partners@novikvadrat.rs.
account_blocked403Staff suspended or archived the organization.Write to partners@novikvadrat.rs.
ip_allowlist_empty403A live app without addresses.Edit the allowlist.
ip_not_allowed403The caller is not listed, or its address can't be determined.Edit the allowlist.
digest_mismatch400The body changed after hashing.Hash the exact bytes you send.
timestamp_out_of_window401The clock is off by more than 300 s.Sync the clock (NTP).
signature_invalid401The base string or the key does not match.Compare with the test vector.
nonce_reused401A nonce sent twice within 15 minutes.A fresh random nonce per request.
rate_limited429Over the per-minute budget (replays count too).Wait Retry-After.

scrolls →

DELETE/connections/{id}

Disconnect: the listings are released to the agency.

Signed request; five headers

Parameters

Parameters of connections.revoke
NameInTypeRequiredDescription
idpathstring (uuid)YesThe connection id.
reasonquerystringNo

scrolls →

Responses

200 OK.

Unknown fields are rejected.

Response 200 of connections.revoke
FieldTypeRequiredConstraintsDescription
connectionobjectYes—Unknown fields are rejected.
connection.idstring (uuid)Yes—
connection.statusstring (enum)certifyingactivepausedrevokedYes—
connection.environmentstring (enum)sandboxliveYes—
connection.agencyobjectYes—Unknown fields are rejected.
connection.agency.namestringYes—
connection.agency.register_numberstring | nullYes—
connection.agency.verification_statusstring (enum)unverifiedpendingverifiedrejectedYes—
connection.agency.listing_quotaobjectYes—Unknown fields are rejected.
connection.agency.listing_quota.usedintegerYes≥ 0 · ≤ 9007199254740991
connection.agency.listing_quota.limitinteger | nullYes≥ -9007199254740991 · ≤ 9007199254740991
connection.agency.photo_limitintegerYes≥ 0 · ≤ 9007199254740991
connection.created_atstringYes—
connection.redeemed_atstring | nullYes—
connection.certified_atstring | nullYes—
connection.pausedobject | nullYes—Unknown fields are rejected.
connection.paused.atstringYes—
connection.paused.bystring (enum)agencystaffYes—
connection.paused.reasonstring | nullYes—
connection.countsobjectYes—Unknown fields are rejected.
connection.counts.liveintegerYes≥ 0 · ≤ 9007199254740991
connection.counts.pausedintegerYes≥ 0 · ≤ 9007199254740991
connection.counts.reviewintegerYes≥ 0 · ≤ 9007199254740991
connection.counts.failedintegerYes≥ 0 · ≤ 9007199254740991
connection.last_push_atstring | nullYes—

scrolls →

  • 404 connection_not_found: Unknown id, or another app's connection. The body is the error envelope.
  • 422 validation_failed: The payload is invalid (details array). The body is the error envelope.

Examples

Request · connections.revoke
DELETE /api/partners/v1/connections/{id}
NK-Key-Id: nkp_sandbox_7f3k9q2m4x8c1v6b
NK-Timestamp: 1791792000
NK-Nonce: <16–64 random bytes, base64url>
Content-Digest: sha-256=:47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=:
NK-Signature: v1=<86 base64url characters, no padding>

Errors

Errors of connections.revoke
CodeHTTPWhen it happensWhat to do
connection_not_found404Unknown id, or another app's connection.Check the id and the key environment.
validation_failed422The payload is invalid (details array).Fix the fields at the pointers.

scrolls →

Errors on every endpoint (14)
Errors on every endpoint, connections.revoke
CodeHTTPWhen it happensWhat to do
ingest_disabled503Novi Kvadrat switched ingestion off.Retry later with backoff.
body_too_large413The body is over 4 MiB (checked first).Split the batch.
signature_missing401A signing header is absent or malformed.Send all five headers.
key_invalid401Unknown or revoked key.Register a new key.
key_expired401The key is past its 365 days.Register a new key.
app_suspended403Staff suspended the app.Write to partners@novikvadrat.rs.
account_blocked403Staff suspended or archived the organization.Write to partners@novikvadrat.rs.
ip_allowlist_empty403A live app without addresses.Edit the allowlist.
ip_not_allowed403The caller is not listed, or its address can't be determined.Edit the allowlist.
digest_mismatch400The body changed after hashing.Hash the exact bytes you send.
timestamp_out_of_window401The clock is off by more than 300 s.Sync the clock (NTP).
signature_invalid401The base string or the key does not match.Compare with the test vector.
nonce_reused401A nonce sent twice within 15 minutes.A fresh random nonce per request.
rate_limited429Over the per-minute budget (replays count too).Wait Retry-After.

scrolls →

Detail codes

Detail codes of connections.revoke
Detail codeMeaningExample pointer
unknown_fieldA key the schema doesn't know./structure/balcon
requiredA required field is missing./title/sr
invalid_typeThe wrong JSON type./structure/rooms
too_smallBelow a minimum (length or value)./description/sr
too_bigAbove a maximum (length or value)./price/amount
invalid_enumA value outside the vocabulary./structure/heating
invalid_formatA malformed id, URL, date or pattern./photos/0/url

scrolls →

Listings

PUT/connections/{id}/listings/{external_id}

Create or fully replace one listing.

Signed request; five headers

Parameters

Parameters of listings.put
NameInTypeRequiredDescription
idpathstring (uuid)YesThe connection id.
external_idpathstring, pattern ^[A-Za-z0-9._:-]{1,64}$YesYour listing id (the payload’s external_id).

scrolls →

Request body

One listing; transaction picks the sale or the rent shape. Text lengths count Unicode code points, as maxLength does; titles are ALSO capped at 120 UTF-16 units (an emoji counts as two). A sale price is refused (too_big) when amount × 117 (rounded, for EUR) would exceed 2,147,483,647 RSD (about 18,354,561 EUR). state: active needs legal.mandate_attested: true. See https://developers.novikvadrat.rs/docs/listings/payload-v1.

Unknown fields are rejected.

Request body of listings.put
FieldTypeRequiredConstraintsDescription
external_idstringYesmin length 1 · max length 64 · pattern ^[A-Za-z0-9._:-]*$
categorystring (enum)apartmentstudiopenthouseduplexlofthousehouse_semi_detachedtownhouseYes—
statestring (enum)activeinactiveYes—
titleobjectYes—Unknown fields are rejected.
title.srstringYesmin length 5 · max length 120
title.enstring | nullNomax length 120
title.trstring | nullNomax length 120
title.destring | nullNomax length 120
title.rustring | nullNomax length 120
descriptionobjectYes—Unknown fields are rejected.
description.srstringYesmin length 20 · max length 8000
description.enstring | nullNomax length 8000
description.trstring | nullNomax length 8000
description.destring | nullNomax length 8000
description.rustring | nullNomax length 8000
locationobjectYes—Unknown fields are rejected.
location.place_idstring (uuid)Yes—
location.address_linestringYesmin length 3 · max length 200
location.neighbourhoodstring | nullNomax length 120
location.latnumber | nullNo≥ -90 · ≤ 90
location.lngnumber | nullNo≥ -180 · ≤ 180
amenitiesarray of string (enum) | nullloggiafrench_balconywalk_in_closetbuilt_in_wardrobesunderfloor_heatingfireplacelaundry_roomsoundproofingNomax items 40
attributesmap of any | nullNo—
photosarray of object | nullNomax items 64
photos[].urlstringYesmax length 2048
photos[].captionstring | nullNomax length 500
photos[].room_typestring (enum) | nullexteriorliving_roomkitchenbedroombathroombalconyhallwayviewNo—
photos[].digeststring | nullNopattern ^[0-9a-f]{64}$
video_urlstring | nullNomax length 2048
virtual_tour_urlstring | nullNomax length 2048
agentobject | nullNo—Unknown fields are rejected.
agent.emailstring (email)Yesmax length 254
agent.namestring | nullNomax length 120
agent.phonestring | nullNomax length 32
sourceobjectYes—Unknown fields are rejected.
source.updated_atstring (date-time)Yes—
source.urlstring | nullNomax length 2048
digeststring | nullNomax length 128
transactionstring (enum)salerentYes—
priceobjectsale only—Unknown fields are rejected.
price.amountnumbersale only> 0 · ≤ 9999999999
price.currencystring (enum)EURRSDsale only—
price.negotiableboolean | nullsale only—
structureobjectYes—Unknown fields are rejected.
structure.area_sqmnumber | nullNo> 0 · ≤ 99999.99
structure.bedroomsnumber | nullNo≥ 0 · ≤ 99
structure.bathroomsnumber | nullNo≥ 0 · ≤ 99
structure.floorinteger | nullNo≥ -5 · ≤ 60
structure.levelsinteger | nullNo≥ 1 · ≤ 6
structure.furnishedstring (enum) | nullfurnishedsemi_furnishedunfurnishedNo—
structure.elevatorboolean | nullNo—
structure.parkingboolean | nullNo—
structure.balconyboolean | nullNo—
structure.terraceboolean | nullNo—
structure.air_conditioningboolean | nullNo—
structure.heatingstring (enum) | nulldistrictgas_centralgas_localelectric_localstorage_heaterelectric_panelheat_pumpair_conditioningNo—
structure.roomsnumber | nullsale only≥ 0 · ≤ 99
structure.total_floorsinteger | nullsale only≥ 0 · ≤ 60
structure.year_builtinteger | nullsale only≥ 1800 · ≤ 2035
structure.building_groupstring (enum) | nullnewoldsale only—
structure.conditionstring (enum) | nullluxrenovatedoriginalrenovation_requiredsale only—
structure.garageboolean | nullsale only—
structure.basementboolean | nullsale only—
legalobjectYes—Unknown fields are rejected.
legal.ownership_statusstring (enum) | nulluknjizennije_uknjizenu_postupkusale only—
legal.legalization_statusstring (enum) | nulllegalizovanu_postupkunelegalizovansale only—
legal.mortgage_eligibleboolean | nullsale only—
legal.mandate_attestedbooleanYes—
legal.exclusiveboolean | nullsale only—
legal.broker_license_nostring | nullsale onlymax length 64
legal.tapija_notestring | nullsale onlymax length 500
commissionobject | nullNo—Unknown fields are rejected.
commission.buyer_pctnumber | nullsale only≥ 0 · ≤ 100
commission.seller_pctnumber | nullsale only≥ 0 · ≤ 100
commission.landlord_pctnumber | nullrent only≥ 0 · ≤ 100
commission.agency_fee_pctnumber | nullrent only≥ 0 · ≤ 100
rentobjectrent only—Unknown fields are rejected.
rent.amountnumberrent only≥ 1 · ≤ 10000000
rent.currencystring (enum)EURRSDrent only—
rent.typestring (enum)long_termmid_termshort_termroomrent only—
rent.deposit_monthsnumber | nullrent only≥ 0 · ≤ 12
rent.min_lease_monthsinteger | nullrent only≥ 0 · ≤ 120
rent.max_lease_monthsinteger | nullrent only≥ 0 · ≤ 120
rent.available_fromstring (date) | nullrent only—
rent.utilities_includedmap of boolean | nullrent only—
rent.utilities_estimate_rsdinteger | nullrent only≥ 0 · ≤ 100000000
rent.owner_lives_nearbyboolean | nullrent only—
rent.owner_proximitystring (enum) | nullsame_apartmentsame_floorupstairsdownstairssame_buildingsame_streetwalking_distancerent only—
rent.max_occupantsinteger | nullrent only≥ 1 · ≤ 20
house_rulesobjectrent only—Unknown fields are rejected.
house_rules.petsobjectrent only—Unknown fields are rejected.
house_rules.pets.policystring (enum)allowedon_requestnot_allowedrent only—
house_rules.pets.kindsarray of string (enum)dogscatssmall_cagedbirdsaquariumrent onlymax items 5
house_rules.pets.dog_sizestring (enum)smallmediumanyrent only—
house_rules.pets.max_countintegerrent only≥ 1 · ≤ 5
house_rules.pets.deposit_eurintegerrent only≥ 0 · ≤ 100000
house_rules.pets.notestringrent onlymax length 200
house_rules.smokingstring (enum)not_allowedbalcony_onlyallowedrent only—
house_rules.guestsstring (enum)allowedask_firstnot_allowedrent only—
house_rules.partiesstring (enum)not_allowedallowedrent only—
house_rules.quiet_hoursstringrent onlymax length 200
house_rules.sublettingstring (enum)not_allowedwith_consentrent only—
house_rules.studentsstring (enum)yesnorent only—
house_rules.familiesstring (enum)yesnorent only—
house_rules.foreign_tenantsstring (enum)welcomeask_firstrent only—
house_rules.registers_residencebooleanrent only—
house_rules.otherstringrent onlymax length 500

scrolls →

Responses

202 Accepted.

Unknown fields are rejected.

Response 202 of listings.put
FieldTypeRequiredConstraintsDescription
itemobjectYes—Unknown fields are rejected.
item.positionintegerYes≥ 0 · ≤ 9007199254740991
item.external_idstringYes—
item.resultstring (enum)acceptedunchangedneeds_reviewrejectedremovedYes—
item.candidate_idstring (uuid) | nullYes—
item.listing_idstring (uuid) | nullYes—
item.public_urlstring | nullYes—
item.failure_codestring (enum) | nullunmappable_categorymissing_requiredinvalid_payloadquota_exceededduplicategeo_unresolvedschema_invalidphoto_fetch_failedYes—
item.detailsarray of object | map of any | nullYes—
item.warningsarray of objectYes—
item.warnings[].codestring (enum)agent_not_membervirtual_tour_droppedcommission_droppedfield_not_applicablecoordinates_outside_placephoto_cap_appliedYes—
item.warnings[].pointerstringNo—
item.warnings[].messagestringYes—

scrolls →

  • 400 body_invalid: The body is not a JSON object. The body is the error envelope.
  • 404 connection_not_found: Unknown id, or another app's connection. The body is the error envelope.
  • 409 connection_not_active: details.status is pending, paused or revoked. The body is the error envelope.
  • 422 validation_failed: The payload is invalid (details array). The body is the error envelope.
  • 429 connection_item_limit: Over the hourly item budget. The body is the error envelope.

Examples

Request · listings.put
PUT /api/partners/v1/connections/{id}/listings/{external_id}
NK-Key-Id: nkp_sandbox_7f3k9q2m4x8c1v6b
NK-Timestamp: 1791792000
NK-Nonce: <16–64 random bytes, base64url>
Content-Digest: sha-256=:<base64 SHA-256 of the exact body bytes>:
NK-Signature: v1=<86 base64url characters, no padding>
Content-Type: application/json

{
  "external_id": "REAA-12345",
  "transaction": "sale",
  "category": "apartment",
  "state": "active",
  "title": {
    "sr": "Trosoban stan, Vračar",
    "en": "Three-room flat, Vračar"
  },
  "description": {
    "sr": "Svetao trosoban stan na Vračaru, renoviran 2024, na pet minuta od Hrama Svetog Save.",
    "en": "A bright three-room flat in Vračar, renovated in 2024, five minutes from the Temple of Saint Sava."
  },
  "price": {
    "amount": 245000,
    "currency": "EUR",
    "negotiable": false
  },
  "location": {
    "place_id": "b2c0d6a4-3f1e-4d2a-9c8b-7e6f5a4b3c2d",
    "address_line": "Njegoševa 10",
    "neighbourhood": "Crveni krst",
    "lat": 44.8012,
    "lng": 20.4722
  },
  "structure": {
    "area_sqm": 78.5,
    "rooms": 3,
    "bedrooms": 2,
    "bathrooms": 1,
    "floor": 3,
    "total_floors": 5,
    "levels": 1,
    "year_built": 1968,
    "building_group": "old",
    "condition": "renovated",
    "furnished": "semi_furnished",
    "heating": "district",
    "elevator": true,
    "parking": false,
    "garage": false,
    "balcony": true,
    "terrace": false,
    "air_conditioning": true,
    "basement": false
  },
  "legal": {
    "ownership_status": "uknjizen",
    "legalization_status": "legalizovan",
    "mortgage_eligible": true,
    "mandate_attested": true,
    "exclusive": false,
    "broker_license_no": null,
    "tapija_note": null
  },
  "commission": {
    "buyer_pct": 2,
    "seller_pct": 2
  },
  "amenities": [
    "built_in_wardrobes",
    "intercom"
  ],
  "attributes": {},
  "photos": [
    {
      "url": "https://cdn.reaa.rs/listings/12345/1.jpg",
      "caption": null,
      "room_type": "living_room",
      "digest": null
    },
    {
      "url": "https://cdn.reaa.rs/listings/12345/2.jpg",
      "caption": null,
      "room_type": "kitchen",
      "digest": null
    },
    {
      "url": "https://cdn.reaa.rs/listings/12345/3.jpg",
      "caption": null,
      "room_type": "bedroom",
      "digest": null
    }
  ],
  "video_url": null,
  "virtual_tour_url": null,
  "agent": {
    "email": "milan@agencija.rs",
    "name": "Milan Petrović",
    "phone": "+381601234567"
  },
  "source": {
    "updated_at": "2026-10-12T08:00:00Z",
    "url": "https://agencija.rs/nekretnine/12345"
  },
  "digest": null
}

Errors

Errors of listings.put
CodeHTTPWhen it happensWhat to do
body_invalid400The body is not a JSON object.Send valid JSON.
connection_not_found404Unknown id, or another app's connection.Check the id and the key environment.
connection_not_active409details.status is pending, paused or revoked.Wait for the agency, or stop pushing.
validation_failed422The payload is invalid (details array).Fix the fields at the pointers.
connection_item_limit429Over the hourly item budget.Wait Retry-After, spread pushes.

scrolls →

Errors on every endpoint (14)
Errors on every endpoint, listings.put
CodeHTTPWhen it happensWhat to do
ingest_disabled503Novi Kvadrat switched ingestion off.Retry later with backoff.
body_too_large413The body is over 4 MiB (checked first).Split the batch.
signature_missing401A signing header is absent or malformed.Send all five headers.
key_invalid401Unknown or revoked key.Register a new key.
key_expired401The key is past its 365 days.Register a new key.
app_suspended403Staff suspended the app.Write to partners@novikvadrat.rs.
account_blocked403Staff suspended or archived the organization.Write to partners@novikvadrat.rs.
ip_allowlist_empty403A live app without addresses.Edit the allowlist.
ip_not_allowed403The caller is not listed, or its address can't be determined.Edit the allowlist.
digest_mismatch400The body changed after hashing.Hash the exact bytes you send.
timestamp_out_of_window401The clock is off by more than 300 s.Sync the clock (NTP).
signature_invalid401The base string or the key does not match.Compare with the test vector.
nonce_reused401A nonce sent twice within 15 minutes.A fresh random nonce per request.
rate_limited429Over the per-minute budget (replays count too).Wait Retry-After.

scrolls →

Detail codes

Detail codes of listings.put
Detail codeMeaningExample pointer
unknown_fieldA key the schema doesn't know./structure/balcon
requiredA required field is missing./title/sr
invalid_typeThe wrong JSON type./structure/rooms
too_smallBelow a minimum (length or value)./description/sr
too_bigAbove a maximum (length or value)./price/amount
invalid_enumA value outside the vocabulary./structure/heating
invalid_formatA malformed id, URL, date or pattern./photos/0/url
unknown_placeplace_id is not a city or municipality we know./location/place_id
duplicate_external_idOne external_id twice in one batch./listings/3/external_id
duplicate_photo_urlOne photo URL listed twice./photos/2/url

scrolls →

Warnings of listings.put
WarningMeaningExample pointer
agent_not_memberagent.email is not an active member of the agency; the listing has no agent./agent/email
virtual_tour_droppedThe agency's plan has no virtual tours; the URL was not stored./virtual_tour_url
commission_droppedThe agency is a bank; commission was not stored./commission
field_not_applicableA field that does not apply to the category was not stored./structure/floor
coordinates_outside_placeThe coordinates fall outside the place's boundary (kept)./location
photo_cap_appliedMore photos than the agency's plan allows; the extra ones were dropped./photos

scrolls →

POST/connections/{id}/listings/{external_id}/remove

Remove a listing (sold, rented, withdrawn, expired, error).

Signed request; five headers

Parameters

Parameters of listings.remove
NameInTypeRequiredDescription
idpathstring (uuid)YesThe connection id.
external_idpathstring, pattern ^[A-Za-z0-9._:-]{1,64}$YesYour listing id (the payload’s external_id).

scrolls →

Request body

Unknown fields are rejected.

Request body of listings.remove
FieldTypeRequiredConstraintsDescription
reasonstring (enum)soldrentedwithdrawnexpirederrorYes—

scrolls →

Responses

200 OK.

Unknown fields are rejected.

Response 200 of listings.remove
FieldTypeRequiredConstraintsDescription
itemobjectYes—Unknown fields are rejected.
item.positionintegerYes≥ 0 · ≤ 9007199254740991
item.external_idstringYes—
item.resultstring (enum)acceptedunchangedneeds_reviewrejectedremovedYes—
item.candidate_idstring (uuid) | nullYes—
item.listing_idstring (uuid) | nullYes—
item.public_urlstring | nullYes—
item.failure_codestring (enum) | nullunmappable_categorymissing_requiredinvalid_payloadquota_exceededduplicategeo_unresolvedschema_invalidphoto_fetch_failedYes—
item.detailsarray of object | map of any | nullYes—
item.warningsarray of objectYes—
item.warnings[].codestring (enum)agent_not_membervirtual_tour_droppedcommission_droppedfield_not_applicablecoordinates_outside_placephoto_cap_appliedYes—
item.warnings[].pointerstringNo—
item.warnings[].messagestringYes—

scrolls →

  • 400 body_invalid: The body is not a JSON object. The body is the error envelope.
  • 404 connection_not_found: Unknown id, or another app's connection. listing_not_found: No staged listing with that external_id on this connection. The body is the error envelope.
  • 409 connection_not_active: details.status is pending, paused or revoked. The body is the error envelope.
  • 422 validation_failed: The payload is invalid (details array). The body is the error envelope.

Examples

Request · listings.remove
POST /api/partners/v1/connections/{id}/listings/{external_id}/remove
NK-Key-Id: nkp_sandbox_7f3k9q2m4x8c1v6b
NK-Timestamp: 1791792000
NK-Nonce: <16–64 random bytes, base64url>
Content-Digest: sha-256=:<base64 SHA-256 of the exact body bytes>:
NK-Signature: v1=<86 base64url characters, no padding>
Content-Type: application/json

{
  "reason": "sold"
}

Errors

Errors of listings.remove
CodeHTTPWhen it happensWhat to do
body_invalid400The body is not a JSON object.Send valid JSON.
connection_not_found404Unknown id, or another app's connection.Check the id and the key environment.
listing_not_found404No staged listing with that external_id on this connection.—
connection_not_active409details.status is pending, paused or revoked.Wait for the agency, or stop pushing.
validation_failed422The payload is invalid (details array).Fix the fields at the pointers.

scrolls →

Errors on every endpoint (14)
Errors on every endpoint, listings.remove
CodeHTTPWhen it happensWhat to do
ingest_disabled503Novi Kvadrat switched ingestion off.Retry later with backoff.
body_too_large413The body is over 4 MiB (checked first).Split the batch.
signature_missing401A signing header is absent or malformed.Send all five headers.
key_invalid401Unknown or revoked key.Register a new key.
key_expired401The key is past its 365 days.Register a new key.
app_suspended403Staff suspended the app.Write to partners@novikvadrat.rs.
account_blocked403Staff suspended or archived the organization.Write to partners@novikvadrat.rs.
ip_allowlist_empty403A live app without addresses.Edit the allowlist.
ip_not_allowed403The caller is not listed, or its address can't be determined.Edit the allowlist.
digest_mismatch400The body changed after hashing.Hash the exact bytes you send.
timestamp_out_of_window401The clock is off by more than 300 s.Sync the clock (NTP).
signature_invalid401The base string or the key does not match.Compare with the test vector.
nonce_reused401A nonce sent twice within 15 minutes.A fresh random nonce per request.
rate_limited429Over the per-minute budget (replays count too).Wait Retry-After.

scrolls →

Detail codes

Detail codes of listings.remove
Detail codeMeaningExample pointer
unknown_fieldA key the schema doesn't know./structure/balcon
requiredA required field is missing./title/sr
invalid_typeThe wrong JSON type./structure/rooms
too_smallBelow a minimum (length or value)./description/sr
too_bigAbove a maximum (length or value)./price/amount
invalid_enumA value outside the vocabulary./structure/heating
invalid_formatA malformed id, URL, date or pattern./photos/0/url

scrolls →

GET/connections/{id}/listings

The reconcile view: what Novi Kvadrat holds for this connection.

Signed request; five headers

Parameters

Parameters of listings.list
NameInTypeRequiredDescription
idpathstring (uuid)YesThe connection id.
cursorquerystringNo
limitquerystring, pattern ^\d{1,3}$No
statusquerystringNo

scrolls →

Responses

200 OK.

Unknown fields are rejected.

Response 200 of listings.list
FieldTypeRequiredConstraintsDescription
itemsarray of objectYes—
items[].external_idstringYes—
items[].transactionstring (enum) | nullsalerentYes—
items[].statusstring (enum)pendingimportedfailedskippedneeds_reviewremovedvalidatedYes—
items[].listing_statusstring | nullYes—
items[].moderation_statusstring | nullYes—
items[].listing_idstring (uuid) | nullYes—
items[].public_urlstring | nullYes—
items[].payload_digeststring | nullYes—
items[].imported_digeststring | nullYes—
items[].updated_atstring | nullYes—
items[].failure_codestring (enum) | nullunmappable_categorymissing_requiredinvalid_payloadquota_exceededduplicategeo_unresolvedschema_invalidphoto_fetch_failedYes—
next_cursorstring | nullYes—

scrolls →

  • 404 connection_not_found: Unknown id, or another app's connection. The body is the error envelope.
  • 409 connection_not_active: details.status is pending, paused or revoked. The body is the error envelope.
  • 422 validation_failed: The payload is invalid (details array). The body is the error envelope.

Examples

Request · listings.list
GET /api/partners/v1/connections/{id}/listings
NK-Key-Id: nkp_sandbox_7f3k9q2m4x8c1v6b
NK-Timestamp: 1791792000
NK-Nonce: <16–64 random bytes, base64url>
Content-Digest: sha-256=:47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=:
NK-Signature: v1=<86 base64url characters, no padding>

Errors

Errors of listings.list
CodeHTTPWhen it happensWhat to do
connection_not_found404Unknown id, or another app's connection.Check the id and the key environment.
connection_not_active409details.status is pending, paused or revoked.Wait for the agency, or stop pushing.
validation_failed422The payload is invalid (details array).Fix the fields at the pointers.

scrolls →

Errors on every endpoint (14)
Errors on every endpoint, listings.list
CodeHTTPWhen it happensWhat to do
ingest_disabled503Novi Kvadrat switched ingestion off.Retry later with backoff.
body_too_large413The body is over 4 MiB (checked first).Split the batch.
signature_missing401A signing header is absent or malformed.Send all five headers.
key_invalid401Unknown or revoked key.Register a new key.
key_expired401The key is past its 365 days.Register a new key.
app_suspended403Staff suspended the app.Write to partners@novikvadrat.rs.
account_blocked403Staff suspended or archived the organization.Write to partners@novikvadrat.rs.
ip_allowlist_empty403A live app without addresses.Edit the allowlist.
ip_not_allowed403The caller is not listed, or its address can't be determined.Edit the allowlist.
digest_mismatch400The body changed after hashing.Hash the exact bytes you send.
timestamp_out_of_window401The clock is off by more than 300 s.Sync the clock (NTP).
signature_invalid401The base string or the key does not match.Compare with the test vector.
nonce_reused401A nonce sent twice within 15 minutes.A fresh random nonce per request.
rate_limited429Over the per-minute budget (replays count too).Wait Retry-After.

scrolls →

Detail codes

Detail codes of listings.list
Detail codeMeaningExample pointer
unknown_fieldA key the schema doesn't know./structure/balcon
requiredA required field is missing./title/sr
invalid_typeThe wrong JSON type./structure/rooms
too_smallBelow a minimum (length or value)./description/sr
too_bigAbove a maximum (length or value)./price/amount
invalid_enumA value outside the vocabulary./structure/heating
invalid_formatA malformed id, URL, date or pattern./photos/0/url

scrolls →

POST/connections/{id}/reconcile

Archive everything live that is not in the list.

Signed request; five headers

Parameters

Parameters of reconcile
NameInTypeRequiredDescription
Idempotency-Keyheaderstring, pattern ^[\x21-\x7e]{8,128}$No8–128 visible ASCII characters (no spaces); any other value → 422 `validation_failed`. Same key and same body → the stored outcome (`Idempotent-Replayed: true`); while the first runs → 409 `idempotency_in_progress`; another body → 422 `idempotency_key_reused`; forgotten after 7 days.
idpathstring (uuid)YesThe connection id.

scrolls →

Request body

Unknown fields are rejected.

Request body of reconcile
FieldTypeRequiredConstraintsDescription
external_idsarray of stringYes—
confirm_mass_removalbooleanNo—

scrolls →

Responses

202 Accepted.

Unknown fields are rejected.

Response 202 of reconcile
FieldTypeRequiredConstraintsDescription
batchobjectYes—Unknown fields are rejected.
batch.idstring (uuid)Yes—
batch.kindstring (enum)reconcileYes—
batch.to_removeintegerYes≥ 0 · ≤ 9007199254740991
batch.removed_queuedintegerYes≥ 0 · ≤ 9007199254740991

scrolls →

  • 400 body_invalid: The body is not a JSON object. The body is the error envelope.
  • 404 connection_not_found: Unknown id, or another app's connection. The body is the error envelope.
  • 409 connection_not_active: details.status is pending, paused or revoked. mass_removal_requires_confirmation: A reconcile would remove too much. idempotency_in_progress: The same key while the first request runs (details.batch_id). The body is the error envelope.
  • 422 batch_too_large: More than max_batch_items, more than 50 to validate, or more than 5,000 reconcile ids. idempotency_key_reused: The same key with a different body, within 7 days. validation_failed: The payload is invalid (details array). The body is the error envelope.

Examples

Request · reconcile
POST /api/partners/v1/connections/{id}/reconcile
NK-Key-Id: nkp_sandbox_7f3k9q2m4x8c1v6b
NK-Timestamp: 1791792000
NK-Nonce: <16–64 random bytes, base64url>
Content-Digest: sha-256=:<base64 SHA-256 of the exact body bytes>:
NK-Signature: v1=<86 base64url characters, no padding>
Content-Type: application/json

{
  "external_ids": [
    "REAA-12345",
    "REAA-12346"
  ]
}

Errors

Errors of reconcile
CodeHTTPWhen it happensWhat to do
body_invalid400The body is not a JSON object.Send valid JSON.
connection_not_found404Unknown id, or another app's connection.Check the id and the key environment.
connection_not_active409details.status is pending, paused or revoked.Wait for the agency, or stop pushing.
idempotency_in_progress409The same key while the first request runs (details.batch_id).Poll the batch.
mass_removal_requires_confirmation409A reconcile would remove too much.Check, then confirm.
validation_failed422The payload is invalid (details array).Fix the fields at the pointers.
batch_too_large422More than max_batch_items, more than 50 to validate, or more than 5,000 reconcile ids.Split.
idempotency_key_reused422The same key with a different body, within 7 days.A new key per distinct body.

scrolls →

Errors on every endpoint (14)
Errors on every endpoint, reconcile
CodeHTTPWhen it happensWhat to do
ingest_disabled503Novi Kvadrat switched ingestion off.Retry later with backoff.
body_too_large413The body is over 4 MiB (checked first).Split the batch.
signature_missing401A signing header is absent or malformed.Send all five headers.
key_invalid401Unknown or revoked key.Register a new key.
key_expired401The key is past its 365 days.Register a new key.
app_suspended403Staff suspended the app.Write to partners@novikvadrat.rs.
account_blocked403Staff suspended or archived the organization.Write to partners@novikvadrat.rs.
ip_allowlist_empty403A live app without addresses.Edit the allowlist.
ip_not_allowed403The caller is not listed, or its address can't be determined.Edit the allowlist.
digest_mismatch400The body changed after hashing.Hash the exact bytes you send.
timestamp_out_of_window401The clock is off by more than 300 s.Sync the clock (NTP).
signature_invalid401The base string or the key does not match.Compare with the test vector.
nonce_reused401A nonce sent twice within 15 minutes.A fresh random nonce per request.
rate_limited429Over the per-minute budget (replays count too).Wait Retry-After.

scrolls →

Detail codes

Detail codes of reconcile
Detail codeMeaningExample pointer
unknown_fieldA key the schema doesn't know./structure/balcon
requiredA required field is missing./title/sr
invalid_typeThe wrong JSON type./structure/rooms
too_smallBelow a minimum (length or value)./description/sr
too_bigAbove a maximum (length or value)./price/amount
invalid_enumA value outside the vocabulary./structure/heating
invalid_formatA malformed id, URL, date or pattern./photos/0/url

scrolls →

Batches

POST/connections/{id}/batches

Up to max_batch_items upserts in one call.

Signed request; five headers

Parameters

Parameters of batches.create
NameInTypeRequiredDescription
Idempotency-Keyheaderstring, pattern ^[\x21-\x7e]{8,128}$No8–128 visible ASCII characters (no spaces); any other value → 422 `validation_failed`. Same key and same body → the stored outcome (`Idempotent-Replayed: true`); while the first runs → 409 `idempotency_in_progress`; another body → 422 `idempotency_key_reused`; forgotten after 7 days.
idpathstring (uuid)YesThe connection id.

scrolls →

Request body

Unknown fields are rejected.

Request body of batches.create
FieldTypeRequiredConstraintsDescription
listingsarray of objectYesmin items 1
listings[].external_idstringYesmin length 1 · max length 64 · pattern ^[A-Za-z0-9._:-]*$
listings[].categorystring (enum)apartmentstudiopenthouseduplexlofthousehouse_semi_detachedtownhouseYes—
listings[].statestring (enum)activeinactiveYes—
listings[].titleobjectYes—Unknown fields are rejected.
listings[].title.srstringYesmin length 5 · max length 120
listings[].title.enstring | nullNomax length 120
listings[].title.trstring | nullNomax length 120
listings[].title.destring | nullNomax length 120
listings[].title.rustring | nullNomax length 120
listings[].descriptionobjectYes—Unknown fields are rejected.
listings[].description.srstringYesmin length 20 · max length 8000
listings[].description.enstring | nullNomax length 8000
listings[].description.trstring | nullNomax length 8000
listings[].description.destring | nullNomax length 8000
listings[].description.rustring | nullNomax length 8000
listings[].locationobjectYes—Unknown fields are rejected.
listings[].location.place_idstring (uuid)Yes—
listings[].location.address_linestringYesmin length 3 · max length 200
listings[].location.neighbourhoodstring | nullNomax length 120
listings[].location.latnumber | nullNo≥ -90 · ≤ 90
listings[].location.lngnumber | nullNo≥ -180 · ≤ 180
listings[].amenitiesarray of string (enum) | nullloggiafrench_balconywalk_in_closetbuilt_in_wardrobesunderfloor_heatingfireplacelaundry_roomsoundproofingNomax items 40
listings[].attributesmap of any | nullNo—
listings[].photosarray of object | nullNomax items 64
listings[].photos[].urlstringYesmax length 2048
listings[].photos[].captionstring | nullNomax length 500
listings[].photos[].room_typestring (enum) | nullexteriorliving_roomkitchenbedroombathroombalconyhallwayviewNo—
listings[].photos[].digeststring | nullNopattern ^[0-9a-f]{64}$
listings[].video_urlstring | nullNomax length 2048
listings[].virtual_tour_urlstring | nullNomax length 2048
listings[].agentobject | nullNo—Unknown fields are rejected.
listings[].agent.emailstring (email)Yesmax length 254
listings[].agent.namestring | nullNomax length 120
listings[].agent.phonestring | nullNomax length 32
listings[].sourceobjectYes—Unknown fields are rejected.
listings[].source.updated_atstring (date-time)Yes—
listings[].source.urlstring | nullNomax length 2048
listings[].digeststring | nullNomax length 128
listings[].transactionstring (enum)salerentYes—
listings[].priceobjectsale only—Unknown fields are rejected.
listings[].price.amountnumbersale only> 0 · ≤ 9999999999
listings[].price.currencystring (enum)EURRSDsale only—
listings[].price.negotiableboolean | nullsale only—
listings[].structureobjectYes—Unknown fields are rejected.
listings[].structure.area_sqmnumber | nullNo> 0 · ≤ 99999.99
listings[].structure.bedroomsnumber | nullNo≥ 0 · ≤ 99
listings[].structure.bathroomsnumber | nullNo≥ 0 · ≤ 99
listings[].structure.floorinteger | nullNo≥ -5 · ≤ 60
listings[].structure.levelsinteger | nullNo≥ 1 · ≤ 6
listings[].structure.furnishedstring (enum) | nullfurnishedsemi_furnishedunfurnishedNo—
listings[].structure.elevatorboolean | nullNo—
listings[].structure.parkingboolean | nullNo—
listings[].structure.balconyboolean | nullNo—
listings[].structure.terraceboolean | nullNo—
listings[].structure.air_conditioningboolean | nullNo—
listings[].structure.heatingstring (enum) | nulldistrictgas_centralgas_localelectric_localstorage_heaterelectric_panelheat_pumpair_conditioningNo—
listings[].structure.roomsnumber | nullsale only≥ 0 · ≤ 99
listings[].structure.total_floorsinteger | nullsale only≥ 0 · ≤ 60
listings[].structure.year_builtinteger | nullsale only≥ 1800 · ≤ 2035
listings[].structure.building_groupstring (enum) | nullnewoldsale only—
listings[].structure.conditionstring (enum) | nullluxrenovatedoriginalrenovation_requiredsale only—
listings[].structure.garageboolean | nullsale only—
listings[].structure.basementboolean | nullsale only—
listings[].legalobjectYes—Unknown fields are rejected.
listings[].legal.ownership_statusstring (enum) | nulluknjizennije_uknjizenu_postupkusale only—
listings[].legal.legalization_statusstring (enum) | nulllegalizovanu_postupkunelegalizovansale only—
listings[].legal.mortgage_eligibleboolean | nullsale only—
listings[].legal.mandate_attestedbooleanYes—
listings[].legal.exclusiveboolean | nullsale only—
listings[].legal.broker_license_nostring | nullsale onlymax length 64
listings[].legal.tapija_notestring | nullsale onlymax length 500
listings[].commissionobject | nullNo—Unknown fields are rejected.
listings[].commission.buyer_pctnumber | nullsale only≥ 0 · ≤ 100
listings[].commission.seller_pctnumber | nullsale only≥ 0 · ≤ 100
listings[].commission.landlord_pctnumber | nullrent only≥ 0 · ≤ 100
listings[].commission.agency_fee_pctnumber | nullrent only≥ 0 · ≤ 100
listings[].rentobjectrent only—Unknown fields are rejected.
listings[].rent.amountnumberrent only≥ 1 · ≤ 10000000
listings[].rent.currencystring (enum)EURRSDrent only—
listings[].rent.typestring (enum)long_termmid_termshort_termroomrent only—
listings[].rent.deposit_monthsnumber | nullrent only≥ 0 · ≤ 12
listings[].rent.min_lease_monthsinteger | nullrent only≥ 0 · ≤ 120
listings[].rent.max_lease_monthsinteger | nullrent only≥ 0 · ≤ 120
listings[].rent.available_fromstring (date) | nullrent only—
listings[].rent.utilities_includedmap of boolean | nullrent only—
listings[].rent.utilities_estimate_rsdinteger | nullrent only≥ 0 · ≤ 100000000
listings[].rent.owner_lives_nearbyboolean | nullrent only—
listings[].rent.owner_proximitystring (enum) | nullsame_apartmentsame_floorupstairsdownstairssame_buildingsame_streetwalking_distancerent only—
listings[].rent.max_occupantsinteger | nullrent only≥ 1 · ≤ 20
listings[].house_rulesobjectrent only—Unknown fields are rejected.
listings[].house_rules.petsobjectrent only—Unknown fields are rejected.
listings[].house_rules.pets.policystring (enum)allowedon_requestnot_allowedrent only—
listings[].house_rules.pets.kindsarray of string (enum)dogscatssmall_cagedbirdsaquariumrent onlymax items 5
listings[].house_rules.pets.dog_sizestring (enum)smallmediumanyrent only—
listings[].house_rules.pets.max_countintegerrent only≥ 1 · ≤ 5
listings[].house_rules.pets.deposit_eurintegerrent only≥ 0 · ≤ 100000
listings[].house_rules.pets.notestringrent onlymax length 200
listings[].house_rules.smokingstring (enum)not_allowedbalcony_onlyallowedrent only—
listings[].house_rules.guestsstring (enum)allowedask_firstnot_allowedrent only—
listings[].house_rules.partiesstring (enum)not_allowedallowedrent only—
listings[].house_rules.quiet_hoursstringrent onlymax length 200
listings[].house_rules.sublettingstring (enum)not_allowedwith_consentrent only—
listings[].house_rules.studentsstring (enum)yesnorent only—
listings[].house_rules.familiesstring (enum)yesnorent only—
listings[].house_rules.foreign_tenantsstring (enum)welcomeask_firstrent only—
listings[].house_rules.registers_residencebooleanrent only—
listings[].house_rules.otherstringrent onlymax length 500

scrolls →

Responses

202 Accepted.

Unknown fields are rejected.

Response 202 of batches.create
FieldTypeRequiredConstraintsDescription
batchobjectYes—Unknown fields are rejected.
batch.idstring (uuid)Yes—
batch.statusstring (enum)receivedprocessingcompletedfailedYes—
batch.countsobjectYes—Unknown fields are rejected.
batch.counts.acceptedintegerYes≥ -9007199254740991 · ≤ 9007199254740991
batch.counts.unchangedintegerYes≥ -9007199254740991 · ≤ 9007199254740991
batch.counts.needs_reviewintegerYes≥ -9007199254740991 · ≤ 9007199254740991
batch.counts.rejectedintegerYes≥ -9007199254740991 · ≤ 9007199254740991
batch.counts.removedintegerYes≥ -9007199254740991 · ≤ 9007199254740991
batch.counts.totalintegerYes≥ -9007199254740991 · ≤ 9007199254740991
batch.itemsarray of objectYes—
batch.items[].positionintegerYes≥ 0 · ≤ 9007199254740991
batch.items[].external_idstringYes—
batch.items[].resultstring (enum)acceptedunchangedneeds_reviewrejectedremovedYes—
batch.items[].candidate_idstring (uuid) | nullYes—
batch.items[].listing_idstring (uuid) | nullYes—
batch.items[].public_urlstring | nullYes—
batch.items[].failure_codestring (enum) | nullunmappable_categorymissing_requiredinvalid_payloadquota_exceededduplicategeo_unresolvedschema_invalidphoto_fetch_failedYes—
batch.items[].detailsarray of object | map of any | nullYes—
batch.items[].warningsarray of objectYes—
batch.items[].warnings[].codestring (enum)agent_not_membervirtual_tour_droppedcommission_droppedfield_not_applicablecoordinates_outside_placephoto_cap_appliedYes—
batch.items[].warnings[].pointerstringNo—
batch.items[].warnings[].messagestringYes—

scrolls →

  • 400 body_invalid: The body is not a JSON object. The body is the error envelope.
  • 404 connection_not_found: Unknown id, or another app's connection. The body is the error envelope.
  • 409 connection_not_active: details.status is pending, paused or revoked. idempotency_in_progress: The same key while the first request runs (details.batch_id). The body is the error envelope.
  • 422 batch_too_large: More than max_batch_items, more than 50 to validate, or more than 5,000 reconcile ids. idempotency_key_reused: The same key with a different body, within 7 days. duplicate_external_id: One external_id twice in a batch. validation_failed: The payload is invalid (details array). The body is the error envelope.
  • 429 connection_item_limit: Over the hourly item budget. The body is the error envelope.

Examples

Request · batches.create
POST /api/partners/v1/connections/{id}/batches
NK-Key-Id: nkp_sandbox_7f3k9q2m4x8c1v6b
NK-Timestamp: 1791792000
NK-Nonce: <16–64 random bytes, base64url>
Content-Digest: sha-256=:<base64 SHA-256 of the exact body bytes>:
NK-Signature: v1=<86 base64url characters, no padding>
Content-Type: application/json

{
  "listings": [
    {
      "external_id": "REAA-12345",
      "transaction": "sale",
      "category": "apartment",
      "state": "active",
      "title": {
        "sr": "Trosoban stan, Vračar",
        "en": "Three-room flat, Vračar"
      },
      "description": {
        "sr": "Svetao trosoban stan na Vračaru, renoviran 2024, na pet minuta od Hrama Svetog Save.",
        "en": "A bright three-room flat in Vračar, renovated in 2024, five minutes from the Temple of Saint Sava."
      },
      "price": {
        "amount": 245000,
        "currency": "EUR",
        "negotiable": false
      },
      "location": {
        "place_id": "b2c0d6a4-3f1e-4d2a-9c8b-7e6f5a4b3c2d",
        "address_line": "Njegoševa 10",
        "neighbourhood": "Crveni krst",
        "lat": 44.8012,
        "lng": 20.4722
      },
      "structure": {
        "area_sqm": 78.5,
        "rooms": 3,
        "bedrooms": 2,
        "bathrooms": 1,
        "floor": 3,
        "total_floors": 5,
        "levels": 1,
        "year_built": 1968,
        "building_group": "old",
        "condition": "renovated",
        "furnished": "semi_furnished",
        "heating": "district",
        "elevator": true,
        "parking": false,
        "garage": false,
        "balcony": true,
        "terrace": false,
        "air_conditioning": true,
        "basement": false
      },
      "legal": {
        "ownership_status": "uknjizen",
        "legalization_status": "legalizovan",
        "mortgage_eligible": true,
        "mandate_attested": true,
        "exclusive": false,
        "broker_license_no": null,
        "tapija_note": null
      },
      "commission": {
        "buyer_pct": 2,
        "seller_pct": 2
      },
      "amenities": [
        "built_in_wardrobes",
        "intercom"
      ],
      "attributes": {},
      "photos": [
        {
          "url": "https://cdn.reaa.rs/listings/12345/1.jpg",
          "caption": null,
          "room_type": "living_room",
          "digest": null
        },
        {
          "url": "https://cdn.reaa.rs/listings/12345/2.jpg",
          "caption": null,
          "room_type": "kitchen",
          "digest": null
        },
        {
          "url": "https://cdn.reaa.rs/listings/12345/3.jpg",
          "caption": null,
          "room_type": "bedroom",
          "digest": null
        }
      ],
      "video_url": null,
      "virtual_tour_url": null,
      "agent": {
        "email": "milan@agencija.rs",
        "name": "Milan Petrović",
        "phone": "+381601234567"
      },
      "source": {
        "updated_at": "2026-10-12T08:00:00Z",
        "url": "https://agencija.rs/nekretnine/12345"
      },
      "digest": null
    },
    {
      "external_id": "REAA-12346",
      "transaction": "sale",
      "category": "apartment",
      "state": "active",
      "title": {
        "sr": "Trosoban stan, Vračar",
        "en": "Three-room flat, Vračar"
      },
      "description": {
        "sr": "Svetao trosoban stan na Vračaru, renoviran 2024, na pet minuta od Hrama Svetog Save.",
        "en": "A bright three-room flat in Vračar, renovated in 2024, five minutes from the Temple of Saint Sava."
      },
      "price": {
        "amount": 245000,
        "currency": "EUR",
        "negotiable": false
      },
      "location": {
        "place_id": "b2c0d6a4-3f1e-4d2a-9c8b-7e6f5a4b3c2d",
        "address_line": "Njegoševa 10",
        "neighbourhood": "Crveni krst",
        "lat": 44.8012,
        "lng": 20.4722
      },
      "structure": {
        "area_sqm": 78.5,
        "rooms": 3,
        "bedrooms": 2,
        "bathrooms": 1,
        "floor": 3,
        "total_floors": 5,
        "levels": 1,
        "year_built": 1968,
        "building_group": "old",
        "condition": "renovated",
        "furnished": "semi_furnished",
        "heating": "district",
        "elevator": true,
        "parking": false,
        "garage": false,
        "balcony": true,
        "terrace": false,
        "air_conditioning": true,
        "basement": false
      },
      "legal": {
        "ownership_status": "uknjizen",
        "legalization_status": "legalizovan",
        "mortgage_eligible": true,
        "mandate_attested": true,
        "exclusive": false,
        "broker_license_no": null,
        "tapija_note": null
      },
      "commission": {
        "buyer_pct": 2,
        "seller_pct": 2
      },
      "amenities": [
        "built_in_wardrobes",
        "intercom"
      ],
      "attributes": {},
      "photos": [
        {
          "url": "https://cdn.reaa.rs/listings/12345/1.jpg",
          "caption": null,
          "room_type": "living_room",
          "digest": null
        },
        {
          "url": "https://cdn.reaa.rs/listings/12345/2.jpg",
          "caption": null,
          "room_type": "kitchen",
          "digest": null
        },
        {
          "url": "https://cdn.reaa.rs/listings/12345/3.jpg",
          "caption": null,
          "room_type": "bedroom",
          "digest": null
        }
      ],
      "video_url": null,
      "virtual_tour_url": null,
      "agent": {
        "email": "milan@agencija.rs",
        "name": "Milan Petrović",
        "phone": "+381601234567"
      },
      "source": {
        "updated_at": "2026-10-12T08:00:00Z",
        "url": "https://agencija.rs/nekretnine/12345"
      },
      "digest": null
    },
    {
      "external_id": "REAA-12347",
      "transaction": "sale",
      "category": "apartment",
      "state": "active",
      "title": {
        "sr": "Trosoban stan, Vračar",
        "en": "Three-room flat, Vračar"
      },
      "description": {
        "sr": "Svetao trosoban stan na Vračaru, renoviran 2024, na pet minuta od Hrama Svetog Save.",
        "en": "A bright three-room flat in Vračar, renovated in 2024, five minutes from the Temple of Saint Sava."
      },
      "price": {
        "amount": 245000,
        "currency": "EUR",
        "negotiable": false
      },
      "location": {
        "place_id": "b2c0d6a4-3f1e-4d2a-9c8b-7e6f5a4b3c2d",
        "address_line": "Njegoševa 10",
        "neighbourhood": "Crveni krst",
        "lat": 44.8012,
        "lng": 20.4722
      },
      "structure": {
        "area_sqm": 78.5,
        "rooms": 3,
        "bedrooms": 2,
        "bathrooms": 1,
        "floor": 3,
        "total_floors": 5,
        "levels": 1,
        "year_built": 1968,
        "building_group": "old",
        "condition": "renovated",
        "furnished": "semi_furnished",
        "heating": "district",
        "elevator": true,
        "parking": false,
        "garage": false,
        "balcony": true,
        "terrace": false,
        "air_conditioning": true,
        "basement": false
      },
      "legal": {
        "ownership_status": "uknjizen",
        "legalization_status": "legalizovan",
        "mortgage_eligible": true,
        "mandate_attested": true,
        "exclusive": false,
        "broker_license_no": null,
        "tapija_note": null
      },
      "commission": {
        "buyer_pct": 2,
        "seller_pct": 2
      },
      "amenities": [
        "built_in_wardrobes",
        "intercom"
      ],
      "attributes": {},
      "photos": [
        {
          "url": "https://cdn.reaa.rs/listings/12345/1.jpg",
          "caption": null,
          "room_type": "living_room",
          "digest": null
        },
        {
          "url": "https://cdn.reaa.rs/listings/12345/2.jpg",
          "caption": null,
          "room_type": "kitchen",
          "digest": null
        },
        {
          "url": "https://cdn.reaa.rs/listings/12345/3.jpg",
          "caption": null,
          "room_type": "bedroom",
          "digest": null
        }
      ],
      "video_url": null,
      "virtual_tour_url": null,
      "agent": {
        "email": "milan@agencija.rs",
        "name": "Milan Petrović",
        "phone": "+381601234567"
      },
      "source": {
        "updated_at": "2026-10-12T08:00:00Z",
        "url": "https://agencija.rs/nekretnine/12345"
      },
      "digest": null
    }
  ]
}

Errors

Errors of batches.create
CodeHTTPWhen it happensWhat to do
body_invalid400The body is not a JSON object.Send valid JSON.
connection_not_found404Unknown id, or another app's connection.Check the id and the key environment.
connection_not_active409details.status is pending, paused or revoked.Wait for the agency, or stop pushing.
idempotency_in_progress409The same key while the first request runs (details.batch_id).Poll the batch.
validation_failed422The payload is invalid (details array).Fix the fields at the pointers.
batch_too_large422More than max_batch_items, more than 50 to validate, or more than 5,000 reconcile ids.Split.
duplicate_external_id422One external_id twice in a batch.Send each listing once.
idempotency_key_reused422The same key with a different body, within 7 days.A new key per distinct body.
connection_item_limit429Over the hourly item budget.Wait Retry-After, spread pushes.

scrolls →

Errors on every endpoint (14)
Errors on every endpoint, batches.create
CodeHTTPWhen it happensWhat to do
ingest_disabled503Novi Kvadrat switched ingestion off.Retry later with backoff.
body_too_large413The body is over 4 MiB (checked first).Split the batch.
signature_missing401A signing header is absent or malformed.Send all five headers.
key_invalid401Unknown or revoked key.Register a new key.
key_expired401The key is past its 365 days.Register a new key.
app_suspended403Staff suspended the app.Write to partners@novikvadrat.rs.
account_blocked403Staff suspended or archived the organization.Write to partners@novikvadrat.rs.
ip_allowlist_empty403A live app without addresses.Edit the allowlist.
ip_not_allowed403The caller is not listed, or its address can't be determined.Edit the allowlist.
digest_mismatch400The body changed after hashing.Hash the exact bytes you send.
timestamp_out_of_window401The clock is off by more than 300 s.Sync the clock (NTP).
signature_invalid401The base string or the key does not match.Compare with the test vector.
nonce_reused401A nonce sent twice within 15 minutes.A fresh random nonce per request.
rate_limited429Over the per-minute budget (replays count too).Wait Retry-After.

scrolls →

Detail codes

Detail codes of batches.create
Detail codeMeaningExample pointer
unknown_fieldA key the schema doesn't know./structure/balcon
requiredA required field is missing./title/sr
invalid_typeThe wrong JSON type./structure/rooms
too_smallBelow a minimum (length or value)./description/sr
too_bigAbove a maximum (length or value)./price/amount
invalid_enumA value outside the vocabulary./structure/heating
invalid_formatA malformed id, URL, date or pattern./photos/0/url
unknown_placeplace_id is not a city or municipality we know./location/place_id
duplicate_external_idOne external_id twice in one batch./listings/3/external_id
duplicate_photo_urlOne photo URL listed twice./photos/2/url

scrolls →

Warnings of batches.create
WarningMeaningExample pointer
agent_not_memberagent.email is not an active member of the agency; the listing has no agent./agent/email
virtual_tour_droppedThe agency's plan has no virtual tours; the URL was not stored./virtual_tour_url
commission_droppedThe agency is a bank; commission was not stored./commission
field_not_applicableA field that does not apply to the category was not stored./structure/floor
coordinates_outside_placeThe coordinates fall outside the place's boundary (kept)./location
photo_cap_appliedMore photos than the agency's plan allows; the extra ones were dropped./photos

scrolls →

GET/batches/{id}

Status and per-item results of a push.

Signed request; five headers

Parameters

Parameters of batches.get
NameInTypeRequiredDescription
idpathstring (uuid)YesThe batch id.

scrolls →

Responses

200 OK.

Unknown fields are rejected.

Response 200 of batches.get
FieldTypeRequiredConstraintsDescription
batchobjectYes—
batch.idstring (uuid)Yes—
batch.kindstring (enum)singlebatchremovereconcileYes—
batch.statusstring (enum)receivedprocessingcompletedfailedYes—
batch.countsobjectNo—Unknown fields are rejected.
batch.counts.acceptedintegerYes≥ -9007199254740991 · ≤ 9007199254740991
batch.counts.unchangedintegerYes≥ -9007199254740991 · ≤ 9007199254740991
batch.counts.needs_reviewintegerYes≥ -9007199254740991 · ≤ 9007199254740991
batch.counts.rejectedintegerYes≥ -9007199254740991 · ≤ 9007199254740991
batch.counts.removedintegerYes≥ -9007199254740991 · ≤ 9007199254740991
batch.counts.totalintegerYes≥ -9007199254740991 · ≤ 9007199254740991
itemsarray of objectYes—
items[].positionintegerYes≥ 0 · ≤ 9007199254740991
items[].external_idstringYes—
items[].resultstring (enum)acceptedunchangedneeds_reviewrejectedremovedYes—
items[].candidate_idstring (uuid) | nullYes—
items[].listing_idstring (uuid) | nullYes—
items[].public_urlstring | nullYes—
items[].failure_codestring (enum) | nullunmappable_categorymissing_requiredinvalid_payloadquota_exceededduplicategeo_unresolvedschema_invalidphoto_fetch_failedYes—
items[].detailsarray of object | map of any | nullYes—
items[].warningsarray of objectYes—
items[].warnings[].codestring (enum)agent_not_membervirtual_tour_droppedcommission_droppedfield_not_applicablecoordinates_outside_placephoto_cap_appliedYes—
items[].warnings[].pointerstringNo—
items[].warnings[].messagestringYes—

scrolls →

  • 404 batch_not_found: Unknown batch id, or another app's batch. The body is the error envelope.

Examples

Request · batches.get
GET /api/partners/v1/batches/{id}
NK-Key-Id: nkp_sandbox_7f3k9q2m4x8c1v6b
NK-Timestamp: 1791792000
NK-Nonce: <16–64 random bytes, base64url>
Content-Digest: sha-256=:47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=:
NK-Signature: v1=<86 base64url characters, no padding>

Errors

Errors of batches.get
CodeHTTPWhen it happensWhat to do
batch_not_found404Unknown batch id, or another app's batch.—

scrolls →

Errors on every endpoint (14)
Errors on every endpoint, batches.get
CodeHTTPWhen it happensWhat to do
ingest_disabled503Novi Kvadrat switched ingestion off.Retry later with backoff.
body_too_large413The body is over 4 MiB (checked first).Split the batch.
signature_missing401A signing header is absent or malformed.Send all five headers.
key_invalid401Unknown or revoked key.Register a new key.
key_expired401The key is past its 365 days.Register a new key.
app_suspended403Staff suspended the app.Write to partners@novikvadrat.rs.
account_blocked403Staff suspended or archived the organization.Write to partners@novikvadrat.rs.
ip_allowlist_empty403A live app without addresses.Edit the allowlist.
ip_not_allowed403The caller is not listed, or its address can't be determined.Edit the allowlist.
digest_mismatch400The body changed after hashing.Hash the exact bytes you send.
timestamp_out_of_window401The clock is off by more than 300 s.Sync the clock (NTP).
signature_invalid401The base string or the key does not match.Compare with the test vector.
nonce_reused401A nonce sent twice within 15 minutes.A fresh random nonce per request.
rate_limited429Over the per-minute budget (replays count too).Wait Retry-After.

scrolls →

Validate

POST/validate

Dry run: validate without storing anything.

Signed request; five headers

Request body

Unknown fields are rejected.

Request body of validate
FieldTypeRequiredConstraintsDescription
listingobjectNo—One listing; `transaction` picks the sale or the rent shape. Text lengths count Unicode code points, as `maxLength` does; titles are ALSO capped at 120 UTF-16 units (an emoji counts as two). A sale price is refused (`too_big`) when `amount × 117` (rounded, for EUR) would exceed 2,147,483,647 RSD (about 18,354,561 EUR). `state: active` needs `legal.mandate_attested: true`. See https://developers.novikvadrat.rs/docs/listings/payload-v1.
listing.external_idstringYesmin length 1 · max length 64 · pattern ^[A-Za-z0-9._:-]*$
listing.categorystring (enum)apartmentstudiopenthouseduplexlofthousehouse_semi_detachedtownhouseYes—
listing.statestring (enum)activeinactiveYes—
listing.titleobjectYes—Unknown fields are rejected.
listing.title.srstringYesmin length 5 · max length 120
listing.title.enstring | nullNomax length 120
listing.title.trstring | nullNomax length 120
listing.title.destring | nullNomax length 120
listing.title.rustring | nullNomax length 120
listing.descriptionobjectYes—Unknown fields are rejected.
listing.description.srstringYesmin length 20 · max length 8000
listing.description.enstring | nullNomax length 8000
listing.description.trstring | nullNomax length 8000
listing.description.destring | nullNomax length 8000
listing.description.rustring | nullNomax length 8000
listing.locationobjectYes—Unknown fields are rejected.
listing.location.place_idstring (uuid)Yes—
listing.location.address_linestringYesmin length 3 · max length 200
listing.location.neighbourhoodstring | nullNomax length 120
listing.location.latnumber | nullNo≥ -90 · ≤ 90
listing.location.lngnumber | nullNo≥ -180 · ≤ 180
listing.amenitiesarray of string (enum) | nullloggiafrench_balconywalk_in_closetbuilt_in_wardrobesunderfloor_heatingfireplacelaundry_roomsoundproofingNomax items 40
listing.attributesmap of any | nullNo—
listing.photosarray of object | nullNomax items 64
listing.photos[].urlstringYesmax length 2048
listing.photos[].captionstring | nullNomax length 500
listing.photos[].room_typestring (enum) | nullexteriorliving_roomkitchenbedroombathroombalconyhallwayviewNo—
listing.photos[].digeststring | nullNopattern ^[0-9a-f]{64}$
listing.video_urlstring | nullNomax length 2048
listing.virtual_tour_urlstring | nullNomax length 2048
listing.agentobject | nullNo—Unknown fields are rejected.
listing.agent.emailstring (email)Yesmax length 254
listing.agent.namestring | nullNomax length 120
listing.agent.phonestring | nullNomax length 32
listing.sourceobjectYes—Unknown fields are rejected.
listing.source.updated_atstring (date-time)Yes—
listing.source.urlstring | nullNomax length 2048
listing.digeststring | nullNomax length 128
listing.transactionstring (enum)salerentYes—
listing.priceobjectsale only—Unknown fields are rejected.
listing.price.amountnumbersale only> 0 · ≤ 9999999999
listing.price.currencystring (enum)EURRSDsale only—
listing.price.negotiableboolean | nullsale only—
listing.structureobjectYes—Unknown fields are rejected.
listing.structure.area_sqmnumber | nullNo> 0 · ≤ 99999.99
listing.structure.bedroomsnumber | nullNo≥ 0 · ≤ 99
listing.structure.bathroomsnumber | nullNo≥ 0 · ≤ 99
listing.structure.floorinteger | nullNo≥ -5 · ≤ 60
listing.structure.levelsinteger | nullNo≥ 1 · ≤ 6
listing.structure.furnishedstring (enum) | nullfurnishedsemi_furnishedunfurnishedNo—
listing.structure.elevatorboolean | nullNo—
listing.structure.parkingboolean | nullNo—
listing.structure.balconyboolean | nullNo—
listing.structure.terraceboolean | nullNo—
listing.structure.air_conditioningboolean | nullNo—
listing.structure.heatingstring (enum) | nulldistrictgas_centralgas_localelectric_localstorage_heaterelectric_panelheat_pumpair_conditioningNo—
listing.structure.roomsnumber | nullsale only≥ 0 · ≤ 99
listing.structure.total_floorsinteger | nullsale only≥ 0 · ≤ 60
listing.structure.year_builtinteger | nullsale only≥ 1800 · ≤ 2035
listing.structure.building_groupstring (enum) | nullnewoldsale only—
listing.structure.conditionstring (enum) | nullluxrenovatedoriginalrenovation_requiredsale only—
listing.structure.garageboolean | nullsale only—
listing.structure.basementboolean | nullsale only—
listing.legalobjectYes—Unknown fields are rejected.
listing.legal.ownership_statusstring (enum) | nulluknjizennije_uknjizenu_postupkusale only—
listing.legal.legalization_statusstring (enum) | nulllegalizovanu_postupkunelegalizovansale only—
listing.legal.mortgage_eligibleboolean | nullsale only—
listing.legal.mandate_attestedbooleanYes—
listing.legal.exclusiveboolean | nullsale only—
listing.legal.broker_license_nostring | nullsale onlymax length 64
listing.legal.tapija_notestring | nullsale onlymax length 500
listing.commissionobject | nullNo—Unknown fields are rejected.
listing.commission.buyer_pctnumber | nullsale only≥ 0 · ≤ 100
listing.commission.seller_pctnumber | nullsale only≥ 0 · ≤ 100
listing.commission.landlord_pctnumber | nullrent only≥ 0 · ≤ 100
listing.commission.agency_fee_pctnumber | nullrent only≥ 0 · ≤ 100
listing.rentobjectrent only—Unknown fields are rejected.
listing.rent.amountnumberrent only≥ 1 · ≤ 10000000
listing.rent.currencystring (enum)EURRSDrent only—
listing.rent.typestring (enum)long_termmid_termshort_termroomrent only—
listing.rent.deposit_monthsnumber | nullrent only≥ 0 · ≤ 12
listing.rent.min_lease_monthsinteger | nullrent only≥ 0 · ≤ 120
listing.rent.max_lease_monthsinteger | nullrent only≥ 0 · ≤ 120
listing.rent.available_fromstring (date) | nullrent only—
listing.rent.utilities_includedmap of boolean | nullrent only—
listing.rent.utilities_estimate_rsdinteger | nullrent only≥ 0 · ≤ 100000000
listing.rent.owner_lives_nearbyboolean | nullrent only—
listing.rent.owner_proximitystring (enum) | nullsame_apartmentsame_floorupstairsdownstairssame_buildingsame_streetwalking_distancerent only—
listing.rent.max_occupantsinteger | nullrent only≥ 1 · ≤ 20
listing.house_rulesobjectrent only—Unknown fields are rejected.
listing.house_rules.petsobjectrent only—Unknown fields are rejected.
listing.house_rules.pets.policystring (enum)allowedon_requestnot_allowedrent only—
listing.house_rules.pets.kindsarray of string (enum)dogscatssmall_cagedbirdsaquariumrent onlymax items 5
listing.house_rules.pets.dog_sizestring (enum)smallmediumanyrent only—
listing.house_rules.pets.max_countintegerrent only≥ 1 · ≤ 5
listing.house_rules.pets.deposit_eurintegerrent only≥ 0 · ≤ 100000
listing.house_rules.pets.notestringrent onlymax length 200
listing.house_rules.smokingstring (enum)not_allowedbalcony_onlyallowedrent only—
listing.house_rules.guestsstring (enum)allowedask_firstnot_allowedrent only—
listing.house_rules.partiesstring (enum)not_allowedallowedrent only—
listing.house_rules.quiet_hoursstringrent onlymax length 200
listing.house_rules.sublettingstring (enum)not_allowedwith_consentrent only—
listing.house_rules.studentsstring (enum)yesnorent only—
listing.house_rules.familiesstring (enum)yesnorent only—
listing.house_rules.foreign_tenantsstring (enum)welcomeask_firstrent only—
listing.house_rules.registers_residencebooleanrent only—
listing.house_rules.otherstringrent onlymax length 500
listingsarray of objectNomin items 1
listings[].external_idstringYesmin length 1 · max length 64 · pattern ^[A-Za-z0-9._:-]*$
listings[].categorystring (enum)apartmentstudiopenthouseduplexlofthousehouse_semi_detachedtownhouseYes—
listings[].statestring (enum)activeinactiveYes—
listings[].titleobjectYes—Unknown fields are rejected.
listings[].title.srstringYesmin length 5 · max length 120
listings[].title.enstring | nullNomax length 120
listings[].title.trstring | nullNomax length 120
listings[].title.destring | nullNomax length 120
listings[].title.rustring | nullNomax length 120
listings[].descriptionobjectYes—Unknown fields are rejected.
listings[].description.srstringYesmin length 20 · max length 8000
listings[].description.enstring | nullNomax length 8000
listings[].description.trstring | nullNomax length 8000
listings[].description.destring | nullNomax length 8000
listings[].description.rustring | nullNomax length 8000
listings[].locationobjectYes—Unknown fields are rejected.
listings[].location.place_idstring (uuid)Yes—
listings[].location.address_linestringYesmin length 3 · max length 200
listings[].location.neighbourhoodstring | nullNomax length 120
listings[].location.latnumber | nullNo≥ -90 · ≤ 90
listings[].location.lngnumber | nullNo≥ -180 · ≤ 180
listings[].amenitiesarray of string (enum) | nullloggiafrench_balconywalk_in_closetbuilt_in_wardrobesunderfloor_heatingfireplacelaundry_roomsoundproofingNomax items 40
listings[].attributesmap of any | nullNo—
listings[].photosarray of object | nullNomax items 64
listings[].photos[].urlstringYesmax length 2048
listings[].photos[].captionstring | nullNomax length 500
listings[].photos[].room_typestring (enum) | nullexteriorliving_roomkitchenbedroombathroombalconyhallwayviewNo—
listings[].photos[].digeststring | nullNopattern ^[0-9a-f]{64}$
listings[].video_urlstring | nullNomax length 2048
listings[].virtual_tour_urlstring | nullNomax length 2048
listings[].agentobject | nullNo—Unknown fields are rejected.
listings[].agent.emailstring (email)Yesmax length 254
listings[].agent.namestring | nullNomax length 120
listings[].agent.phonestring | nullNomax length 32
listings[].sourceobjectYes—Unknown fields are rejected.
listings[].source.updated_atstring (date-time)Yes—
listings[].source.urlstring | nullNomax length 2048
listings[].digeststring | nullNomax length 128
listings[].transactionstring (enum)salerentYes—
listings[].priceobjectsale only—Unknown fields are rejected.
listings[].price.amountnumbersale only> 0 · ≤ 9999999999
listings[].price.currencystring (enum)EURRSDsale only—
listings[].price.negotiableboolean | nullsale only—
listings[].structureobjectYes—Unknown fields are rejected.
listings[].structure.area_sqmnumber | nullNo> 0 · ≤ 99999.99
listings[].structure.bedroomsnumber | nullNo≥ 0 · ≤ 99
listings[].structure.bathroomsnumber | nullNo≥ 0 · ≤ 99
listings[].structure.floorinteger | nullNo≥ -5 · ≤ 60
listings[].structure.levelsinteger | nullNo≥ 1 · ≤ 6
listings[].structure.furnishedstring (enum) | nullfurnishedsemi_furnishedunfurnishedNo—
listings[].structure.elevatorboolean | nullNo—
listings[].structure.parkingboolean | nullNo—
listings[].structure.balconyboolean | nullNo—
listings[].structure.terraceboolean | nullNo—
listings[].structure.air_conditioningboolean | nullNo—
listings[].structure.heatingstring (enum) | nulldistrictgas_centralgas_localelectric_localstorage_heaterelectric_panelheat_pumpair_conditioningNo—
listings[].structure.roomsnumber | nullsale only≥ 0 · ≤ 99
listings[].structure.total_floorsinteger | nullsale only≥ 0 · ≤ 60
listings[].structure.year_builtinteger | nullsale only≥ 1800 · ≤ 2035
listings[].structure.building_groupstring (enum) | nullnewoldsale only—
listings[].structure.conditionstring (enum) | nullluxrenovatedoriginalrenovation_requiredsale only—
listings[].structure.garageboolean | nullsale only—
listings[].structure.basementboolean | nullsale only—
listings[].legalobjectYes—Unknown fields are rejected.
listings[].legal.ownership_statusstring (enum) | nulluknjizennije_uknjizenu_postupkusale only—
listings[].legal.legalization_statusstring (enum) | nulllegalizovanu_postupkunelegalizovansale only—
listings[].legal.mortgage_eligibleboolean | nullsale only—
listings[].legal.mandate_attestedbooleanYes—
listings[].legal.exclusiveboolean | nullsale only—
listings[].legal.broker_license_nostring | nullsale onlymax length 64
listings[].legal.tapija_notestring | nullsale onlymax length 500
listings[].commissionobject | nullNo—Unknown fields are rejected.
listings[].commission.buyer_pctnumber | nullsale only≥ 0 · ≤ 100
listings[].commission.seller_pctnumber | nullsale only≥ 0 · ≤ 100
listings[].commission.landlord_pctnumber | nullrent only≥ 0 · ≤ 100
listings[].commission.agency_fee_pctnumber | nullrent only≥ 0 · ≤ 100
listings[].rentobjectrent only—Unknown fields are rejected.
listings[].rent.amountnumberrent only≥ 1 · ≤ 10000000
listings[].rent.currencystring (enum)EURRSDrent only—
listings[].rent.typestring (enum)long_termmid_termshort_termroomrent only—
listings[].rent.deposit_monthsnumber | nullrent only≥ 0 · ≤ 12
listings[].rent.min_lease_monthsinteger | nullrent only≥ 0 · ≤ 120
listings[].rent.max_lease_monthsinteger | nullrent only≥ 0 · ≤ 120
listings[].rent.available_fromstring (date) | nullrent only—
listings[].rent.utilities_includedmap of boolean | nullrent only—
listings[].rent.utilities_estimate_rsdinteger | nullrent only≥ 0 · ≤ 100000000
listings[].rent.owner_lives_nearbyboolean | nullrent only—
listings[].rent.owner_proximitystring (enum) | nullsame_apartmentsame_floorupstairsdownstairssame_buildingsame_streetwalking_distancerent only—
listings[].rent.max_occupantsinteger | nullrent only≥ 1 · ≤ 20
listings[].house_rulesobjectrent only—Unknown fields are rejected.
listings[].house_rules.petsobjectrent only—Unknown fields are rejected.
listings[].house_rules.pets.policystring (enum)allowedon_requestnot_allowedrent only—
listings[].house_rules.pets.kindsarray of string (enum)dogscatssmall_cagedbirdsaquariumrent onlymax items 5
listings[].house_rules.pets.dog_sizestring (enum)smallmediumanyrent only—
listings[].house_rules.pets.max_countintegerrent only≥ 1 · ≤ 5
listings[].house_rules.pets.deposit_eurintegerrent only≥ 0 · ≤ 100000
listings[].house_rules.pets.notestringrent onlymax length 200
listings[].house_rules.smokingstring (enum)not_allowedbalcony_onlyallowedrent only—
listings[].house_rules.guestsstring (enum)allowedask_firstnot_allowedrent only—
listings[].house_rules.partiesstring (enum)not_allowedallowedrent only—
listings[].house_rules.quiet_hoursstringrent onlymax length 200
listings[].house_rules.sublettingstring (enum)not_allowedwith_consentrent only—
listings[].house_rules.studentsstring (enum)yesnorent only—
listings[].house_rules.familiesstring (enum)yesnorent only—
listings[].house_rules.foreign_tenantsstring (enum)welcomeask_firstrent only—
listings[].house_rules.registers_residencebooleanrent only—
listings[].house_rules.otherstringrent onlymax length 500
connection_idstring (uuid)No—

scrolls →

Responses

200 OK.

Unknown fields are rejected.

Response 200 of validate
FieldTypeRequiredConstraintsDescription
resultsarray of objectYes—
results[].positionintegerYes≥ 0 · ≤ 9007199254740991
results[].external_idstring | nullYes—
results[].validbooleanYes—
results[].errorsarray of objectYes—
results[].errors[].pointerstringYes—
results[].errors[].codestring (enum)unknown_fieldrequiredinvalid_typetoo_smalltoo_biginvalid_enuminvalid_formatunknown_placeYes—
results[].errors[].messagestringYes—
results[].warningsarray of objectYes—
results[].warnings[].codestring (enum)agent_not_membervirtual_tour_droppedcommission_droppedfield_not_applicablecoordinates_outside_placephoto_cap_appliedYes—
results[].warnings[].pointerstringNo—
results[].warnings[].messagestringYes—
results[].mapped_previewmap of any | nullYes—

scrolls →

  • 400 body_invalid: The body is not a JSON object. The body is the error envelope.
  • 404 connection_not_found: Unknown id, or another app's connection. The body is the error envelope.
  • 409 connection_not_active: details.status is pending, paused or revoked. The body is the error envelope.
  • 422 batch_too_large: More than max_batch_items, more than 50 to validate, or more than 5,000 reconcile ids. validation_failed: The payload is invalid (details array). The body is the error envelope.

Examples

Request · validate
POST /api/partners/v1/validate
NK-Key-Id: nkp_sandbox_7f3k9q2m4x8c1v6b
NK-Timestamp: 1791792000
NK-Nonce: <16–64 random bytes, base64url>
Content-Digest: sha-256=:<base64 SHA-256 of the exact body bytes>:
NK-Signature: v1=<86 base64url characters, no padding>
Content-Type: application/json

{
  "listing": {
    "external_id": "REAA-12345",
    "transaction": "sale",
    "category": "apartment",
    "state": "active",
    "title": {
      "sr": "Trosoban stan, Vračar",
      "en": "Three-room flat, Vračar"
    },
    "description": {
      "sr": "Svetao trosoban stan na Vračaru, renoviran 2024, na pet minuta od Hrama Svetog Save.",
      "en": "A bright three-room flat in Vračar, renovated in 2024, five minutes from the Temple of Saint Sava."
    },
    "price": {
      "amount": 245000,
      "currency": "EUR",
      "negotiable": false
    },
    "location": {
      "place_id": "b2c0d6a4-3f1e-4d2a-9c8b-7e6f5a4b3c2d",
      "address_line": "Njegoševa 10",
      "neighbourhood": "Crveni krst",
      "lat": 44.8012,
      "lng": 20.4722
    },
    "structure": {
      "area_sqm": 78.5,
      "rooms": 3,
      "bedrooms": 2,
      "bathrooms": 1,
      "floor": 3,
      "total_floors": 5,
      "levels": 1,
      "year_built": 1968,
      "building_group": "old",
      "condition": "renovated",
      "furnished": "semi_furnished",
      "heating": "district",
      "elevator": true,
      "parking": false,
      "garage": false,
      "balcony": true,
      "terrace": false,
      "air_conditioning": true,
      "basement": false
    },
    "legal": {
      "ownership_status": "uknjizen",
      "legalization_status": "legalizovan",
      "mortgage_eligible": true,
      "mandate_attested": true,
      "exclusive": false,
      "broker_license_no": null,
      "tapija_note": null
    },
    "commission": {
      "buyer_pct": 2,
      "seller_pct": 2
    },
    "amenities": [
      "built_in_wardrobes",
      "intercom"
    ],
    "attributes": {},
    "photos": [
      {
        "url": "https://cdn.reaa.rs/listings/12345/1.jpg",
        "caption": null,
        "room_type": "living_room",
        "digest": null
      },
      {
        "url": "https://cdn.reaa.rs/listings/12345/2.jpg",
        "caption": null,
        "room_type": "kitchen",
        "digest": null
      },
      {
        "url": "https://cdn.reaa.rs/listings/12345/3.jpg",
        "caption": null,
        "room_type": "bedroom",
        "digest": null
      }
    ],
    "video_url": null,
    "virtual_tour_url": null,
    "agent": {
      "email": "milan@agencija.rs",
      "name": "Milan Petrović",
      "phone": "+381601234567"
    },
    "source": {
      "updated_at": "2026-10-12T08:00:00Z",
      "url": "https://agencija.rs/nekretnine/12345"
    },
    "digest": null
  },
  "connection_id": "9b1d6c2e-4f3a-4c8e-9a71-2d5e8f0b3c44"
}

Errors

Errors of validate
CodeHTTPWhen it happensWhat to do
body_invalid400The body is not a JSON object.Send valid JSON.
connection_not_found404Unknown id, or another app's connection.Check the id and the key environment.
connection_not_active409details.status is pending, paused or revoked.Wait for the agency, or stop pushing.
validation_failed422The payload is invalid (details array).Fix the fields at the pointers.
batch_too_large422More than max_batch_items, more than 50 to validate, or more than 5,000 reconcile ids.Split.

scrolls →

Errors on every endpoint (14)
Errors on every endpoint, validate
CodeHTTPWhen it happensWhat to do
ingest_disabled503Novi Kvadrat switched ingestion off.Retry later with backoff.
body_too_large413The body is over 4 MiB (checked first).Split the batch.
signature_missing401A signing header is absent or malformed.Send all five headers.
key_invalid401Unknown or revoked key.Register a new key.
key_expired401The key is past its 365 days.Register a new key.
app_suspended403Staff suspended the app.Write to partners@novikvadrat.rs.
account_blocked403Staff suspended or archived the organization.Write to partners@novikvadrat.rs.
ip_allowlist_empty403A live app without addresses.Edit the allowlist.
ip_not_allowed403The caller is not listed, or its address can't be determined.Edit the allowlist.
digest_mismatch400The body changed after hashing.Hash the exact bytes you send.
timestamp_out_of_window401The clock is off by more than 300 s.Sync the clock (NTP).
signature_invalid401The base string or the key does not match.Compare with the test vector.
nonce_reused401A nonce sent twice within 15 minutes.A fresh random nonce per request.
rate_limited429Over the per-minute budget (replays count too).Wait Retry-After.

scrolls →

Detail codes

Detail codes of validate
Detail codeMeaningExample pointer
unknown_fieldA key the schema doesn't know./structure/balcon
requiredA required field is missing./title/sr
invalid_typeThe wrong JSON type./structure/rooms
too_smallBelow a minimum (length or value)./description/sr
too_bigAbove a maximum (length or value)./price/amount
invalid_enumA value outside the vocabulary./structure/heating
invalid_formatA malformed id, URL, date or pattern./photos/0/url
unknown_placeplace_id is not a city or municipality we know./location/place_id
duplicate_external_idOne external_id twice in one batch./listings/3/external_id
duplicate_photo_urlOne photo URL listed twice./photos/2/url

scrolls →

Warnings of validate
WarningMeaningExample pointer
agent_not_memberagent.email is not an active member of the agency; the listing has no agent./agent/email
virtual_tour_droppedThe agency's plan has no virtual tours; the URL was not stored./virtual_tour_url
commission_droppedThe agency is a bank; commission was not stored./commission
field_not_applicableA field that does not apply to the category was not stored./structure/floor
coordinates_outside_placeThe coordinates fall outside the place's boundary (kept)./location
photo_cap_appliedMore photos than the agency's plan allows; the extra ones were dropped./photos

scrolls →

Vocabularies

GET/vocabularies

Every enumeration, with labels and per-category attributes.

Signed request; five headers

Parameters

Parameters of vocabularies
NameInTypeRequiredDescription
If-None-MatchheaderstringNoThe ETag of a previous answer; when it is still current the answer is 304 with no body.

scrolls →

Responses

200 OK.

Unknown fields are rejected.

Response 200 of vocabularies
FieldTypeRequiredConstraintsDescription
versionstringYes—
categoriesarray of objectYes—
categories[].codestringYes—
categories[].groupstringYes—
categories[].labelsobjectYes—Unknown fields are rejected.
categories[].labels.enstringYes—
categories[].labels.srstringYes—
transactionarray of stringYes—
heatingarray of stringYes—
conditionarray of stringYes—
furnishedarray of stringYes—
building_grouparray of stringYes—
ownership_statusarray of stringYes—
legalization_statusarray of stringYes—
rental_typearray of stringYes—
room_typesarray of stringYes—
amenitiesarray of objectYes—
amenities[].codestringYes—
amenities[].labelsobjectYes—Unknown fields are rejected.
amenities[].labels.enstringYes—
amenities[].labels.srstringYes—
remove_reasonsarray of stringYes—
attributes_by_categorymap of anyYes—

scrolls →

  • 304 Not modified: If-None-Match matched the current ETag. The body is the error envelope.

Examples

Request · vocabularies
GET /api/partners/v1/vocabularies
NK-Key-Id: nkp_sandbox_7f3k9q2m4x8c1v6b
NK-Timestamp: 1791792000
NK-Nonce: <16–64 random bytes, base64url>
Content-Digest: sha-256=:47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=:
NK-Signature: v1=<86 base64url characters, no padding>

Errors

No errors beyond the signed-request checks.

Errors on every endpoint (14)
Errors on every endpoint, vocabularies
CodeHTTPWhen it happensWhat to do
ingest_disabled503Novi Kvadrat switched ingestion off.Retry later with backoff.
body_too_large413The body is over 4 MiB (checked first).Split the batch.
signature_missing401A signing header is absent or malformed.Send all five headers.
key_invalid401Unknown or revoked key.Register a new key.
key_expired401The key is past its 365 days.Register a new key.
app_suspended403Staff suspended the app.Write to partners@novikvadrat.rs.
account_blocked403Staff suspended or archived the organization.Write to partners@novikvadrat.rs.
ip_allowlist_empty403A live app without addresses.Edit the allowlist.
ip_not_allowed403The caller is not listed, or its address can't be determined.Edit the allowlist.
digest_mismatch400The body changed after hashing.Hash the exact bytes you send.
timestamp_out_of_window401The clock is off by more than 300 s.Sync the clock (NTP).
signature_invalid401The base string or the key does not match.Compare with the test vector.
nonce_reused401A nonce sent twice within 15 minutes.A fresh random nonce per request.
rate_limited429Over the per-minute budget (replays count too).Wait Retry-After.

scrolls →

Places

GET/places

Search cities and municipalities.

Signed request; five headers

Parameters

Parameters of places.search
NameInTypeRequiredDescription
qquerystringNo
typequeryenum: city, municipalityNo
cursorquerystringNo
limitquerystring, pattern ^\d{1,3}$No

scrolls →

Responses

200 OK.

Unknown fields are rejected.

Response 200 of places.search
FieldTypeRequiredConstraintsDescription
placesarray of objectYes—
places[].idstring (uuid)Yes—
places[].typestring (enum)citymunicipalityYes—
places[].name_srstringYes—
places[].name_enstringYes—
places[].official_codestring | nullYes—
places[].city_idstring (uuid) | nullYes—
places[].city_name_srstring | nullYes—
places[].latnumber | nullYes—
places[].lngnumber | nullYes—
next_cursorstring | nullYes—

scrolls →

  • 422 validation_failed: The payload is invalid (details array). The body is the error envelope.

Examples

Request · places.search
GET /api/partners/v1/places
NK-Key-Id: nkp_sandbox_7f3k9q2m4x8c1v6b
NK-Timestamp: 1791792000
NK-Nonce: <16–64 random bytes, base64url>
Content-Digest: sha-256=:47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=:
NK-Signature: v1=<86 base64url characters, no padding>

Errors

Errors of places.search
CodeHTTPWhen it happensWhat to do
validation_failed422The payload is invalid (details array).Fix the fields at the pointers.

scrolls →

Errors on every endpoint (14)
Errors on every endpoint, places.search
CodeHTTPWhen it happensWhat to do
ingest_disabled503Novi Kvadrat switched ingestion off.Retry later with backoff.
body_too_large413The body is over 4 MiB (checked first).Split the batch.
signature_missing401A signing header is absent or malformed.Send all five headers.
key_invalid401Unknown or revoked key.Register a new key.
key_expired401The key is past its 365 days.Register a new key.
app_suspended403Staff suspended the app.Write to partners@novikvadrat.rs.
account_blocked403Staff suspended or archived the organization.Write to partners@novikvadrat.rs.
ip_allowlist_empty403A live app without addresses.Edit the allowlist.
ip_not_allowed403The caller is not listed, or its address can't be determined.Edit the allowlist.
digest_mismatch400The body changed after hashing.Hash the exact bytes you send.
timestamp_out_of_window401The clock is off by more than 300 s.Sync the clock (NTP).
signature_invalid401The base string or the key does not match.Compare with the test vector.
nonce_reused401A nonce sent twice within 15 minutes.A fresh random nonce per request.
rate_limited429Over the per-minute budget (replays count too).Wait Retry-After.

scrolls →

Detail codes

Detail codes of places.search
Detail codeMeaningExample pointer
unknown_fieldA key the schema doesn't know./structure/balcon
requiredA required field is missing./title/sr
invalid_typeThe wrong JSON type./structure/rooms
too_smallBelow a minimum (length or value)./description/sr
too_bigAbove a maximum (length or value)./price/amount
invalid_enumA value outside the vocabulary./structure/heating
invalid_formatA malformed id, URL, date or pattern./photos/0/url

scrolls →

GET/places/{id}

One place.

Signed request; five headers

Parameters

Parameters of places.get
NameInTypeRequiredDescription
idpathstring (uuid)YesThe place id.

scrolls →

Responses

200 OK.

Unknown fields are rejected.

Response 200 of places.get
FieldTypeRequiredConstraintsDescription
placeobjectYes—Unknown fields are rejected.
place.idstring (uuid)Yes—
place.typestring (enum)citymunicipalityYes—
place.name_srstringYes—
place.name_enstringYes—
place.official_codestring | nullYes—
place.city_idstring (uuid) | nullYes—
place.city_name_srstring | nullYes—
place.latnumber | nullYes—
place.lngnumber | nullYes—

scrolls →

  • 404 place_not_found: Unknown place id. The body is the error envelope.

Examples

Request · places.get
GET /api/partners/v1/places/{id}
NK-Key-Id: nkp_sandbox_7f3k9q2m4x8c1v6b
NK-Timestamp: 1791792000
NK-Nonce: <16–64 random bytes, base64url>
Content-Digest: sha-256=:47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=:
NK-Signature: v1=<86 base64url characters, no padding>

Errors

Errors of places.get
CodeHTTPWhen it happensWhat to do
place_not_found404Unknown place id.—

scrolls →

Errors on every endpoint (14)
Errors on every endpoint, places.get
CodeHTTPWhen it happensWhat to do
ingest_disabled503Novi Kvadrat switched ingestion off.Retry later with backoff.
body_too_large413The body is over 4 MiB (checked first).Split the batch.
signature_missing401A signing header is absent or malformed.Send all five headers.
key_invalid401Unknown or revoked key.Register a new key.
key_expired401The key is past its 365 days.Register a new key.
app_suspended403Staff suspended the app.Write to partners@novikvadrat.rs.
account_blocked403Staff suspended or archived the organization.Write to partners@novikvadrat.rs.
ip_allowlist_empty403A live app without addresses.Edit the allowlist.
ip_not_allowed403The caller is not listed, or its address can't be determined.Edit the allowlist.
digest_mismatch400The body changed after hashing.Hash the exact bytes you send.
timestamp_out_of_window401The clock is off by more than 300 s.Sync the clock (NTP).
signature_invalid401The base string or the key does not match.Compare with the test vector.
nonce_reused401A nonce sent twice within 15 minutes.A fresh random nonce per request.
rate_limited429Over the per-minute budget (replays count too).Wait Retry-After.

scrolls →