{"openapi":"3.0.3","info":{"title":"Novi Kvadrat Partner API","version":"1.0.0","description":"Publish your agencies' sale and rental listings on Novi Kvadrat, with each agency's consent. Every request is signed (NK-SIG-1). Docs: https://developers.novikvadrat.rs/docs. Contact: partners@novikvadrat.rs.","contact":{"email":"partners@novikvadrat.rs"}},"servers":[{"url":"https://novikvadrat.rs/api/partners/v1"}],"tags":[{"name":"Ping"},{"name":"Connections"},{"name":"Listings"},{"name":"Batches"},{"name":"Validate"},{"name":"Vocabularies"},{"name":"Places"}],"security":[{"NK-SIG-1":[]}],"paths":{"/ping":{"get":{"operationId":"ping","tags":["Ping"],"summary":"Prove the signature works and read the app, key and limits.","parameters":[{"$ref":"#/components/parameters/NK-Timestamp"},{"$ref":"#/components/parameters/NK-Nonce"},{"$ref":"#/components/parameters/Content-Digest"},{"$ref":"#/components/parameters/NK-Signature"}],"responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"app":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"environment":{"type":"string","enum":["sandbox","live"]},"name":{"type":"string"}},"required":["id","environment","name"],"additionalProperties":false},"key_id":{"type":"string"},"partner":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false},"server_time":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"limits":{"type":"object","properties":{"rate_limit_per_minute":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"connection_items_per_hour":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"max_batch_items":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["rate_limit_per_minute","connection_items_per_hour","max_batch_items"],"additionalProperties":false}},"required":["app","key_id","partner","server_time","limits"],"additionalProperties":false},"example":{"app":{"id":"5d0a8f3c-2b1e-4d7a-9c6b-8e5f4a3b2c1d","environment":"sandbox","name":"Sandbox"},"key_id":"nkp_sandbox_7f3k9q2m4x8c1v6b","partner":{"id":"a41c7e2d-9b3f-4a1e-8d6c-5b4a3f2e1d0c","name":"REAA"},"server_time":"2026-10-12T08:00:01Z","limits":{"rate_limit_per_minute":120,"connection_items_per_hour":500,"max_batch_items":200}}}}},"default":{"description":"Any refusal of the signed-request checks (x-nk-shared-errors) or 500 internal_error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-nk-success-status":200,"x-nk-errors":[],"x-nk-detail-codes":[],"x-nk-warning-codes":[],"x-nk-error-example":{"error":{"code":"signature_invalid","message":"The signature does not match."},"request_id":"0f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a"}}},"/connections":{"post":{"operationId":"connections.redeem","tags":["Connections"],"summary":"Redeem a connect code an agency generated.","parameters":[{"$ref":"#/components/parameters/NK-Timestamp"},{"$ref":"#/components/parameters/NK-Nonce"},{"$ref":"#/components/parameters/Content-Digest"},{"$ref":"#/components/parameters/NK-Signature"}],"responses":{"201":{"description":"Created.","content":{"application/json":{"schema":{"type":"object","properties":{"connection":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"status":{"type":"string","enum":["certifying","active","paused","revoked"]},"environment":{"type":"string","enum":["sandbox","live"]},"agency":{"type":"object","properties":{"name":{"type":"string"},"register_number":{"nullable":true,"type":"string"},"verification_status":{"type":"string","enum":["unverified","pending","verified","rejected"]},"listing_quota":{"type":"object","properties":{"used":{"type":"integer","minimum":0,"maximum":9007199254740991},"limit":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["used","limit"],"additionalProperties":false},"photo_limit":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["name","register_number","verification_status","listing_quota","photo_limit"],"additionalProperties":false},"created_at":{"type":"string"},"redeemed_at":{"nullable":true,"type":"string"},"certified_at":{"nullable":true,"type":"string"},"paused":{"nullable":true,"type":"object","properties":{"at":{"type":"string"},"by":{"type":"string","enum":["agency","staff"]},"reason":{"nullable":true,"type":"string"}},"required":["at","by","reason"],"additionalProperties":false},"counts":{"type":"object","properties":{"live":{"type":"integer","minimum":0,"maximum":9007199254740991},"paused":{"type":"integer","minimum":0,"maximum":9007199254740991},"review":{"type":"integer","minimum":0,"maximum":9007199254740991},"failed":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["live","paused","review","failed"],"additionalProperties":false},"last_push_at":{"nullable":true,"type":"string"}},"required":["id","status","environment","agency","created_at","redeemed_at","certified_at","paused","counts","last_push_at"],"additionalProperties":false}},"required":["connection"],"additionalProperties":false},"example":{"connection":{"id":"9b1d6c2e-4f3a-4c8e-9a71-2d5e8f0b3c44","status":"certifying","environment":"sandbox","agency":{"name":"Test agencija","register_number":"123/2024","verification_status":"verified","listing_quota":{"used":0,"limit":50},"photo_limit":30},"created_at":"2026-10-12T07:58:00Z","redeemed_at":"2026-10-12T08:00:00Z","certified_at":null,"paused":null,"counts":{"live":0,"paused":0,"review":0,"failed":0},"last_push_at":null}}}}},"400":{"description":"`body_invalid`: The body is not a JSON object.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"`connect_code_invalid`: An unknown, expired, used or other app's code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"error":{"code":"connect_code_invalid","message":"The connect code is unknown, expired or already used."},"request_id":"0f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a"}}}},"422":{"description":"`agency_not_eligible`: details.reason is register_number_missing or account_blocked. `validation_failed`: The payload is invalid (details array).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"default":{"description":"Any refusal of the signed-request checks (x-nk-shared-errors) or 500 internal_error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-nk-success-status":201,"x-nk-errors":[{"code":"body_invalid","status":400,"when":"The body is not a JSON object.","fix":"Send valid JSON."},{"code":"connect_code_invalid","status":404,"when":"An unknown, expired, used or other app's code.","fix":"Ask for a new code."},{"code":"agency_not_eligible","status":422,"when":"details.reason is register_number_missing or account_blocked.","fix":"The agency fixes its profile."},{"code":"validation_failed","status":422,"when":"The payload is invalid (details array).","fix":"Fix the fields at the pointers."}],"x-nk-detail-codes":[{"code":"unknown_field","meaning":"A key the schema doesn't know.","example_pointer":"/structure/balcon"},{"code":"required","meaning":"A required field is missing.","example_pointer":"/title/sr"},{"code":"invalid_type","meaning":"The wrong JSON type.","example_pointer":"/structure/rooms"},{"code":"too_small","meaning":"Below a minimum (length or value).","example_pointer":"/description/sr"},{"code":"too_big","meaning":"Above a maximum (length or value).","example_pointer":"/price/amount"},{"code":"invalid_enum","meaning":"A value outside the vocabulary.","example_pointer":"/structure/heating"},{"code":"invalid_format","meaning":"A malformed id, URL, date or pattern.","example_pointer":"/photos/0/url"}],"x-nk-warning-codes":[],"x-nk-error-example":{"error":{"code":"connect_code_invalid","message":"The connect code is unknown, expired or already used."},"request_id":"0f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"connect_code":{"type":"string","minLength":12,"maxLength":32}},"required":["connect_code"],"additionalProperties":false},"example":{"connect_code":"NK-7Q4M-X2PA-9KDF"}}}}},"get":{"operationId":"connections.list","tags":["Connections"],"summary":"List this app's connections.","parameters":[{"$ref":"#/components/parameters/NK-Timestamp"},{"$ref":"#/components/parameters/NK-Nonce"},{"$ref":"#/components/parameters/Content-Digest"},{"$ref":"#/components/parameters/NK-Signature"},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["certifying","active","paused","revoked"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{1,3}$"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","maxLength":512}}],"responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"connections":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"status":{"type":"string","enum":["certifying","active","paused","revoked"]},"environment":{"type":"string","enum":["sandbox","live"]},"agency":{"type":"object","properties":{"name":{"type":"string"},"register_number":{"nullable":true,"type":"string"},"verification_status":{"type":"string","enum":["unverified","pending","verified","rejected"]},"listing_quota":{"type":"object","properties":{"used":{"type":"integer","minimum":0,"maximum":9007199254740991},"limit":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["used","limit"],"additionalProperties":false},"photo_limit":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["name","register_number","verification_status","listing_quota","photo_limit"],"additionalProperties":false},"created_at":{"type":"string"},"redeemed_at":{"nullable":true,"type":"string"},"certified_at":{"nullable":true,"type":"string"},"paused":{"nullable":true,"type":"object","properties":{"at":{"type":"string"},"by":{"type":"string","enum":["agency","staff"]},"reason":{"nullable":true,"type":"string"}},"required":["at","by","reason"],"additionalProperties":false},"counts":{"type":"object","properties":{"live":{"type":"integer","minimum":0,"maximum":9007199254740991},"paused":{"type":"integer","minimum":0,"maximum":9007199254740991},"review":{"type":"integer","minimum":0,"maximum":9007199254740991},"failed":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["live","paused","review","failed"],"additionalProperties":false},"last_push_at":{"nullable":true,"type":"string"}},"required":["id","status","environment","agency","created_at","redeemed_at","certified_at","paused","counts","last_push_at"],"additionalProperties":false}},"next_cursor":{"nullable":true,"type":"string"}},"required":["connections","next_cursor"],"additionalProperties":false},"example":{"connections":[{"id":"9b1d6c2e-4f3a-4c8e-9a71-2d5e8f0b3c44","status":"active","environment":"sandbox","agency":{"name":"Test agencija","register_number":"123/2024","verification_status":"verified","listing_quota":{"used":0,"limit":50},"photo_limit":30},"created_at":"2026-10-12T07:58:00Z","redeemed_at":"2026-10-12T08:00:00Z","certified_at":"2026-10-12T09:00:00Z","paused":null,"counts":{"live":0,"paused":0,"review":0,"failed":0},"last_push_at":null}],"next_cursor":null}}}},"422":{"description":"`validation_failed`: The payload is invalid (details array).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"error":{"code":"validation_failed","message":"The query is not valid.","details":[{"pointer":"/limit","code":"too_big","message":"Must be at most 200."}]},"request_id":"0f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a"}}}},"default":{"description":"Any refusal of the signed-request checks (x-nk-shared-errors) or 500 internal_error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-nk-success-status":200,"x-nk-errors":[{"code":"validation_failed","status":422,"when":"The payload is invalid (details array).","fix":"Fix the fields at the pointers."}],"x-nk-detail-codes":[{"code":"unknown_field","meaning":"A key the schema doesn't know.","example_pointer":"/structure/balcon"},{"code":"required","meaning":"A required field is missing.","example_pointer":"/title/sr"},{"code":"invalid_type","meaning":"The wrong JSON type.","example_pointer":"/structure/rooms"},{"code":"too_small","meaning":"Below a minimum (length or value).","example_pointer":"/description/sr"},{"code":"too_big","meaning":"Above a maximum (length or value).","example_pointer":"/price/amount"},{"code":"invalid_enum","meaning":"A value outside the vocabulary.","example_pointer":"/structure/heating"},{"code":"invalid_format","meaning":"A malformed id, URL, date or pattern.","example_pointer":"/photos/0/url"}],"x-nk-warning-codes":[],"x-nk-error-example":{"error":{"code":"validation_failed","message":"The query is not valid.","details":[{"pointer":"/limit","code":"too_big","message":"Must be at most 200."}]},"request_id":"0f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a"}}},"/connections/{id}":{"get":{"operationId":"connections.get","tags":["Connections"],"summary":"One connection with counts and the agency summary.","parameters":[{"$ref":"#/components/parameters/NK-Timestamp"},{"$ref":"#/components/parameters/NK-Nonce"},{"$ref":"#/components/parameters/Content-Digest"},{"$ref":"#/components/parameters/NK-Signature"},{"name":"id","in":"path","required":true,"description":"The connection id.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"connection":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"status":{"type":"string","enum":["certifying","active","paused","revoked"]},"environment":{"type":"string","enum":["sandbox","live"]},"agency":{"type":"object","properties":{"name":{"type":"string"},"register_number":{"nullable":true,"type":"string"},"verification_status":{"type":"string","enum":["unverified","pending","verified","rejected"]},"listing_quota":{"type":"object","properties":{"used":{"type":"integer","minimum":0,"maximum":9007199254740991},"limit":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["used","limit"],"additionalProperties":false},"photo_limit":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["name","register_number","verification_status","listing_quota","photo_limit"],"additionalProperties":false},"created_at":{"type":"string"},"redeemed_at":{"nullable":true,"type":"string"},"certified_at":{"nullable":true,"type":"string"},"paused":{"nullable":true,"type":"object","properties":{"at":{"type":"string"},"by":{"type":"string","enum":["agency","staff"]},"reason":{"nullable":true,"type":"string"}},"required":["at","by","reason"],"additionalProperties":false},"counts":{"type":"object","properties":{"live":{"type":"integer","minimum":0,"maximum":9007199254740991},"paused":{"type":"integer","minimum":0,"maximum":9007199254740991},"review":{"type":"integer","minimum":0,"maximum":9007199254740991},"failed":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["live","paused","review","failed"],"additionalProperties":false},"last_push_at":{"nullable":true,"type":"string"}},"required":["id","status","environment","agency","created_at","redeemed_at","certified_at","paused","counts","last_push_at"],"additionalProperties":false}},"required":["connection"],"additionalProperties":false},"example":{"connection":{"id":"9b1d6c2e-4f3a-4c8e-9a71-2d5e8f0b3c44","status":"active","environment":"sandbox","agency":{"name":"Test agencija","register_number":"123/2024","verification_status":"verified","listing_quota":{"used":0,"limit":50},"photo_limit":30},"created_at":"2026-10-12T07:58:00Z","redeemed_at":"2026-10-12T08:00:00Z","certified_at":"2026-10-12T09:00:00Z","paused":null,"counts":{"live":0,"paused":0,"review":0,"failed":0},"last_push_at":null}}}}},"404":{"description":"`connection_not_found`: Unknown id, or another app's connection.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"error":{"code":"connection_not_found","message":"No such connection."},"request_id":"0f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a"}}}},"default":{"description":"Any refusal of the signed-request checks (x-nk-shared-errors) or 500 internal_error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-nk-success-status":200,"x-nk-errors":[{"code":"connection_not_found","status":404,"when":"Unknown id, or another app's connection.","fix":"Check the id and the key environment."}],"x-nk-detail-codes":[],"x-nk-warning-codes":[],"x-nk-error-example":{"error":{"code":"connection_not_found","message":"No such connection."},"request_id":"0f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a"}},"delete":{"operationId":"connections.revoke","tags":["Connections"],"summary":"Disconnect: the listings are released to the agency.","parameters":[{"$ref":"#/components/parameters/NK-Timestamp"},{"$ref":"#/components/parameters/NK-Nonce"},{"$ref":"#/components/parameters/Content-Digest"},{"$ref":"#/components/parameters/NK-Signature"},{"name":"id","in":"path","required":true,"description":"The connection id.","schema":{"type":"string","format":"uuid"}},{"name":"reason","in":"query","required":false,"schema":{"type":"string","maxLength":200}}],"responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"connection":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"status":{"type":"string","enum":["certifying","active","paused","revoked"]},"environment":{"type":"string","enum":["sandbox","live"]},"agency":{"type":"object","properties":{"name":{"type":"string"},"register_number":{"nullable":true,"type":"string"},"verification_status":{"type":"string","enum":["unverified","pending","verified","rejected"]},"listing_quota":{"type":"object","properties":{"used":{"type":"integer","minimum":0,"maximum":9007199254740991},"limit":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["used","limit"],"additionalProperties":false},"photo_limit":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["name","register_number","verification_status","listing_quota","photo_limit"],"additionalProperties":false},"created_at":{"type":"string"},"redeemed_at":{"nullable":true,"type":"string"},"certified_at":{"nullable":true,"type":"string"},"paused":{"nullable":true,"type":"object","properties":{"at":{"type":"string"},"by":{"type":"string","enum":["agency","staff"]},"reason":{"nullable":true,"type":"string"}},"required":["at","by","reason"],"additionalProperties":false},"counts":{"type":"object","properties":{"live":{"type":"integer","minimum":0,"maximum":9007199254740991},"paused":{"type":"integer","minimum":0,"maximum":9007199254740991},"review":{"type":"integer","minimum":0,"maximum":9007199254740991},"failed":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["live","paused","review","failed"],"additionalProperties":false},"last_push_at":{"nullable":true,"type":"string"}},"required":["id","status","environment","agency","created_at","redeemed_at","certified_at","paused","counts","last_push_at"],"additionalProperties":false}},"required":["connection"],"additionalProperties":false},"example":{"connection":{"id":"9b1d6c2e-4f3a-4c8e-9a71-2d5e8f0b3c44","status":"revoked","environment":"sandbox","agency":{"name":"Test agencija","register_number":"123/2024","verification_status":"verified","listing_quota":{"used":0,"limit":50},"photo_limit":30},"created_at":"2026-10-12T07:58:00Z","redeemed_at":"2026-10-12T08:00:00Z","certified_at":"2026-10-12T09:00:00Z","paused":null,"counts":{"live":0,"paused":0,"review":0,"failed":0},"last_push_at":null}}}}},"404":{"description":"`connection_not_found`: Unknown id, or another app's connection.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"error":{"code":"connection_not_found","message":"No such connection."},"request_id":"0f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a"}}}},"422":{"description":"`validation_failed`: The payload is invalid (details array).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"default":{"description":"Any refusal of the signed-request checks (x-nk-shared-errors) or 500 internal_error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-nk-success-status":200,"x-nk-errors":[{"code":"connection_not_found","status":404,"when":"Unknown id, or another app's connection.","fix":"Check the id and the key environment."},{"code":"validation_failed","status":422,"when":"The payload is invalid (details array).","fix":"Fix the fields at the pointers."}],"x-nk-detail-codes":[{"code":"unknown_field","meaning":"A key the schema doesn't know.","example_pointer":"/structure/balcon"},{"code":"required","meaning":"A required field is missing.","example_pointer":"/title/sr"},{"code":"invalid_type","meaning":"The wrong JSON type.","example_pointer":"/structure/rooms"},{"code":"too_small","meaning":"Below a minimum (length or value).","example_pointer":"/description/sr"},{"code":"too_big","meaning":"Above a maximum (length or value).","example_pointer":"/price/amount"},{"code":"invalid_enum","meaning":"A value outside the vocabulary.","example_pointer":"/structure/heating"},{"code":"invalid_format","meaning":"A malformed id, URL, date or pattern.","example_pointer":"/photos/0/url"}],"x-nk-warning-codes":[],"x-nk-error-example":{"error":{"code":"connection_not_found","message":"No such connection."},"request_id":"0f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a"}}},"/connections/{id}/listings/{external_id}":{"put":{"operationId":"listings.put","tags":["Listings"],"summary":"Create or fully replace one listing.","parameters":[{"$ref":"#/components/parameters/NK-Timestamp"},{"$ref":"#/components/parameters/NK-Nonce"},{"$ref":"#/components/parameters/Content-Digest"},{"$ref":"#/components/parameters/NK-Signature"},{"name":"id","in":"path","required":true,"description":"The connection id.","schema":{"type":"string","format":"uuid"}},{"name":"external_id","in":"path","required":true,"description":"Your listing id (the payload’s external_id).","schema":{"type":"string","pattern":"^[A-Za-z0-9._:-]{1,64}$"}}],"responses":{"202":{"description":"Accepted.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"position":{"type":"integer","minimum":0,"maximum":9007199254740991},"external_id":{"type":"string"},"result":{"type":"string","enum":["accepted","unchanged","needs_review","rejected","removed"]},"candidate_id":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"listing_id":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"public_url":{"nullable":true,"type":"string"},"failure_code":{"nullable":true,"type":"string","enum":["unmappable_category","missing_required","invalid_payload","quota_exceeded","duplicate","geo_unresolved","schema_invalid","photo_fetch_failed","photo_minimum","mandate_missing","moderation_blocked","certification_rejected","worker_error"]},"details":{"nullable":true,"anyOf":[{"type":"array","items":{"type":"object","properties":{"pointer":{"type":"string"},"code":{"type":"string","enum":["unknown_field","required","invalid_type","too_small","too_big","invalid_enum","invalid_format","unknown_place","duplicate_external_id","duplicate_photo_url"]},"message":{"type":"string"}},"required":["pointer","code","message"],"additionalProperties":false}},{"type":"object","additionalProperties":{}}]},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["agent_not_member","virtual_tour_dropped","commission_dropped","field_not_applicable","coordinates_outside_place","photo_cap_applied"]},"pointer":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["position","external_id","result","candidate_id","listing_id","public_url","failure_code","details","warnings"],"additionalProperties":false}},"required":["item"],"additionalProperties":false},"example":{"item":{"position":0,"external_id":"REAA-12345","result":"accepted","candidate_id":"c7e3a1d2-5b6f-4e8a-9c0d-1e2f3a4b5c6d","listing_id":null,"public_url":null,"failure_code":null,"details":null,"warnings":[]}}}}},"400":{"description":"`body_invalid`: The body is not a JSON object.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"`connection_not_found`: Unknown id, or another app's connection.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"`connection_not_active`: details.status is pending, paused or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"`validation_failed`: The payload is invalid (details array).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"error":{"code":"validation_failed","message":"The listing is not valid.","details":[{"pointer":"/structure/area_sqm","code":"too_small","message":"Must be greater than 0."},{"pointer":"/structure/balcon","code":"unknown_field","message":"Unknown field."}]},"request_id":"0f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a"}}}},"429":{"description":"`connection_item_limit`: Over the hourly item budget.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"default":{"description":"Any refusal of the signed-request checks (x-nk-shared-errors) or 500 internal_error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-nk-success-status":202,"x-nk-errors":[{"code":"body_invalid","status":400,"when":"The body is not a JSON object.","fix":"Send valid JSON."},{"code":"connection_not_found","status":404,"when":"Unknown id, or another app's connection.","fix":"Check the id and the key environment."},{"code":"connection_not_active","status":409,"when":"details.status is pending, paused or revoked.","fix":"Wait for the agency, or stop pushing."},{"code":"validation_failed","status":422,"when":"The payload is invalid (details array).","fix":"Fix the fields at the pointers."},{"code":"connection_item_limit","status":429,"when":"Over the hourly item budget.","fix":"Wait Retry-After, spread pushes."}],"x-nk-detail-codes":[{"code":"unknown_field","meaning":"A key the schema doesn't know.","example_pointer":"/structure/balcon"},{"code":"required","meaning":"A required field is missing.","example_pointer":"/title/sr"},{"code":"invalid_type","meaning":"The wrong JSON type.","example_pointer":"/structure/rooms"},{"code":"too_small","meaning":"Below a minimum (length or value).","example_pointer":"/description/sr"},{"code":"too_big","meaning":"Above a maximum (length or value).","example_pointer":"/price/amount"},{"code":"invalid_enum","meaning":"A value outside the vocabulary.","example_pointer":"/structure/heating"},{"code":"invalid_format","meaning":"A malformed id, URL, date or pattern.","example_pointer":"/photos/0/url"},{"code":"unknown_place","meaning":"place_id is not a city or municipality we know.","example_pointer":"/location/place_id"},{"code":"duplicate_external_id","meaning":"One external_id twice in one batch.","example_pointer":"/listings/3/external_id"},{"code":"duplicate_photo_url","meaning":"One photo URL listed twice.","example_pointer":"/photos/2/url"}],"x-nk-warning-codes":[{"code":"agent_not_member","meaning":"agent.email is not an active member of the agency; the listing has no agent.","example_pointer":"/agent/email"},{"code":"virtual_tour_dropped","meaning":"The agency's plan has no virtual tours; the URL was not stored.","example_pointer":"/virtual_tour_url"},{"code":"commission_dropped","meaning":"The agency is a bank; commission was not stored.","example_pointer":"/commission"},{"code":"field_not_applicable","meaning":"A field that does not apply to the category was not stored.","example_pointer":"/structure/floor"},{"code":"coordinates_outside_place","meaning":"The coordinates fall outside the place's boundary (kept).","example_pointer":"/location"},{"code":"photo_cap_applied","meaning":"More photos than the agency's plan allows; the extra ones were dropped.","example_pointer":"/photos"}],"x-nk-error-example":{"error":{"code":"validation_failed","message":"The listing is not valid.","details":[{"pointer":"/structure/area_sqm","code":"too_small","message":"Must be greater than 0."},{"pointer":"/structure/balcon","code":"unknown_field","message":"Unknown field."}]},"request_id":"0f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Listing"},"example":{"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}}}}}},"/connections/{id}/batches":{"post":{"operationId":"batches.create","tags":["Batches"],"summary":"Up to max_batch_items upserts in one call.","parameters":[{"$ref":"#/components/parameters/NK-Timestamp"},{"$ref":"#/components/parameters/NK-Nonce"},{"$ref":"#/components/parameters/Content-Digest"},{"$ref":"#/components/parameters/NK-Signature"},{"$ref":"#/components/parameters/Idempotency-Key"},{"name":"id","in":"path","required":true,"description":"The connection id.","schema":{"type":"string","format":"uuid"}}],"responses":{"202":{"description":"Accepted.","content":{"application/json":{"schema":{"type":"object","properties":{"batch":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"status":{"type":"string","enum":["received","processing","completed","failed"]},"counts":{"type":"object","properties":{"accepted":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"unchanged":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"needs_review":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"rejected":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"removed":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["accepted","unchanged","needs_review","rejected","removed","total"],"additionalProperties":false},"items":{"type":"array","items":{"type":"object","properties":{"position":{"type":"integer","minimum":0,"maximum":9007199254740991},"external_id":{"type":"string"},"result":{"type":"string","enum":["accepted","unchanged","needs_review","rejected","removed"]},"candidate_id":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"listing_id":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"public_url":{"nullable":true,"type":"string"},"failure_code":{"nullable":true,"type":"string","enum":["unmappable_category","missing_required","invalid_payload","quota_exceeded","duplicate","geo_unresolved","schema_invalid","photo_fetch_failed","photo_minimum","mandate_missing","moderation_blocked","certification_rejected","worker_error"]},"details":{"nullable":true,"anyOf":[{"type":"array","items":{"type":"object","properties":{"pointer":{"type":"string"},"code":{"type":"string","enum":["unknown_field","required","invalid_type","too_small","too_big","invalid_enum","invalid_format","unknown_place","duplicate_external_id","duplicate_photo_url"]},"message":{"type":"string"}},"required":["pointer","code","message"],"additionalProperties":false}},{"type":"object","additionalProperties":{}}]},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["agent_not_member","virtual_tour_dropped","commission_dropped","field_not_applicable","coordinates_outside_place","photo_cap_applied"]},"pointer":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["position","external_id","result","candidate_id","listing_id","public_url","failure_code","details","warnings"],"additionalProperties":false}}},"required":["id","status","counts","items"],"additionalProperties":false}},"required":["batch"],"additionalProperties":false},"example":{"batch":{"id":"b52d3e4f-6a7b-4c8d-9e0f-1a2b3c4d5e6f","status":"received","counts":{"total":3,"accepted":1,"unchanged":1,"needs_review":0,"rejected":1,"removed":0},"items":[{"position":0,"external_id":"REAA-12345","result":"unchanged","candidate_id":"c7e3a1d2-5b6f-4e8a-9c0d-1e2f3a4b5c6d","listing_id":null,"public_url":null,"failure_code":null,"details":null,"warnings":[]},{"position":1,"external_id":"REAA-12346","result":"accepted","candidate_id":"c7e3a1d2-5b6f-4e8a-9c0d-1e2f3a4b5c6d","listing_id":null,"public_url":null,"failure_code":null,"details":null,"warnings":[]},{"position":2,"external_id":"REAA-12347","result":"rejected","candidate_id":null,"listing_id":null,"public_url":null,"failure_code":"geo_unresolved","details":[{"pointer":"/listings/2/location/place_id","code":"unknown_place","message":"No such place."}],"warnings":[]}]}}}}},"400":{"description":"`body_invalid`: The body is not a JSON object.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"`connection_not_found`: Unknown id, or another app's connection.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"`connection_not_active`: details.status is pending, paused or revoked. `idempotency_in_progress`: The same key while the first request runs (details.batch_id).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"error":{"code":"idempotency_in_progress","message":"A request with this Idempotency-Key is still running.","details":{"batch_id":"b52d3e4f-6a7b-4c8d-9e0f-1a2b3c4d5e6f"}},"request_id":"0f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a"}}}},"422":{"description":"`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).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"`connection_item_limit`: Over the hourly item budget.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"default":{"description":"Any refusal of the signed-request checks (x-nk-shared-errors) or 500 internal_error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-nk-success-status":202,"x-nk-errors":[{"code":"body_invalid","status":400,"when":"The body is not a JSON object.","fix":"Send valid JSON."},{"code":"connection_not_found","status":404,"when":"Unknown id, or another app's connection.","fix":"Check the id and the key environment."},{"code":"connection_not_active","status":409,"when":"details.status is pending, paused or revoked.","fix":"Wait for the agency, or stop pushing."},{"code":"idempotency_in_progress","status":409,"when":"The same key while the first request runs (details.batch_id).","fix":"Poll the batch."},{"code":"validation_failed","status":422,"when":"The payload is invalid (details array).","fix":"Fix the fields at the pointers."},{"code":"batch_too_large","status":422,"when":"More than max_batch_items, more than 50 to validate, or more than 5,000 reconcile ids.","fix":"Split."},{"code":"duplicate_external_id","status":422,"when":"One external_id twice in a batch.","fix":"Send each listing once."},{"code":"idempotency_key_reused","status":422,"when":"The same key with a different body, within 7 days.","fix":"A new key per distinct body."},{"code":"connection_item_limit","status":429,"when":"Over the hourly item budget.","fix":"Wait Retry-After, spread pushes."}],"x-nk-detail-codes":[{"code":"unknown_field","meaning":"A key the schema doesn't know.","example_pointer":"/structure/balcon"},{"code":"required","meaning":"A required field is missing.","example_pointer":"/title/sr"},{"code":"invalid_type","meaning":"The wrong JSON type.","example_pointer":"/structure/rooms"},{"code":"too_small","meaning":"Below a minimum (length or value).","example_pointer":"/description/sr"},{"code":"too_big","meaning":"Above a maximum (length or value).","example_pointer":"/price/amount"},{"code":"invalid_enum","meaning":"A value outside the vocabulary.","example_pointer":"/structure/heating"},{"code":"invalid_format","meaning":"A malformed id, URL, date or pattern.","example_pointer":"/photos/0/url"},{"code":"unknown_place","meaning":"place_id is not a city or municipality we know.","example_pointer":"/location/place_id"},{"code":"duplicate_external_id","meaning":"One external_id twice in one batch.","example_pointer":"/listings/3/external_id"},{"code":"duplicate_photo_url","meaning":"One photo URL listed twice.","example_pointer":"/photos/2/url"}],"x-nk-warning-codes":[{"code":"agent_not_member","meaning":"agent.email is not an active member of the agency; the listing has no agent.","example_pointer":"/agent/email"},{"code":"virtual_tour_dropped","meaning":"The agency's plan has no virtual tours; the URL was not stored.","example_pointer":"/virtual_tour_url"},{"code":"commission_dropped","meaning":"The agency is a bank; commission was not stored.","example_pointer":"/commission"},{"code":"field_not_applicable","meaning":"A field that does not apply to the category was not stored.","example_pointer":"/structure/floor"},{"code":"coordinates_outside_place","meaning":"The coordinates fall outside the place's boundary (kept).","example_pointer":"/location"},{"code":"photo_cap_applied","meaning":"More photos than the agency's plan allows; the extra ones were dropped.","example_pointer":"/photos"}],"x-nk-error-example":{"error":{"code":"idempotency_in_progress","message":"A request with this Idempotency-Key is still running.","details":{"batch_id":"b52d3e4f-6a7b-4c8d-9e0f-1a2b3c4d5e6f"}},"request_id":"0f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"listings":{"minItems":1,"type":"array","items":{"$ref":"#/components/schemas/Listing"}}},"required":["listings"],"additionalProperties":false},"example":{"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}]}}}}}},"/connections/{id}/listings/{external_id}/remove":{"post":{"operationId":"listings.remove","tags":["Listings"],"summary":"Remove a listing (sold, rented, withdrawn, expired, error).","parameters":[{"$ref":"#/components/parameters/NK-Timestamp"},{"$ref":"#/components/parameters/NK-Nonce"},{"$ref":"#/components/parameters/Content-Digest"},{"$ref":"#/components/parameters/NK-Signature"},{"name":"id","in":"path","required":true,"description":"The connection id.","schema":{"type":"string","format":"uuid"}},{"name":"external_id","in":"path","required":true,"description":"Your listing id (the payload’s external_id).","schema":{"type":"string","pattern":"^[A-Za-z0-9._:-]{1,64}$"}}],"responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"position":{"type":"integer","minimum":0,"maximum":9007199254740991},"external_id":{"type":"string"},"result":{"type":"string","enum":["accepted","unchanged","needs_review","rejected","removed"]},"candidate_id":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"listing_id":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"public_url":{"nullable":true,"type":"string"},"failure_code":{"nullable":true,"type":"string","enum":["unmappable_category","missing_required","invalid_payload","quota_exceeded","duplicate","geo_unresolved","schema_invalid","photo_fetch_failed","photo_minimum","mandate_missing","moderation_blocked","certification_rejected","worker_error"]},"details":{"nullable":true,"anyOf":[{"type":"array","items":{"type":"object","properties":{"pointer":{"type":"string"},"code":{"type":"string","enum":["unknown_field","required","invalid_type","too_small","too_big","invalid_enum","invalid_format","unknown_place","duplicate_external_id","duplicate_photo_url"]},"message":{"type":"string"}},"required":["pointer","code","message"],"additionalProperties":false}},{"type":"object","additionalProperties":{}}]},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["agent_not_member","virtual_tour_dropped","commission_dropped","field_not_applicable","coordinates_outside_place","photo_cap_applied"]},"pointer":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["position","external_id","result","candidate_id","listing_id","public_url","failure_code","details","warnings"],"additionalProperties":false}},"required":["item"],"additionalProperties":false},"example":{"item":{"position":0,"external_id":"REAA-12345","result":"removed","candidate_id":"c7e3a1d2-5b6f-4e8a-9c0d-1e2f3a4b5c6d","listing_id":"e19b2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c4d","public_url":null,"failure_code":null,"details":null,"warnings":[]}}}}},"400":{"description":"`body_invalid`: The body is not a JSON object.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"`connection_not_found`: Unknown id, or another app's connection. `listing_not_found`: No staged listing with that external_id on this connection.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"error":{"code":"listing_not_found","message":"No listing with this external_id on this connection."},"request_id":"0f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a"}}}},"409":{"description":"`connection_not_active`: details.status is pending, paused or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"`validation_failed`: The payload is invalid (details array).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"default":{"description":"Any refusal of the signed-request checks (x-nk-shared-errors) or 500 internal_error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-nk-success-status":200,"x-nk-errors":[{"code":"body_invalid","status":400,"when":"The body is not a JSON object.","fix":"Send valid JSON."},{"code":"connection_not_found","status":404,"when":"Unknown id, or another app's connection.","fix":"Check the id and the key environment."},{"code":"listing_not_found","status":404,"when":"No staged listing with that external_id on this connection.","fix":"—"},{"code":"connection_not_active","status":409,"when":"details.status is pending, paused or revoked.","fix":"Wait for the agency, or stop pushing."},{"code":"validation_failed","status":422,"when":"The payload is invalid (details array).","fix":"Fix the fields at the pointers."}],"x-nk-detail-codes":[{"code":"unknown_field","meaning":"A key the schema doesn't know.","example_pointer":"/structure/balcon"},{"code":"required","meaning":"A required field is missing.","example_pointer":"/title/sr"},{"code":"invalid_type","meaning":"The wrong JSON type.","example_pointer":"/structure/rooms"},{"code":"too_small","meaning":"Below a minimum (length or value).","example_pointer":"/description/sr"},{"code":"too_big","meaning":"Above a maximum (length or value).","example_pointer":"/price/amount"},{"code":"invalid_enum","meaning":"A value outside the vocabulary.","example_pointer":"/structure/heating"},{"code":"invalid_format","meaning":"A malformed id, URL, date or pattern.","example_pointer":"/photos/0/url"}],"x-nk-warning-codes":[],"x-nk-error-example":{"error":{"code":"listing_not_found","message":"No listing with this external_id on this connection."},"request_id":"0f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","enum":["sold","rented","withdrawn","expired","error"]}},"required":["reason"],"additionalProperties":false},"example":{"reason":"sold"}}}}}},"/connections/{id}/listings":{"get":{"operationId":"listings.list","tags":["Listings"],"summary":"The reconcile view: what Novi Kvadrat holds for this connection.","parameters":[{"$ref":"#/components/parameters/NK-Timestamp"},{"$ref":"#/components/parameters/NK-Nonce"},{"$ref":"#/components/parameters/Content-Digest"},{"$ref":"#/components/parameters/NK-Signature"},{"name":"id","in":"path","required":true,"description":"The connection id.","schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","maxLength":512}},{"name":"limit","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{1,3}$"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","maxLength":32}}],"responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"external_id":{"type":"string"},"transaction":{"nullable":true,"type":"string","enum":["sale","rent"]},"status":{"type":"string","enum":["pending","imported","failed","skipped","needs_review","removed","validated"]},"listing_status":{"nullable":true,"type":"string"},"moderation_status":{"nullable":true,"type":"string"},"listing_id":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"public_url":{"nullable":true,"type":"string"},"payload_digest":{"nullable":true,"type":"string"},"imported_digest":{"nullable":true,"type":"string"},"updated_at":{"nullable":true,"type":"string"},"failure_code":{"nullable":true,"type":"string","enum":["unmappable_category","missing_required","invalid_payload","quota_exceeded","duplicate","geo_unresolved","schema_invalid","photo_fetch_failed","photo_minimum","mandate_missing","moderation_blocked","certification_rejected","worker_error"]}},"required":["external_id","transaction","status","listing_status","moderation_status","listing_id","public_url","payload_digest","imported_digest","updated_at","failure_code"],"additionalProperties":false}},"next_cursor":{"nullable":true,"type":"string"}},"required":["items","next_cursor"],"additionalProperties":false},"example":{"items":[{"external_id":"REAA-12345","transaction":"sale","status":"imported","listing_status":"published","moderation_status":"approved","listing_id":"e19b2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c4d","public_url":"https://novikvadrat.rs/en/listing/trosoban-stan-vracar-a1b2c3","payload_digest":"3f2a","imported_digest":"3f2a","updated_at":"2026-10-12T08:01:00Z","failure_code":null}],"next_cursor":null}}}},"404":{"description":"`connection_not_found`: Unknown id, or another app's connection.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"`connection_not_active`: details.status is pending, paused or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"error":{"code":"connection_not_active","message":"The connection is revoked.","details":{"status":"revoked"}},"request_id":"0f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a"}}}},"422":{"description":"`validation_failed`: The payload is invalid (details array).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"default":{"description":"Any refusal of the signed-request checks (x-nk-shared-errors) or 500 internal_error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-nk-success-status":200,"x-nk-errors":[{"code":"connection_not_found","status":404,"when":"Unknown id, or another app's connection.","fix":"Check the id and the key environment."},{"code":"connection_not_active","status":409,"when":"details.status is pending, paused or revoked.","fix":"Wait for the agency, or stop pushing."},{"code":"validation_failed","status":422,"when":"The payload is invalid (details array).","fix":"Fix the fields at the pointers."}],"x-nk-detail-codes":[{"code":"unknown_field","meaning":"A key the schema doesn't know.","example_pointer":"/structure/balcon"},{"code":"required","meaning":"A required field is missing.","example_pointer":"/title/sr"},{"code":"invalid_type","meaning":"The wrong JSON type.","example_pointer":"/structure/rooms"},{"code":"too_small","meaning":"Below a minimum (length or value).","example_pointer":"/description/sr"},{"code":"too_big","meaning":"Above a maximum (length or value).","example_pointer":"/price/amount"},{"code":"invalid_enum","meaning":"A value outside the vocabulary.","example_pointer":"/structure/heating"},{"code":"invalid_format","meaning":"A malformed id, URL, date or pattern.","example_pointer":"/photos/0/url"}],"x-nk-warning-codes":[],"x-nk-error-example":{"error":{"code":"connection_not_active","message":"The connection is revoked.","details":{"status":"revoked"}},"request_id":"0f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a"}}},"/connections/{id}/reconcile":{"post":{"operationId":"reconcile","tags":["Listings"],"summary":"Archive everything live that is not in the list.","parameters":[{"$ref":"#/components/parameters/NK-Timestamp"},{"$ref":"#/components/parameters/NK-Nonce"},{"$ref":"#/components/parameters/Content-Digest"},{"$ref":"#/components/parameters/NK-Signature"},{"$ref":"#/components/parameters/Idempotency-Key"},{"name":"id","in":"path","required":true,"description":"The connection id.","schema":{"type":"string","format":"uuid"}}],"responses":{"202":{"description":"Accepted.","content":{"application/json":{"schema":{"type":"object","properties":{"batch":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"kind":{"type":"string","enum":["reconcile"]},"to_remove":{"type":"integer","minimum":0,"maximum":9007199254740991},"removed_queued":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["id","kind","to_remove","removed_queued"],"additionalProperties":false}},"required":["batch"],"additionalProperties":false},"example":{"batch":{"id":"f08e1d2c-3b4a-4f5e-8d6c-7b8a9f0e1d2c","kind":"reconcile","to_remove":2,"removed_queued":2}}}}},"400":{"description":"`body_invalid`: The body is not a JSON object.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"`connection_not_found`: Unknown id, or another app's connection.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"`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).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"error":{"code":"mass_removal_requires_confirmation","message":"This would remove 41 of 120 live listings.","details":{"live":120,"missing":41,"threshold_ratio":0.2,"threshold_min":5}},"request_id":"0f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a"}}}},"422":{"description":"`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).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"default":{"description":"Any refusal of the signed-request checks (x-nk-shared-errors) or 500 internal_error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-nk-success-status":202,"x-nk-errors":[{"code":"body_invalid","status":400,"when":"The body is not a JSON object.","fix":"Send valid JSON."},{"code":"connection_not_found","status":404,"when":"Unknown id, or another app's connection.","fix":"Check the id and the key environment."},{"code":"connection_not_active","status":409,"when":"details.status is pending, paused or revoked.","fix":"Wait for the agency, or stop pushing."},{"code":"idempotency_in_progress","status":409,"when":"The same key while the first request runs (details.batch_id).","fix":"Poll the batch."},{"code":"mass_removal_requires_confirmation","status":409,"when":"A reconcile would remove too much.","fix":"Check, then confirm."},{"code":"validation_failed","status":422,"when":"The payload is invalid (details array).","fix":"Fix the fields at the pointers."},{"code":"batch_too_large","status":422,"when":"More than max_batch_items, more than 50 to validate, or more than 5,000 reconcile ids.","fix":"Split."},{"code":"idempotency_key_reused","status":422,"when":"The same key with a different body, within 7 days.","fix":"A new key per distinct body."}],"x-nk-detail-codes":[{"code":"unknown_field","meaning":"A key the schema doesn't know.","example_pointer":"/structure/balcon"},{"code":"required","meaning":"A required field is missing.","example_pointer":"/title/sr"},{"code":"invalid_type","meaning":"The wrong JSON type.","example_pointer":"/structure/rooms"},{"code":"too_small","meaning":"Below a minimum (length or value).","example_pointer":"/description/sr"},{"code":"too_big","meaning":"Above a maximum (length or value).","example_pointer":"/price/amount"},{"code":"invalid_enum","meaning":"A value outside the vocabulary.","example_pointer":"/structure/heating"},{"code":"invalid_format","meaning":"A malformed id, URL, date or pattern.","example_pointer":"/photos/0/url"}],"x-nk-warning-codes":[],"x-nk-error-example":{"error":{"code":"mass_removal_requires_confirmation","message":"This would remove 41 of 120 live listings.","details":{"live":120,"missing":41,"threshold_ratio":0.2,"threshold_min":5}},"request_id":"0f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"external_ids":{"type":"array","items":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9._:-]*$"}},"confirm_mass_removal":{"type":"boolean"}},"required":["external_ids"],"additionalProperties":false},"example":{"external_ids":["REAA-12345","REAA-12346"]}}}}}},"/batches/{id}":{"get":{"operationId":"batches.get","tags":["Batches"],"summary":"Status and per-item results of a push.","parameters":[{"$ref":"#/components/parameters/NK-Timestamp"},{"$ref":"#/components/parameters/NK-Nonce"},{"$ref":"#/components/parameters/Content-Digest"},{"$ref":"#/components/parameters/NK-Signature"},{"name":"id","in":"path","required":true,"description":"The batch id.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"batch":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"kind":{"type":"string","enum":["single","batch","remove","reconcile"]},"status":{"type":"string","enum":["received","processing","completed","failed"]},"counts":{"type":"object","properties":{"accepted":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"unchanged":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"needs_review":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"rejected":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"removed":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["accepted","unchanged","needs_review","rejected","removed","total"],"additionalProperties":false}},"required":["id","kind","status"],"additionalProperties":{}},"items":{"type":"array","items":{"type":"object","properties":{"position":{"type":"integer","minimum":0,"maximum":9007199254740991},"external_id":{"type":"string"},"result":{"type":"string","enum":["accepted","unchanged","needs_review","rejected","removed"]},"candidate_id":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"listing_id":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"public_url":{"nullable":true,"type":"string"},"failure_code":{"nullable":true,"type":"string","enum":["unmappable_category","missing_required","invalid_payload","quota_exceeded","duplicate","geo_unresolved","schema_invalid","photo_fetch_failed","photo_minimum","mandate_missing","moderation_blocked","certification_rejected","worker_error"]},"details":{"nullable":true,"anyOf":[{"type":"array","items":{"type":"object","properties":{"pointer":{"type":"string"},"code":{"type":"string","enum":["unknown_field","required","invalid_type","too_small","too_big","invalid_enum","invalid_format","unknown_place","duplicate_external_id","duplicate_photo_url"]},"message":{"type":"string"}},"required":["pointer","code","message"],"additionalProperties":false}},{"type":"object","additionalProperties":{}}]},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["agent_not_member","virtual_tour_dropped","commission_dropped","field_not_applicable","coordinates_outside_place","photo_cap_applied"]},"pointer":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}}},"required":["position","external_id","result","candidate_id","listing_id","public_url","failure_code","details","warnings"],"additionalProperties":false}}},"required":["batch","items"],"additionalProperties":false},"example":{"batch":{"id":"b52d3e4f-6a7b-4c8d-9e0f-1a2b3c4d5e6f","kind":"batch","status":"completed","counts":{"total":2,"accepted":1,"unchanged":1,"needs_review":0,"rejected":0,"removed":0}},"items":[{"position":0,"external_id":"REAA-12345","result":"unchanged","candidate_id":"c7e3a1d2-5b6f-4e8a-9c0d-1e2f3a4b5c6d","listing_id":null,"public_url":null,"failure_code":null,"details":null,"warnings":[]},{"position":1,"external_id":"REAA-12346","result":"accepted","candidate_id":"c7e3a1d2-5b6f-4e8a-9c0d-1e2f3a4b5c6d","listing_id":null,"public_url":null,"failure_code":null,"details":null,"warnings":[]}]}}}},"404":{"description":"`batch_not_found`: Unknown batch id, or another app's batch.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"error":{"code":"batch_not_found","message":"No such batch."},"request_id":"0f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a"}}}},"default":{"description":"Any refusal of the signed-request checks (x-nk-shared-errors) or 500 internal_error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-nk-success-status":200,"x-nk-errors":[{"code":"batch_not_found","status":404,"when":"Unknown batch id, or another app's batch.","fix":"—"}],"x-nk-detail-codes":[],"x-nk-warning-codes":[],"x-nk-error-example":{"error":{"code":"batch_not_found","message":"No such batch."},"request_id":"0f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a"}}},"/validate":{"post":{"operationId":"validate","tags":["Validate"],"summary":"Dry run: validate without storing anything.","parameters":[{"$ref":"#/components/parameters/NK-Timestamp"},{"$ref":"#/components/parameters/NK-Nonce"},{"$ref":"#/components/parameters/Content-Digest"},{"$ref":"#/components/parameters/NK-Signature"}],"responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"results":{"type":"array","items":{"type":"object","properties":{"position":{"type":"integer","minimum":0,"maximum":9007199254740991},"external_id":{"nullable":true,"type":"string"},"valid":{"type":"boolean"},"errors":{"type":"array","items":{"type":"object","properties":{"pointer":{"type":"string"},"code":{"type":"string","enum":["unknown_field","required","invalid_type","too_small","too_big","invalid_enum","invalid_format","unknown_place","duplicate_external_id","duplicate_photo_url","unmappable_category","missing_required","invalid_payload","quota_exceeded","duplicate","geo_unresolved","schema_invalid","photo_fetch_failed","photo_minimum","mandate_missing","moderation_blocked","certification_rejected","worker_error"]},"message":{"type":"string"}},"required":["pointer","code","message"],"additionalProperties":false}},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["agent_not_member","virtual_tour_dropped","commission_dropped","field_not_applicable","coordinates_outside_place","photo_cap_applied"]},"pointer":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"mapped_preview":{"nullable":true,"type":"object","additionalProperties":{}}},"required":["position","external_id","valid","errors","warnings","mapped_preview"],"additionalProperties":false}}},"required":["results"],"additionalProperties":false},"example":{"results":[{"position":0,"external_id":"REAA-12345","valid":true,"errors":[],"warnings":[{"pointer":"/agent/email","code":"agent_not_member","message":"This address is not a member of the agency."}],"mapped_preview":{"table":"sale_listings","row":{"title":"Trosoban stan, Vračar"}}}]}}}},"400":{"description":"`body_invalid`: The body is not a JSON object.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"`connection_not_found`: Unknown id, or another app's connection.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"`connection_not_active`: details.status is pending, paused or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"422":{"description":"`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).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"error":{"code":"batch_too_large","message":"Validate takes at most 50 listings."},"request_id":"0f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a"}}}},"default":{"description":"Any refusal of the signed-request checks (x-nk-shared-errors) or 500 internal_error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-nk-success-status":200,"x-nk-errors":[{"code":"body_invalid","status":400,"when":"The body is not a JSON object.","fix":"Send valid JSON."},{"code":"connection_not_found","status":404,"when":"Unknown id, or another app's connection.","fix":"Check the id and the key environment."},{"code":"connection_not_active","status":409,"when":"details.status is pending, paused or revoked.","fix":"Wait for the agency, or stop pushing."},{"code":"validation_failed","status":422,"when":"The payload is invalid (details array).","fix":"Fix the fields at the pointers."},{"code":"batch_too_large","status":422,"when":"More than max_batch_items, more than 50 to validate, or more than 5,000 reconcile ids.","fix":"Split."}],"x-nk-detail-codes":[{"code":"unknown_field","meaning":"A key the schema doesn't know.","example_pointer":"/structure/balcon"},{"code":"required","meaning":"A required field is missing.","example_pointer":"/title/sr"},{"code":"invalid_type","meaning":"The wrong JSON type.","example_pointer":"/structure/rooms"},{"code":"too_small","meaning":"Below a minimum (length or value).","example_pointer":"/description/sr"},{"code":"too_big","meaning":"Above a maximum (length or value).","example_pointer":"/price/amount"},{"code":"invalid_enum","meaning":"A value outside the vocabulary.","example_pointer":"/structure/heating"},{"code":"invalid_format","meaning":"A malformed id, URL, date or pattern.","example_pointer":"/photos/0/url"},{"code":"unknown_place","meaning":"place_id is not a city or municipality we know.","example_pointer":"/location/place_id"},{"code":"duplicate_external_id","meaning":"One external_id twice in one batch.","example_pointer":"/listings/3/external_id"},{"code":"duplicate_photo_url","meaning":"One photo URL listed twice.","example_pointer":"/photos/2/url"}],"x-nk-warning-codes":[{"code":"agent_not_member","meaning":"agent.email is not an active member of the agency; the listing has no agent.","example_pointer":"/agent/email"},{"code":"virtual_tour_dropped","meaning":"The agency's plan has no virtual tours; the URL was not stored.","example_pointer":"/virtual_tour_url"},{"code":"commission_dropped","meaning":"The agency is a bank; commission was not stored.","example_pointer":"/commission"},{"code":"field_not_applicable","meaning":"A field that does not apply to the category was not stored.","example_pointer":"/structure/floor"},{"code":"coordinates_outside_place","meaning":"The coordinates fall outside the place's boundary (kept).","example_pointer":"/location"},{"code":"photo_cap_applied","meaning":"More photos than the agency's plan allows; the extra ones were dropped.","example_pointer":"/photos"}],"x-nk-error-example":{"error":{"code":"batch_too_large","message":"Validate takes at most 50 listings."},"request_id":"0f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"listing":{"$ref":"#/components/schemas/Listing"},"listings":{"minItems":1,"type":"array","items":{"$ref":"#/components/schemas/Listing"}},"connection_id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"additionalProperties":false},"example":{"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"}}}}}},"/vocabularies":{"get":{"operationId":"vocabularies","tags":["Vocabularies"],"summary":"Every enumeration, with labels and per-category attributes.","parameters":[{"$ref":"#/components/parameters/NK-Timestamp"},{"$ref":"#/components/parameters/NK-Nonce"},{"$ref":"#/components/parameters/Content-Digest"},{"$ref":"#/components/parameters/NK-Signature"},{"name":"If-None-Match","in":"header","required":false,"description":"The ETag of a previous answer; when it is still current the answer is 304 with no body.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"version":{"type":"string"},"categories":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"group":{"type":"string"},"labels":{"type":"object","properties":{"en":{"type":"string"},"sr":{"type":"string"}},"required":["en","sr"],"additionalProperties":false}},"required":["code","group","labels"],"additionalProperties":false}},"transaction":{"type":"array","items":{"type":"string"}},"heating":{"type":"array","items":{"type":"string"}},"condition":{"type":"array","items":{"type":"string"}},"furnished":{"type":"array","items":{"type":"string"}},"building_group":{"type":"array","items":{"type":"string"}},"ownership_status":{"type":"array","items":{"type":"string"}},"legalization_status":{"type":"array","items":{"type":"string"}},"rental_type":{"type":"array","items":{"type":"string"}},"room_types":{"type":"array","items":{"type":"string"}},"amenities":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"labels":{"type":"object","properties":{"en":{"type":"string"},"sr":{"type":"string"}},"required":["en","sr"],"additionalProperties":false}},"required":["code","labels"],"additionalProperties":false}},"remove_reasons":{"type":"array","items":{"type":"string"}},"attributes_by_category":{"type":"object","additionalProperties":{}}},"required":["version","categories","transaction","heating","condition","furnished","building_group","ownership_status","legalization_status","rental_type","room_types","amenities","remove_reasons","attributes_by_category"],"additionalProperties":false},"example":{"version":"sha256:9c1f","categories":[{"code":"apartment","group":"residential_apartment","labels":{"en":"Apartment","sr":"Stan"}}],"transaction":["sale","rent"],"heating":["district"],"condition":["lux","renovated","original","renovation_required"],"furnished":["furnished","semi_furnished","unfurnished"],"building_group":["new","old"],"ownership_status":["uknjizen","nije_uknjizen","u_postupku"],"legalization_status":["legalizovan","u_postupku","nelegalizovan"],"rental_type":["long_term","mid_term","short_term","room"],"room_types":["exterior","living_room"],"amenities":[{"code":"intercom","labels":{"en":"Intercom","sr":"Interfon"}}],"remove_reasons":["sold","rented","withdrawn","expired","error"],"attributes_by_category":{}}}}},"304":{"description":"Not modified: If-None-Match matched the current ETag."},"default":{"description":"Any refusal of the signed-request checks (x-nk-shared-errors) or 500 internal_error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-nk-success-status":200,"x-nk-errors":[],"x-nk-detail-codes":[],"x-nk-warning-codes":[],"x-nk-error-example":{"error":{"code":"rate_limited","message":"Too many requests."},"request_id":"0f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a"}}},"/places":{"get":{"operationId":"places.search","tags":["Places"],"summary":"Search cities and municipalities.","parameters":[{"$ref":"#/components/parameters/NK-Timestamp"},{"$ref":"#/components/parameters/NK-Nonce"},{"$ref":"#/components/parameters/Content-Digest"},{"$ref":"#/components/parameters/NK-Signature"},{"name":"q","in":"query","required":false,"schema":{"type":"string","maxLength":200}},{"name":"type","in":"query","required":false,"schema":{"type":"string","enum":["city","municipality"]}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","maxLength":512}},{"name":"limit","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{1,3}$"}}],"responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"places":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"type":{"type":"string","enum":["city","municipality"]},"name_sr":{"type":"string"},"name_en":{"type":"string"},"official_code":{"nullable":true,"type":"string"},"city_id":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"city_name_sr":{"nullable":true,"type":"string"},"lat":{"nullable":true,"type":"number"},"lng":{"nullable":true,"type":"number"}},"required":["id","type","name_sr","name_en","official_code","city_id","city_name_sr","lat","lng"],"additionalProperties":false}},"next_cursor":{"nullable":true,"type":"string"}},"required":["places","next_cursor"],"additionalProperties":false},"example":{"places":[{"id":"b2c0d6a4-3f1e-4d2a-9c8b-7e6f5a4b3c2d","type":"municipality","name_sr":"Vračar","name_en":"Vracar","official_code":"70114","city_id":"d4e5f6a7-b8c9-4d0e-9f1a-2b3c4d5e6f7a","city_name_sr":"Beograd","lat":44.8,"lng":20.48}],"next_cursor":null}}}},"422":{"description":"`validation_failed`: The payload is invalid (details array).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"error":{"code":"validation_failed","message":"The query is not valid.","details":[{"pointer":"/type","code":"invalid_enum","message":"Use city or municipality."}]},"request_id":"0f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a"}}}},"default":{"description":"Any refusal of the signed-request checks (x-nk-shared-errors) or 500 internal_error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-nk-success-status":200,"x-nk-errors":[{"code":"validation_failed","status":422,"when":"The payload is invalid (details array).","fix":"Fix the fields at the pointers."}],"x-nk-detail-codes":[{"code":"unknown_field","meaning":"A key the schema doesn't know.","example_pointer":"/structure/balcon"},{"code":"required","meaning":"A required field is missing.","example_pointer":"/title/sr"},{"code":"invalid_type","meaning":"The wrong JSON type.","example_pointer":"/structure/rooms"},{"code":"too_small","meaning":"Below a minimum (length or value).","example_pointer":"/description/sr"},{"code":"too_big","meaning":"Above a maximum (length or value).","example_pointer":"/price/amount"},{"code":"invalid_enum","meaning":"A value outside the vocabulary.","example_pointer":"/structure/heating"},{"code":"invalid_format","meaning":"A malformed id, URL, date or pattern.","example_pointer":"/photos/0/url"}],"x-nk-warning-codes":[],"x-nk-error-example":{"error":{"code":"validation_failed","message":"The query is not valid.","details":[{"pointer":"/type","code":"invalid_enum","message":"Use city or municipality."}]},"request_id":"0f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a"}}},"/places/{id}":{"get":{"operationId":"places.get","tags":["Places"],"summary":"One place.","parameters":[{"$ref":"#/components/parameters/NK-Timestamp"},{"$ref":"#/components/parameters/NK-Nonce"},{"$ref":"#/components/parameters/Content-Digest"},{"$ref":"#/components/parameters/NK-Signature"},{"name":"id","in":"path","required":true,"description":"The place id.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"place":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"type":{"type":"string","enum":["city","municipality"]},"name_sr":{"type":"string"},"name_en":{"type":"string"},"official_code":{"nullable":true,"type":"string"},"city_id":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"city_name_sr":{"nullable":true,"type":"string"},"lat":{"nullable":true,"type":"number"},"lng":{"nullable":true,"type":"number"}},"required":["id","type","name_sr","name_en","official_code","city_id","city_name_sr","lat","lng"],"additionalProperties":false}},"required":["place"],"additionalProperties":false},"example":{"place":{"id":"b2c0d6a4-3f1e-4d2a-9c8b-7e6f5a4b3c2d","type":"municipality","name_sr":"Vračar","name_en":"Vracar","official_code":"70114","city_id":"d4e5f6a7-b8c9-4d0e-9f1a-2b3c4d5e6f7a","city_name_sr":"Beograd","lat":44.8,"lng":20.48}}}}},"404":{"description":"`place_not_found`: Unknown place id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"error":{"code":"place_not_found","message":"No such place."},"request_id":"0f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a"}}}},"default":{"description":"Any refusal of the signed-request checks (x-nk-shared-errors) or 500 internal_error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"x-nk-success-status":200,"x-nk-errors":[{"code":"place_not_found","status":404,"when":"Unknown place id.","fix":"—"}],"x-nk-detail-codes":[],"x-nk-warning-codes":[],"x-nk-error-example":{"error":{"code":"place_not_found","message":"No such place."},"request_id":"0f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a"}}}},"components":{"parameters":{"Content-Digest":{"name":"Content-Digest","in":"header","required":true,"description":"RFC 9530 digest of the raw body: `sha-256=:<base64>:`; the empty body has `sha-256=:47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=:`.","schema":{"type":"string","pattern":"^sha-256=:[A-Za-z0-9+/]{43}=:$"}},"Idempotency-Key":{"name":"Idempotency-Key","in":"header","required":false,"description":"8–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.","schema":{"type":"string","minLength":8,"maxLength":128,"pattern":"^[\\x21-\\x7e]{8,128}$"}},"NK-Nonce":{"name":"NK-Nonce","in":"header","required":true,"description":"16–64 random bytes, base64url without padding, unique per request per key (kept 15 minutes).","schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{22,86}$"}},"NK-Signature":{"name":"NK-Signature","in":"header","required":true,"description":"`v1=` + base64url without padding of the 64-byte Ed25519 signature over the NK-SIG-1 base.","schema":{"type":"string","pattern":"^v1=[A-Za-z0-9_-]{86}$"}},"NK-Timestamp":{"name":"NK-Timestamp","in":"header","required":true,"description":"Unix seconds; within ±300 s of our clock.","schema":{"type":"string","pattern":"^\\d{1,12}$"}}},"schemas":{"Listing":{"oneOf":[{"type":"object","properties":{"external_id":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9._:-]*$"},"category":{"type":"string","enum":["apartment","studio","penthouse","duplex","loft","house","house_semi_detached","townhouse","villa","land","land_building","land_agricultural","land_forest","garage","parking","storage","office","retail","warehouse","hospitality","commercial"]},"state":{"type":"string","enum":["active","inactive"]},"title":{"type":"object","properties":{"sr":{"type":"string","minLength":5,"maxLength":120},"en":{"nullable":true,"type":"string","minLength":0,"maxLength":120},"tr":{"nullable":true,"type":"string","minLength":0,"maxLength":120},"de":{"nullable":true,"type":"string","minLength":0,"maxLength":120},"ru":{"nullable":true,"type":"string","minLength":0,"maxLength":120}},"required":["sr"],"additionalProperties":false},"description":{"type":"object","properties":{"sr":{"type":"string","minLength":20,"maxLength":8000},"en":{"nullable":true,"type":"string","minLength":0,"maxLength":8000},"tr":{"nullable":true,"type":"string","minLength":0,"maxLength":8000},"de":{"nullable":true,"type":"string","minLength":0,"maxLength":8000},"ru":{"nullable":true,"type":"string","minLength":0,"maxLength":8000}},"required":["sr"],"additionalProperties":false},"location":{"type":"object","properties":{"place_id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"address_line":{"type":"string","minLength":3,"maxLength":200},"neighbourhood":{"nullable":true,"type":"string","minLength":0,"maxLength":120},"lat":{"nullable":true,"type":"number","minimum":-90,"maximum":90},"lng":{"nullable":true,"type":"number","minimum":-180,"maximum":180}},"required":["place_id","address_line"],"additionalProperties":false},"amenities":{"nullable":true,"maxItems":40,"type":"array","items":{"type":"string","enum":["loggia","french_balcony","walk_in_closet","built_in_wardrobes","underfloor_heating","fireplace","laundry_room","soundproofing","smart_home","fibre_internet","pvc_joinery","reception_desk","meeting_rooms","kitchenette","showers","own_toilets","storage_room","open_plan","cellular_offices","intercom","video_intercom","reception","gym","swimming_pool","spa_sauna","playground","park","courtyard","freight_elevator","access_24_7","bike_storage","ev_charger","roof_terrace","wheelchair_access","signage_rights","canteen_nearby","video_surveillance","security_service","alarm","security_door","access_control","raised_floor","suspended_ceiling","three_phase_power","backup_generator","server_room","sprinklers"]}},"attributes":{"nullable":true,"type":"object","additionalProperties":{}},"photos":{"nullable":true,"maxItems":64,"type":"array","items":{"type":"object","properties":{"url":{"type":"string","maxLength":2048},"caption":{"nullable":true,"type":"string","minLength":0,"maxLength":500},"room_type":{"nullable":true,"type":"string","enum":["exterior","living_room","kitchen","bedroom","bathroom","balcony","hallway","view","garage","other"]},"digest":{"nullable":true,"type":"string","pattern":"^[0-9a-f]{64}$"}},"required":["url"],"additionalProperties":false}},"video_url":{"nullable":true,"type":"string","maxLength":2048},"virtual_tour_url":{"nullable":true,"type":"string","maxLength":2048},"agent":{"nullable":true,"type":"object","properties":{"email":{"type":"string","maxLength":254,"format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"name":{"nullable":true,"type":"string","minLength":0,"maxLength":120},"phone":{"nullable":true,"type":"string","minLength":0,"maxLength":32}},"required":["email"],"additionalProperties":false},"source":{"type":"object","properties":{"updated_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"url":{"nullable":true,"type":"string","maxLength":2048}},"required":["updated_at"],"additionalProperties":false},"digest":{"nullable":true,"type":"string","maxLength":128},"transaction":{"type":"string","enum":["sale"]},"price":{"type":"object","properties":{"amount":{"type":"number","minimum":0,"exclusiveMinimum":true,"maximum":9999999999},"currency":{"type":"string","enum":["EUR","RSD"]},"negotiable":{"nullable":true,"type":"boolean"}},"required":["amount","currency"],"additionalProperties":false},"structure":{"type":"object","properties":{"area_sqm":{"nullable":true,"type":"number","minimum":0,"exclusiveMinimum":true,"maximum":99999.99},"bedrooms":{"nullable":true,"type":"number","minimum":0,"maximum":99},"bathrooms":{"nullable":true,"type":"number","minimum":0,"maximum":99},"floor":{"nullable":true,"type":"integer","minimum":-5,"maximum":60},"levels":{"nullable":true,"type":"integer","minimum":1,"maximum":6},"furnished":{"nullable":true,"type":"string","enum":["furnished","semi_furnished","unfurnished"]},"elevator":{"nullable":true,"type":"boolean"},"parking":{"nullable":true,"type":"boolean"},"balcony":{"nullable":true,"type":"boolean"},"terrace":{"nullable":true,"type":"boolean"},"air_conditioning":{"nullable":true,"type":"boolean"},"heating":{"nullable":true,"type":"string","enum":["district","gas_central","gas_local","electric_local","storage_heater","electric_panel","heat_pump","air_conditioning","underfloor","pellet","solid_fuel","tiled_stove","oil","solar","none","other"]},"rooms":{"nullable":true,"type":"number","minimum":0,"maximum":99},"total_floors":{"nullable":true,"type":"integer","minimum":0,"maximum":60},"year_built":{"nullable":true,"type":"integer","minimum":1800,"maximum":2035},"building_group":{"nullable":true,"type":"string","enum":["new","old"]},"condition":{"nullable":true,"type":"string","enum":["lux","renovated","original","renovation_required"]},"garage":{"nullable":true,"type":"boolean"},"basement":{"nullable":true,"type":"boolean"}},"additionalProperties":false},"legal":{"type":"object","properties":{"ownership_status":{"nullable":true,"type":"string","enum":["uknjizen","nije_uknjizen","u_postupku"]},"legalization_status":{"nullable":true,"type":"string","enum":["legalizovan","u_postupku","nelegalizovan"]},"mortgage_eligible":{"nullable":true,"type":"boolean"},"mandate_attested":{"type":"boolean"},"exclusive":{"nullable":true,"type":"boolean"},"broker_license_no":{"nullable":true,"type":"string","minLength":0,"maxLength":64},"tapija_note":{"nullable":true,"type":"string","minLength":0,"maxLength":500}},"required":["mandate_attested"],"additionalProperties":false},"commission":{"nullable":true,"type":"object","properties":{"buyer_pct":{"nullable":true,"type":"number","minimum":0,"maximum":100},"seller_pct":{"nullable":true,"type":"number","minimum":0,"maximum":100}},"additionalProperties":false}},"required":["external_id","category","state","title","description","location","source","transaction","price","structure","legal"],"additionalProperties":false},{"type":"object","properties":{"external_id":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9._:-]*$"},"category":{"type":"string","enum":["apartment","studio","penthouse","duplex","loft","house","house_semi_detached","townhouse","villa","land","land_building","land_agricultural","land_forest","garage","parking","storage","office","retail","warehouse","hospitality","commercial"]},"state":{"type":"string","enum":["active","inactive"]},"title":{"type":"object","properties":{"sr":{"type":"string","minLength":5,"maxLength":120},"en":{"nullable":true,"type":"string","minLength":0,"maxLength":120},"tr":{"nullable":true,"type":"string","minLength":0,"maxLength":120},"de":{"nullable":true,"type":"string","minLength":0,"maxLength":120},"ru":{"nullable":true,"type":"string","minLength":0,"maxLength":120}},"required":["sr"],"additionalProperties":false},"description":{"type":"object","properties":{"sr":{"type":"string","minLength":20,"maxLength":8000},"en":{"nullable":true,"type":"string","minLength":0,"maxLength":8000},"tr":{"nullable":true,"type":"string","minLength":0,"maxLength":8000},"de":{"nullable":true,"type":"string","minLength":0,"maxLength":8000},"ru":{"nullable":true,"type":"string","minLength":0,"maxLength":8000}},"required":["sr"],"additionalProperties":false},"location":{"type":"object","properties":{"place_id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"address_line":{"type":"string","minLength":3,"maxLength":200},"neighbourhood":{"nullable":true,"type":"string","minLength":0,"maxLength":120},"lat":{"nullable":true,"type":"number","minimum":-90,"maximum":90},"lng":{"nullable":true,"type":"number","minimum":-180,"maximum":180}},"required":["place_id","address_line"],"additionalProperties":false},"amenities":{"nullable":true,"maxItems":40,"type":"array","items":{"type":"string","enum":["loggia","french_balcony","walk_in_closet","built_in_wardrobes","underfloor_heating","fireplace","laundry_room","soundproofing","smart_home","fibre_internet","pvc_joinery","reception_desk","meeting_rooms","kitchenette","showers","own_toilets","storage_room","open_plan","cellular_offices","intercom","video_intercom","reception","gym","swimming_pool","spa_sauna","playground","park","courtyard","freight_elevator","access_24_7","bike_storage","ev_charger","roof_terrace","wheelchair_access","signage_rights","canteen_nearby","video_surveillance","security_service","alarm","security_door","access_control","raised_floor","suspended_ceiling","three_phase_power","backup_generator","server_room","sprinklers"]}},"attributes":{"nullable":true,"type":"object","additionalProperties":{}},"photos":{"nullable":true,"maxItems":64,"type":"array","items":{"type":"object","properties":{"url":{"type":"string","maxLength":2048},"caption":{"nullable":true,"type":"string","minLength":0,"maxLength":500},"room_type":{"nullable":true,"type":"string","enum":["exterior","living_room","kitchen","bedroom","bathroom","balcony","hallway","view","garage","other"]},"digest":{"nullable":true,"type":"string","pattern":"^[0-9a-f]{64}$"}},"required":["url"],"additionalProperties":false}},"video_url":{"nullable":true,"type":"string","maxLength":2048},"virtual_tour_url":{"nullable":true,"type":"string","maxLength":2048},"agent":{"nullable":true,"type":"object","properties":{"email":{"type":"string","maxLength":254,"format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"name":{"nullable":true,"type":"string","minLength":0,"maxLength":120},"phone":{"nullable":true,"type":"string","minLength":0,"maxLength":32}},"required":["email"],"additionalProperties":false},"source":{"type":"object","properties":{"updated_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"url":{"nullable":true,"type":"string","maxLength":2048}},"required":["updated_at"],"additionalProperties":false},"digest":{"nullable":true,"type":"string","maxLength":128},"transaction":{"type":"string","enum":["rent"]},"rent":{"type":"object","properties":{"amount":{"type":"number","minimum":1,"maximum":10000000},"currency":{"type":"string","enum":["EUR","RSD"]},"type":{"type":"string","enum":["long_term","mid_term","short_term","room"]},"deposit_months":{"nullable":true,"type":"number","minimum":0,"maximum":12},"min_lease_months":{"nullable":true,"type":"integer","minimum":0,"maximum":120},"max_lease_months":{"nullable":true,"type":"integer","minimum":0,"maximum":120},"available_from":{"nullable":true,"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},"utilities_included":{"nullable":true,"type":"object","additionalProperties":{"type":"boolean"}},"utilities_estimate_rsd":{"nullable":true,"type":"integer","minimum":0,"maximum":100000000},"owner_lives_nearby":{"nullable":true,"type":"boolean"},"owner_proximity":{"nullable":true,"type":"string","enum":["same_apartment","same_floor","upstairs","downstairs","same_building","same_street","walking_distance"]},"max_occupants":{"nullable":true,"type":"integer","minimum":1,"maximum":20}},"required":["amount","currency","type"],"additionalProperties":false},"house_rules":{"type":"object","properties":{"pets":{"type":"object","properties":{"policy":{"type":"string","enum":["allowed","on_request","not_allowed"]},"kinds":{"maxItems":5,"type":"array","items":{"type":"string","enum":["dogs","cats","small_caged","birds","aquarium"]}},"dog_size":{"type":"string","enum":["small","medium","any"]},"max_count":{"type":"integer","minimum":1,"maximum":5},"deposit_eur":{"type":"integer","minimum":0,"maximum":100000},"note":{"type":"string","maxLength":200}},"required":["policy"],"additionalProperties":false},"smoking":{"type":"string","enum":["not_allowed","balcony_only","allowed"]},"guests":{"type":"string","enum":["allowed","ask_first","not_allowed"]},"parties":{"type":"string","enum":["not_allowed","allowed"]},"quiet_hours":{"type":"string","maxLength":200},"subletting":{"type":"string","enum":["not_allowed","with_consent"]},"students":{"type":"string","enum":["yes","no"]},"families":{"type":"string","enum":["yes","no"]},"foreign_tenants":{"type":"string","enum":["welcome","ask_first"]},"registers_residence":{"type":"boolean"},"other":{"type":"string","maxLength":500}},"additionalProperties":false},"structure":{"type":"object","properties":{"area_sqm":{"nullable":true,"type":"number","minimum":0,"exclusiveMinimum":true,"maximum":99999.99},"bedrooms":{"nullable":true,"type":"number","minimum":0,"maximum":99},"bathrooms":{"nullable":true,"type":"number","minimum":0,"maximum":99},"floor":{"nullable":true,"type":"integer","minimum":-5,"maximum":60},"levels":{"nullable":true,"type":"integer","minimum":1,"maximum":6},"furnished":{"nullable":true,"type":"string","enum":["furnished","semi_furnished","unfurnished"]},"elevator":{"nullable":true,"type":"boolean"},"parking":{"nullable":true,"type":"boolean"},"balcony":{"nullable":true,"type":"boolean"},"terrace":{"nullable":true,"type":"boolean"},"air_conditioning":{"nullable":true,"type":"boolean"},"heating":{"nullable":true,"type":"string","enum":["district","gas_central","gas_local","electric_local","storage_heater","electric_panel","heat_pump","air_conditioning","underfloor","pellet","solid_fuel","tiled_stove","oil","solar","none","other","electric"]}},"additionalProperties":false},"legal":{"type":"object","properties":{"mandate_attested":{"type":"boolean"}},"required":["mandate_attested"],"additionalProperties":false},"commission":{"nullable":true,"type":"object","properties":{"landlord_pct":{"nullable":true,"type":"number","minimum":0,"maximum":100},"agency_fee_pct":{"nullable":true,"type":"number","minimum":0,"maximum":100}},"additionalProperties":false}},"required":["external_id","category","state","title","description","location","source","transaction","rent","house_rules","structure","legal"],"additionalProperties":false}],"description":"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."},"ErrorEnvelope":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["ingest_disabled","body_too_large","signature_missing","key_invalid","key_expired","app_suspended","account_blocked","ip_allowlist_empty","ip_not_allowed","digest_mismatch","timestamp_out_of_window","signature_invalid","nonce_reused","rate_limited","connection_not_found","connection_not_active","connection_item_limit","connect_code_invalid","agency_not_eligible","connection_exists","listing_not_found","batch_not_found","place_not_found","validation_failed","batch_too_large","duplicate_external_id","idempotency_key_reused","idempotency_in_progress","mass_removal_requires_confirmation","body_invalid","internal_error"]},"message":{"type":"string"},"details":{}},"required":["code","message"],"additionalProperties":false},"request_id":{"type":"string"}},"required":["error","request_id"],"additionalProperties":false}},"securitySchemes":{"NK-SIG-1":{"type":"apiKey","in":"header","name":"NK-Key-Id","description":"Every request is signed with NK-SIG-1 (Ed25519). Five headers: `NK-Key-Id` (the key id), `NK-Timestamp` (Unix seconds), `NK-Nonce` (16–64 random bytes, base64url without padding, unique per request), `Content-Digest` (`sha-256=:<base64 SHA-256 of the raw body>:`, also for an empty body) and `NK-Signature` (`v1=<base64url without padding of the 64-byte Ed25519 signature>`). The signature base is seven lines joined with `\\n`, no trailing newline: `NK-SIG-1`, the upper-case method, the lower-case host without port, the path as sent followed by the canonical query (pairs form-decoded, sorted by key then value, RFC 3986-encoded, `&`-joined; no `?` when empty), the timestamp, the nonce and the Content-Digest value. See https://developers.novikvadrat.rs/docs/authentication/signing."}}},"x-nk-shared-errors":[{"code":"ingest_disabled","status":503,"when":"Novi Kvadrat switched ingestion off.","fix":"Retry later with backoff."},{"code":"body_too_large","status":413,"when":"The body is over 4 MiB (checked first).","fix":"Split the batch."},{"code":"signature_missing","status":401,"when":"A signing header is absent or malformed.","fix":"Send all five headers."},{"code":"key_invalid","status":401,"when":"Unknown or revoked key.","fix":"Register a new key."},{"code":"key_expired","status":401,"when":"The key is past its 365 days.","fix":"Register a new key."},{"code":"app_suspended","status":403,"when":"Staff suspended the app.","fix":"Write to partners@novikvadrat.rs."},{"code":"account_blocked","status":403,"when":"Staff suspended or archived the organization.","fix":"Write to partners@novikvadrat.rs."},{"code":"ip_allowlist_empty","status":403,"when":"A live app without addresses.","fix":"Edit the allowlist."},{"code":"ip_not_allowed","status":403,"when":"The caller is not listed, or its address can't be determined.","fix":"Edit the allowlist."},{"code":"digest_mismatch","status":400,"when":"The body changed after hashing.","fix":"Hash the exact bytes you send."},{"code":"timestamp_out_of_window","status":401,"when":"The clock is off by more than 300 s.","fix":"Sync the clock (NTP)."},{"code":"signature_invalid","status":401,"when":"The base string or the key does not match.","fix":"Compare with the test vector."},{"code":"nonce_reused","status":401,"when":"A nonce sent twice within 15 minutes.","fix":"A fresh random nonce per request."},{"code":"rate_limited","status":429,"when":"Over the per-minute budget (replays count too).","fix":"Wait Retry-After."}]}