BETA

POST /properties/verify

You send a property object and we answer three things:

  1. Whether the object is valid according to Mapaprop's contract, and what it is missing if it is not.
  2. What we understood of what you sent — how many fields we rebuilt from your attributes array.
  3. Whether each portal could publish it, and when it could not, exactly what is missing and whose problem it is.

This endpoint does not create, modify or publish anything. It leaves no trace. It is there for you to adjust your object before integrating, as many times as you want.

It is in beta. The shape of the response may change while this stage lasts. Changes are announced on this page beforehand.

What it is for

Integrating with several portals has a problem that shows up late: you send an object that looks complete to you, it gets published, and only then do you see that the listing came out without a price, without a pool or with the wrong type — because each portal asks for different things and stays quiet about what it does not understand.

This endpoint lets you see that before publishing, without creating anything and without needing the portal accounts connected.

Resource information
AuthenticationRequired (JWT) — scope property-api-verify
HTTP MethodPOST
ResponseJSON
Version1

Resource URL

https://property-api.mapaprop.com/property-v1/properties/verify

Authentication

An OAuth2 token and the property-api-verify scope are required.

POST /property-v1/properties/verify
Host: property-api.mapaprop.com
Content-Type: application/json
Authorization: Bearer {access_token}

The token is obtained like any other: POST /api/action/oauth2-v1/authorize.

Scopes travel signed inside the token. If we add a scope after you generated yours, it has to be generated again to take effect — and generating a new one invalidates the previous one. Ask up front for every scope you are going to need.

The request body

Verify works WITHOUT having declared your client. It is a tester: it validates the token and describes the object, it does not upload anything. If you have not declared it yet, it fills the client details with a placeholder, and tells you so in customerSource — so you can try your object on day one, with no prior step and without mistaking filler for your own data.

⚠️ Where it IS required is the upload: POST /property-v1/properties responds 400 with rule: account_required if the account has no client declared. You declare it ONCE with POST /property-v1/customers. The properties you upload afterwards inherit it; the ones already uploaded keep the contact they were created with.

⚠️ One detail about the placeholder: country is not filled in. A filler value there would be indistinguishable from a real answer, and it is the one field you should not guess.

{
  "canonical": { …el objeto de la propiedad… },
  "portals": ["argenprop", "zonaprop", "cabaprop"]
}
KeyRequiredWhat it is
canonicalyesThe property object. property is accepted as an alternative name
portalsnoWhich portals to evaluate. If you omit it, all of them are evaluated

The object that goes in canonical is the usual one: The property JSON object.

If you send a portal that does not exist, the request fails with a 400 instead of ignoring it silently.

Which portals it reports back

If in publication.api you declare…The response brings…
One or several portalsonly those
Nothing (you do not send publication)all of them

The idea is that you do not receive problems about a portal you did not configure. If you already declared Argenprop and nothing else, Zonaprop does not show up in the response nor count in the summary.

And if you have not configured any yet, you see all of them: that is the case of someone evaluating the integration who wants to see how their object converts on each portal before deciding.

If you want to narrow the response without declaring configuration, use portals in the request body. They are two different things: portals says what you want to look at, publication says what you have configured.

publication — the publishing configuration, inside the object

Inside canonical you can send a publication key with what each portal needs from your account and from your publishing choices. It is not a field of the property: it is how you publish it.

{
  "publication": {
    "api": {
      "argenprop": { "advertiserId": 99999, "visible": true },
      "zonaprop": {
        "plan": { "plan": "SUPERDESTACADO" },
        "branch": { "custId": 1, "email": "contacto@ejemplo.com", "name": "Inmobiliaria", "phone1": "1144445555" }
      },
      "cabaprop": { "branchOfficeId": 42 }
    }
  }
}

Zonaprop's branch and MercadoLibre's sellerContact are autofilled from the client you declared: you do not need to send them. They are in the example because if you do send them, they win — autofilling has the lowest precedence of all.

PortalFields
argenpropadvertiserId (number) · visible (boolean)
zonapropplan (object) · branch (object)
cabapropbranchOfficeId (number)
mercadolibrelistingTypeId (string) · condition (string) · sellerContact (object)

Each portal also accepts a token (string), which is validated for shape and never for validity: this endpoint does not verify accounts. Its value does not appear anywhere in the response.

publication does not travel to the portals as one more field: it is consumed here and discarded.

The full reference —the two levels, what happens if you send something that does not belong, and the detail about the token— is on its own page: The publication key.

The response

The response carries the clientRef, the same one you sent in the envelope. We return it on all six paths (verify, create, read, list, update and delete) so you can match it against your own database without having to remember which clientRef you asked with.

{
  "mode": "client",
  "object": {
    "valid": true,
    "contract": [],
    "mapapropZone": "1-2-189-973",
    "conflicts": [],
    "conflicts": []
  },
  "portals": {
    "argenprop": {
      "status": "fields_complete",
      "connection": "not_verified",
      "zone": {
        "sent": {
          "code": "1-2-189-973",
          "level": 3
        },
        "publishingTo": "Mar del Plata",
        "status": "mapped"
      },
      "blockers": [],
      "pendingAtPublishTime": []
    },
    "zonaprop": {
      "status": "fields_complete",
      "connection": "not_verified",
      "zone": {
        "sent": {
          "code": "1-2-189-973",
          "level": 3
        },
        "publishingTo": "General Pueyrredón",
        "status": "mapped"
      },
      "blockers": [],
      "pendingAtPublishTime": []
    },
    "cabaprop": {
      "status": "fields_complete",
      "connection": "not_verified",
      "zone": {
        "sent": {
          "code": "1-2-189-973",
          "level": 3
        },
        "status": "not_mapped",
        "message": "Todavía no tenemos mapeada esta zona para cabaprop. Escribinos con el código de zona y la publicamos: el mapeo queda hecho para siempre."
      },
      "blockers": [],
      "pendingAtPublishTime": []
    },
    "mercadolibre": {
      "status": "coming_soon",
      "message": "MercadoLibre: disponible pronto. La integración todavía no está habilitada en este endpoint."
    }
  },
  "summary": {
    "complete": 3,
    "of": 4
  }
}

object — what happened to your object

FieldWhat it says
validWhether the object complies with Mapaprop's contract
contractWhat does not comply: field, rule and the detail. Empty if valid is true
mapapropZoneThe zone we resolved, as zone0-zone1-zone2-zone3
conflictsFields where your attributes contradicts the individual field. attributes wins

conflicts deserves attention: if you send "type": 23 and your attributes says "Departamento", it is published as Departamento. It is not an error, it is the rule — but if that was not what you wanted, you see it here instead of in the listing.

portals — what each portal says

FieldWhat it says
statusThe verdict. Values below
connectionconnected · not_connected · not_verified
zoneWhich zone you sent and which one we are going to publish in. Below
blockersWhat is missing in the object in order to publish
pendingAtPublishTimeWhat is missing in order to publish, but is not part of the object (plan, branch, mapped zone)

status values:

ValueMeans
fields_completeThe object has everything that portal needs
missing_dataA piece of data is missing. Look at blockers — there is something you can fix
not_supportedThe portal does not support something about this property. You cannot fix it by sending more data
coming_soonThe integration is not enabled on this endpoint yet

Some portals cannot build the listing until they have their configuration: Zonaprop needs the plan and the branch details to build the listing. In those cases the portal shows up with its status and its pendingAtPublishTime, but without the mapping — not because your object is wrong, but because the account data it is built with is still missing.

Blockers coming from publication also carry a concrete example of how to fix them, attached to the message: se espera number · ejemplo: "publication": { "api": { "argenprop": { "advertiserId": 99999 } } }. See The publication key.

Each blocker carries:

{ "field": "price",
  "kind": "missing",
  "message": "`price` es obligatorio en el objeto de Mapaprop y no vino…",
  "youCanFixIt": true }

youCanFixIt answers the only question that matters about a blocker: do I fix this by sending more data, or is it a limitation of the portal? If it is true, send the data. If it is false, that portal does not admit what you are asking of it and no JSON will solve it.

blockers and pendingAtPublishTime are different things on purpose. A perfect object that is only missing the choice of plan is not an incomplete object: it is a listing that has not been configured. That is why pendingAtPublishTime does not affect the status.

zone — which zone we are going to publish in

Every portal has its own zone map, and we maintain the translation between your Mapaprop zone and that portal's. zone shows you both ends:

{ "sent": { "code": "1-2-189-973", "level": 3 },
  "publishingTo": "Mar del Plata",
  "status": "mapped" }
FieldWhat it says
sent.codeThe zone you sent, exactly as we build it from your zone0…zone3
sent.levelHow deep that code goes: 2 is the whole district, 3 goes down to the locality
sent.nameThe name of your zone, if you sent the description for that level
publishingToThe name of the portal zone where your listing is going to appear
statusmapped · not_mapped · not_sent · not_verified

The states:

ValueMeans
mappedWe resolved the zone. publishingTo tells you where it is going to appear
not_mappedYour zone is valid, but we do not have it mapped to that portal yet. It comes with a message explaining what to do
not_sentYou did not send the zone in the object
not_verifiedWe did not get to look up the mapping, so we are not claiming anything

Check publishingTo even when the status is mapped. It is the public name of the portal zone: if you sent one zone and a different one shows up there, the listing is going to appear in that other place. Write to us and we will fix it — you are the only one who can notice, because you are the one who knows the property.

A 0 at the end of the code does not mean a level is missing: 1-2-201-0 is the whole district, and it is a valid publishing destination on its own. That is why level counts up to the last non-zero number.

summary

{ "summary": { "complete": 3, "of": 4 } }

How many portals have their required fields complete, out of the total evaluated.

Mapaprop's required fields override the portal's

This is the most important thing to understand about the endpoint.

Mapaprop has its own contract of required fields, and it does not depend on what each portal asks for. If one of those fields is missing, no portal stays in fields_complete — even if that particular portal does not require it.

Example: Argenprop does not require the price to build its listing. Even so, if you do not send price:

{
  "object": {
    "valid": false,
    "contract": [ { "field": "price", "rule": "required", "detail": "" } ]
  },
  "portals": {
    "argenprop": {
      "status": "missing_data",
      "blockers": [
        { "field": "price",
          "kind": "missing",
          "message": "`price` es obligatorio en el objeto de Mapaprop y no vino. Sin él no se publica en ningún portal, lo exija o no este portal en particular.",
          "youCanFixIt": true }
      ]
    }
  },
  "summary": { "complete": 0, "of": 4 }
}

The full list of required fields is in The property JSON object.

Only the absence of a required field blocks. A field that is present but with an incorrect format shows up in object.contract and informs without blocking — so that you can keep correcting without the endpoint becoming unusable. Always check object.contract, not just the summary.

You do not need the portal connected

The connection field tells you whether that portal's account is connected, but it does not condition anything: the object is mapped the same way and the blockers are computed the same way.

ValueMeans
connectedThe account is connected
not_connectedThere is no connected account for that portal
not_verifiedThe connection status could not be verified

It is a piece of data on the side, and it still matters: a flawless object is not published if the account is not connected. But to perfect your object you do not need any.

Errors

CodeWhen
400The body is missing, it is not valid JSON, canonical/property is missing, or you asked for a portal that does not exist. ⚠️ Verify does NOT return 400 for having no client declared — that belongs to the upload; here it is simulated with a placeholder
403The token is missing the property-api-verify scope
{ "error": "Portales desconocidos: idealista. Válidos: argenprop, zonaprop, cabaprop, mercadolibre, mapaprop" }

MercadoLibre

It always comes out as coming_soon. The integration exists but is not enabled on this endpoint yet, and we prefer not to show you an unverified mapping: you would take it for good.

How to use it

  1. Send your object exactly as you have it today.
  2. Look at object.valid and object.contract first. If a required field is missing, fix that — it is blocking every portal at once.
  3. Look at object.conflicts. If something shows up, your attributes and your individual fields are contradicting each other, and attributes wins.
  4. Portal by portal, resolve the blockers with youCanFixIt: true.
  5. The youCanFixIt: false ones you cannot resolve: they are limits of the portal.
  6. Repeat. Nothing is created, so try as many times as you need.

Do you need help? Contact Mapaprop technical support