Skip to content
deveras.

REST API

Read-only, JSON, open to calls from the browser. Field names are stable: an incompatible change would ship as a new version.

Base URL

URL
https://www.deveras.app/api/v1

Access and keys

You do not need a key to start. With a key the limit is higher and you can follow your usage. Send it in the Authorization: Bearer … header or in x-api-key.

curl
curl -H "Authorization: Bearer $API_KEY" \
  "https://www.deveras.app/api/v1/listings?city=playa-del-carmen"

Your key is secret: use it from your server, never in code that reaches the browser. If it leaks, revoke it and create another.

Limits and caching

  • Without a key: 60 requests per minute per IP address.
  • With a key: 600 requests per minute per key.
  • Above the limit we answer 429 with a Retry-After header (seconds to wait). With a key, every response includes X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset.
  • Responses can be cached for 60 seconds (Cache-Control). Listings do not change often: keep the responses and save requests.

Response shape

Every successful response has data (the result) and attribution (the mention you must display). Lists add pagination, with links to the previous and next page, also sent in the Link header.

JSON
{
  "data": [
    {
      "id": "k7m2x9p",
      "url": "https://www.deveras.app/en/p/bright-two-bedroom-near-the-beach-k7m2x9p",
      "title": "Bright two-bedroom near the beach",
      "language": "en",
      "type": "apartment",
      "operation": "rent",
      "terms": [
        "long",
        "mid"
      ],
      "price": {
        "amount": 1200,
        "currency": "USD",
        "amount_mxn": 21960,
        "period": "month"
      },
      "sale": null,
      "bedrooms": 2,
      "bathrooms": 1.5,
      "area_m2": 78,
      "land_m2": null,
      "furnished": true,
      "pets_allowed": false,
      "amenities": [
        "pool",
        "ac",
        "wifi"
      ],
      "location": {
        "city": {
          "slug": "playa-del-carmen",
          "name": "Playa del Carmen"
        },
        "zone": {
          "slug": "centro",
          "name": "Centro"
        },
        "coordinates": {
          "lat": 20.627,
          "lng": -87.074,
          "precision": "approximate"
        }
      },
      "photos": [
        {
          "url": "https://www.deveras.app/media/public/listings/k7m2x9p/1.jpg",
          "width": 1600,
          "height": 1200,
          "alt": "Living room",
          "room": "living"
        }
      ],
      "advertiser": {
        "handle": "ana-lopez",
        "name": "Ana López",
        "role": "owner",
        "agency_name": null,
        "avatar_url": null,
        "trust_score": 82,
        "reviews": {
          "count": 4,
          "average": 4.75
        },
        "verifications": [
          {
            "kind": "email",
            "verified_at": "2026-01-05T10:00:00.000Z"
          },
          {
            "kind": "identity",
            "verified_at": "2026-03-02T10:00:00.000Z"
          }
        ],
        "url": "https://www.deveras.app/en/u/ana-lopez"
      },
      "verifications": [
        {
          "kind": "ownership",
          "verified_at": "2026-04-01T10:00:00.000Z"
        }
      ],
      "shares_commission": false,
      "demo": false,
      "published_at": "2026-06-10T15:00:00.000Z",
      "availability_confirmed_at": "2026-10-01T12:00:00.000Z"
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 24,
    "total": 1,
    "pages": 1,
    "links": {
      "self": "https://www.deveras.app/api/v1/listings?city=playa-del-carmen&beds=2&max=25000",
      "first": "https://www.deveras.app/api/v1/listings?city=playa-del-carmen&beds=2&max=25000",
      "last": "https://www.deveras.app/api/v1/listings?city=playa-del-carmen&beds=2&max=25000",
      "prev": null,
      "next": null
    }
  },
  "attribution": {
    "text": "Listings from Deveras",
    "url": "https://www.deveras.app/en",
    "license_url": "https://www.deveras.app/en/developers/license",
    "notice": "Free to reuse, including commercially, as long as you show this mention visibly and link each listing to its `url`. Do not remove verification context or the demo flag, and do not publish contact details."
  }
}

Good to know about the fields

url
The listing’s page on Deveras. It is the required link in any reuse.
price
amount is in the listing’s currency (currency); amount_mxn is the same price in pesos. The min and max filters and price sorting use pesos.
sale
Sales only (operation: sale, price.period: total): pre-sale, delivery, title type, HOA fee and price per m². null for rentals.
location.coordinates
precision is exact or approximate. When approximate, the point is offset on purpose: draw an area, not a pin. It can be null.
verifications
The proofs checked by the platform, with their kind and date. On the listing they are about the property; under advertiser, about the person. An empty list means “not verified”.
demo
true on demonstration data, which is not a real listing. Left out unless you ask for demo=1.
locale
locale=es, en or fr picks the language of titles, descriptions and links. Without a translation you get the original text (language tells you which).

What we never return

Exact address, phone, WhatsApp, email, identity documents, internal identifiers and unpublished listings. Nor tenant profiles. If a free-text field contains a phone number or an email address, we hide it.

Endpoints

Search listings

GET/api/v1/listings

Published listings, most recent first, with the same filters as the site search. Rentals by default; sales with operation=sale.

operationstring — optional — rent · sale — default: rent
rent (the default) or sale. A search returns one or the other, never both.
citystring — optional
City (slug from /places). Without it, every city is searched.
zonestring — optional
Zone inside the city. Requires city.
typestring — optional — apartment · house · studio · room · villa · commercial · land
Property type.
bedsinteger — optional
Minimum number of bedrooms.
bathsinteger — optional
Minimum number of bathrooms.
mininteger — optional
Minimum price in pesos (MXN): the rent, or the total price of a sale.
maxinteger — optional
Maximum price in pesos (MXN): the rent, or the total price of a sale.
furnishedboolean — optional
1 for furnished listings only.
petsboolean — optional
1 for listings that accept pets only. Rentals only.
termstring — optional — long · mid · short
Term: long (12 months or more), mid (1 to 11 months) or short (nightly or weekly). Rentals only.
amenitiesstring[] — optional — pool · gym · ac · parking · rooftop · security · washer · elevator · cowork · balcony · garden · kitchen · wifi · tv · beach_walk · generator · cistern · storage · bbq · jacuzzi
Amenities the listing must all have, separated by commas.
verifiedboolean — optional
1 for advertisers with a verified identity only.
qstring — optional
Free text, searched in the title and the description.
advertiserstring — optional
Only this profile’s listings.
sortstring — optional — recent · price_asc · price_desc — default: recent
Order: recent, price_asc or price_desc.
pageinteger — optional — default: 1
Page number, starting at 1.
per_pageinteger — optional — default: 24
Listings per page.
demoboolean — optional — default: 0
1 to include demonstration data (flagged with demo: true).
localestring — optional — es · en · fr — default: es
Language of texts and links: es, en or fr.
curl
curl "https://www.deveras.app/api/v1/listings?city=playa-del-carmen&beds=2&max=25000&furnished=1"
JavaScript
const response = await fetch("https://www.deveras.app/api/v1/listings?city=playa-del-carmen&beds=2&max=25000");
const { data, pagination, attribution } = await response.json();

for (const listing of data) {
  // listing.url is the page of the listing: always link to it.
  console.log(listing.title, listing.price.amount, listing.price.currency, listing.url);
}

// Show attribution.text, linked to attribution.url, wherever you display the listings.
console.log(attribution.text, attribution.url, pagination.total);

Get a listing

GET/api/v1/listings/{shortId}

The full listing: description, every photo, conditions, what is included, distances and verifications.

shortIdstring
Listing id (the id field).
demoboolean — optional — default: 0
1 to include demonstration data (flagged with demo: true).
localestring — optional — es · en · fr — default: es
Language of texts and links: es, en or fr.
curl
curl "https://www.deveras.app/api/v1/listings/k7m2x9p?locale=en"

Cities and zones

GET/api/v1/places

Cities and their zones, with the slugs used by the city and zone filters and the number of listings for rent (listing_count) and for sale (sale_count).

demoboolean — optional — default: 0
1 to include demonstration data (flagged with demo: true).
localestring — optional — es · en · fr — default: es
Language of texts and links: es, en or fr.
curl
curl "https://www.deveras.app/api/v1/places"

An advertiser’s public profile

GET/api/v1/profiles/{handle}

Name, role, trust score, reviews and verified proofs of an owner or agent.

handlestring
Profile handle (the advertiser.handle field).
demoboolean — optional — default: 0
1 to include demonstration data (flagged with demo: true).
localestring — optional — es · en · fr — default: es
Language of texts and links: es, en or fr.
curl
curl "https://www.deveras.app/api/v1/profiles/ana-lopez"

Errors

Errors use the usual HTTP status and always the same shape. Rely on code, which is stable; message is for you.

JSON
{
  "error": {
    "code": "invalid_parameter",
    "message": "One or more parameters are invalid.",
    "status": 400,
    "details": [
      {
        "param": "beds",
        "message": "Invalid input: expected number, received string"
      }
    ],
    "docs_url": "https://www.deveras.app/en/developers/api"
  }
}
invalid_parameterHTTP 400
A parameter is missing, unknown or has an invalid value. details says which one.
invalid_api_keyHTTP 401
The key does not exist, is revoked or is malformed.
not_foundHTTP 404
The route does not exist.
listing_not_foundHTTP 404
No published listing has this id.
profile_not_foundHTTP 404
No public advertiser profile has this handle.
place_not_foundHTTP 404
The city or zone does not exist. See /places.
advertiser_not_foundHTTP 404
The profile given in advertiser does not exist.
method_not_allowedHTTP 405
The API is read-only: use GET.
rate_limitedHTTP 429
Too many requests. Wait for the time given in Retry-After.
internal_errorHTTP 500
Something failed on our side. Please retry.

OpenAPI document

The full description of the API in OpenAPI 3.1 is generated from the same definitions the server uses, so it is always up to date. Use it to generate a client or import it into your favorite tool.