# Airbnb Portugal AL License Checker (`nice_dev/airbnb-portugal-license-checker`) Actor

Check the AL licence number of Airbnb and Booking.com listings in Portugal against the national register (RNAL): verdict, registered holder with tax number, e-mail and phone, address with floor, authorised guests, insurance — or list every AL of a municipality.

- **URL**: https://apify.com/nice_dev/airbnb-portugal-license-checker.md
- **Developed by:** [Nice Dev](https://apify.com/nice_dev) (community)
- **Categories:** Travel, Real estate, MCP servers
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### 🏠 What is Airbnb Portugal AL License Checker?

**Airbnb Portugal AL License Checker** checks the **AL licence number** (`12345/AL`) that each Airbnb listing in Portugal displays — and, if you want, each **Booking.com** property — against **Turismo de Portugal's national register of local accommodation (RNAL)**, and tells you whether it is **valid, never issued, cancelled, used for another property or for more guests than allowed**. Each result gives what the register publishes about the licence: the **registered holder** (person or company) with its **tax number, e-mail and phone**, the **address with floor and side**, the **authorised guests**, bedrooms and beds, the **insurance**, the occupancy permit and the dates — plus the listing's own details (host, business details of professional hosts, capacity, rating, amenities, price).

Type a **place** (`Lisbon, Portugal`), draw a **map area**, paste **Airbnb or Booking.com URLs** or **listing IDs**, give **licence numbers** alone — or list **every AL of a municipality** straight from the register, without any listing — click **Start**, and download the results in JSON, CSV or Excel. No login, nothing to set up. Built for city councils, tourism inspectors, property managers, cleaning and maintenance companies looking for AL operators, investors and journalists.

### 📋 What data can you extract from Airbnb, Booking.com and the Portuguese AL register?

One item per listing checked (or per licence number given alone, or per register record of a municipality), 143 fields:

| Category | What you get |
| --- | --- |
| ✅ **Verdict** | valid, never issued, not in the register, another property's number, more guests than allowed, unreadable number, no number, exempt claimed, hotel register… with the reasons and one plain sentence |
| 🪪 **Licence number** | the number as the listing shows it and as the register writes it, other numbers shown, the exemption claimed, other listings of the run with the same number |
| 👤 **Registered holder** | name, tax number (NIF or NIPC), person or company, role (owner, tenant, borrower, assignee…), e-mail, landline, mobile — every holder when there are several |
| 🏛️ **Registered accommodation** | name, kind (apartment, house, rooms, guesthouse, hostel), registration and opening dates, authorised guests, bedrooms, beds, dormitories, occupancy permit, built before or after 1951 |
| 📍 **Registered address** | street, number, floor, side, postal code, town, parish, municipality, district, position and distance to the listing |
| 🛡️ **Insurance** | insurer, policy number, start and end dates |
| 🏠 **Listing** | title, type of place, city, position, guests, bedrooms, beds, bathrooms, rating and sub-ratings, badges, highlights, house rules and the host's own rules, where you'll sleep, description, amenities, photos |
| 👥 **Host** | name, profile link, business or individual, verified, years hosting, response rate and time, rating, reviews, co-hosts, how many listings they manage |
| 🏢 **Business host details** | business name, business registry, tax identification number, e-mail, phone and address that professional hosts must show in the EU |
| 💶 **Price** | total price of the stay, price per night, price breakdown, dates (from the Airbnb search results) |
| 🅱️ **Booking.com** | property ID and page, the licence sentences shown, professional host or not |
| 🏢 **Professional host contact** (option) | business email and phone of professional Airbnb hosts, from publicly available sources, when neither Airbnb nor the register gave one |
| 📞 **Business contact** (option) | the business e-mail and phone Booking.com shows for its professional hosts, on Booking.com properties (the professional block Airbnb shows stays free in every Airbnb row) |
| 📷 **Photos** (option) | the first photos of each listing kept in the run's storage, with their public links, their SHA-256 and the time of the download - a dated copy; the photo links stay free |
| ⚡ **Cards only** (option) | the card of each Airbnb search result - link, title, type, price, rating, position, bedrooms - without opening the listing, so without a licence number or a verdict |
| 🎯 **Risk score** (option) | a score from 0 to 100 per listing and the short codes of the rules behind it: the verdict, a number shown twice, a registered address far from the listing, an insurance ended, a host with several listings… |
| 🏷️ **AI labels** (option) | four yes / no labels read in the English description of an Airbnb listing — managed by a company, self check-in, monthly stays, licence mentioned — with their scores |
| 🏘️ **Comparables** (option) | the nearest Airbnb listings of the same type and size around each Airbnb listing, with their price per night, rating and distance, and their median price |

Every field, with an example, is listed in the **Output** section below.

### ✅ Why use Airbnb Portugal AL License Checker?

- 🏛️ **The official register, not a format check**: each number is looked up live in Turismo de Portugal's register of local accommodation, the day of the run.
- 👤 **Who runs it, and how to reach them**: the register publishes the holder of every licence with an e-mail (on every record) and a phone (on about 1 in 3) — nothing a listing shows.
- 🔎 **Finds what a glance cannot**: numbers above any number ever issued, cancelled numbers, numbers of a property kilometres away or on another island, listings taking more guests than the licence allows.
- 🗂️ **Nine ways in, in one run**: places, map areas, Airbnb search URLs, listing URLs, listing IDs, Booking.com property URLs, licence numbers alone, whole municipalities and districts of the register.
- 🅱️ **Airbnb and Booking.com**: the same place checked on both platforms in one run.
- 🗺️ **Whole cities**: Airbnb shows 270 listings per search and Booking.com 1,000; a full search is cut into smaller ones automatically to reach the others.
- 🔔 **Monitoring built in**: tick **Only new listings**, schedule the Actor, and each run returns (and charges) only what it has never delivered before — new listings, or the new AL registrations of a municipality.
- 🔌 API, scheduling, integrations (Make, Zapier, n8n, Google Sheets…) and JSON/CSV/Excel export via the Apify platform.

### 🚀 How to check Airbnb AL licences in Portugal

1. Create a free Apify account.
2. Open **Airbnb Portugal AL License Checker** and type a **Place** (e.g. `Lisbon, Portugal`); tick **Booking.com** in **Platforms** to check it too.
3. Or paste **Airbnb URLs** (search results or single listings), **listing IDs**, **Booking.com property URLs**, **map areas**, **licence numbers to check** without any listing, or **municipalities** to list every registered AL.
4. Set **Max results** (100 by default, 0 = no limit) — and keep only the suspicious listings with **Keep only these verdicts** — then click **Start**.
5. Download the dataset in JSON, CSV, Excel or via API.

### 💰 How much does it cost to check AL licences?

This Actor uses **pay per event** pricing, with one price per kind of result — an **Airbnb listing** checked, a **Booking.com property** checked, or a **register record** (a licence number given alone, or a record of a municipality list) — a small fee per run start, a fee per **host profile** (**Host's listing count**, one per host whose profile reaches your results, not per listing), one for a **card alone** (`listing-card`, the only price of a run with **Cards only (fast)**), one for a **photo downloaded** (`photo-download`, one per photo delivered, charged only once the **Pricing** tab lists it), one for a **business contact** (`business-contact`, one per Booking.com property whose row carries an e-mail or a phone, charged only once the **Pricing** tab lists it), one for a **professional host contact** (`pro-host-contact`, one per Airbnb listing whose row carries an e-mail or a phone of the host's company, charged only once the **Pricing** tab lists it), a fee per **risk score** (`risk-score`, one per listing whose row carries a score, charged only once the **Pricing** tab lists it), a fee per listing given its **AI labels** (`ai-labels`, charged only once the **Pricing** tab lists it), a fee per listing given its **comparables** (`comparables`, charged only once the **Pricing** tab lists it) and a lower fee for each result a filter of the Actor drops — `filter-check` when the search results are enough to drop it (minimum rating, host type, excluded words), `detail-filter-check` when its page and the register had to be read (verdicts, regions, holder, phone; also a licence number or a register record that these filters drop). A result you keep costs its normal price: filtering never costs more than taking everything. The prices are shown on the **Pricing** tab of this page. Platform usage (compute, proxy) is included in the price.

### ⚙️ Input

A place on Airbnb and Booking.com, only the listings whose licence does not match the register:

```json
{
    "location": "Lisbon, Portugal",
    "sources": ["airbnb", "booking"],
    "maxItems": 200,
    "onlyVerdicts": ["never_issued", "not_in_register", "other_property", "over_capacity"]
}
```

Every AL registered in two municipalities since September, companies with a phone only:

```json
{
    "municipalities": ["Lisboa", "Porto"],
    "registeredAfter": "2026-09-01",
    "holderType": "company",
    "onlyWithPhone": true,
    "maxItems": 500
}
```

Several places and a map area, a cap per search, only the listings not delivered before:

```json
{
    "locations": ["Albufeira", "Lagos"],
    "boundingBoxes": ["38.70, -9.16, 38.73, -9.12"],
    "maxItemsPerQuery": 100,
    "onlyNew": true,
    "stateKey": "algarve-weekly"
}
```

Your own URLs, listing IDs, and licence numbers alone:

```json
{
    "startUrls": [
        { "url": "https://www.airbnb.com/s/Porto--Portugal/homes?adults=2" },
        { "url": "https://www.airbnb.pt/rooms/1550967010992579703" }
    ],
    "listingIds": ["13231767"],
    "bookingUrls": ["https://www.booking.com/hotel/pt/charming-city-centre-apartment.html"],
    "licenseNumbers": ["42391/AL", "AL 40000", "12833"],
    "maxItems": 500
}
```

| Field | Notes |
| --- | --- |
| `sources` | Where the places are searched: `airbnb`, `booking`, or both (map areas: Airbnb only). |
| `startUrls` | Airbnb search results pages (filters kept, pagination and map splitting automatic) or single listing pages, any Airbnb domain (e.g. `https://www.airbnb.pt/rooms/1550967010992579703`). |
| `listingIds` | Airbnb listing IDs alone (the digits after `/rooms/`). Checked in the order given and before any search: with `maxItems`, the first ones are the ones saved. |
| `bookingUrls` | Booking.com property pages (e.g. `https://www.booking.com/hotel/pt/charming-city-centre-apartment.html`), checked in the order given, before any search. |
| `location`, `locations` | Places as typed in the platforms' search box (e.g. `Lisbon, Portugal`, `Albufeira`); one search each, on each platform of `sources`. |
| `boundingBoxes` | Map rectangles `south, west, north, east` (e.g. `38.70, -9.16, 38.73, -9.12`), Airbnb only: the surest way to cover a whole city. |
| `licenseNumbers` | AL licence numbers checked in the register without any listing (e.g. `42391/AL`, `AL 40000`, `12833`). One result per licence: two spellings of the same number (`42391/AL`, `AL42391`) are checked once. Several numbers in one entry (commas, semicolons or line breaks between them) count one each. |
| `municipalities` | Every AL registered in these mainland municipalities, from the register, without any listing (e.g. `Lisboa`, `Porto`, `Albufeira`, `Cascais`); newest registrations first. |
| `districts` | Every AL registered in these mainland districts (e.g. `Faro` for the Algarve, `Lisboa`). |
| `registeredAfter` | Register lists only: registered on or after this date (e.g. `2026-09-01`). |
| `modalities` | Register lists only: kinds of accommodation (`apartment`, `house`, `rooms`, `guesthouse`, `hostel`). |
| `maxItems` | Stop after this many results for the whole run (`0` = unlimited). Order: licence numbers alone, then the listing IDs and URLs you pasted (Airbnb and Booking.com), then the searches — with Airbnb and Booking.com both searched, Booking.com first takes half of what is left, then Airbnb, then Booking.com fills what Airbnb left — then the register lists. |
| `maxItemsPerQuery` | Cap for EACH search (place, map area, search URL, municipality or district). 0 = no per-search cap. |
| `splitMap` | Cut a full Airbnb search (270 listings) into smaller map areas to reach the others (default on). |
| `checkIn`, `checkOut`, `adults`, `children`, `infants`, `pets` | Travel dates and guests sent to Airbnb's search (e.g. `2027-07-12`, today or later in Portugal); the price of the stay then follows them, and `checkIn` / `checkOut` of each listing are these dates. |
| `currency`, `priceMin`, `priceMax` | Currency of the prices (`EUR`, `USD`, `GBP`) and price per night bounds. |
| `roomTypes` | Airbnb's type of place: `entire_home`, `private_room`, `shared_room`, `hotel_room`. |
| `propertyTypes` | Airbnb's property type: `house`, `apartment`, `guesthouse`, `hotel`. |
| `minBedrooms`, `minBeds`, `minBathrooms`, `superhostOnly` | Airbnb's own filters: at least this many rooms, Superhosts only. |
| `bookingPropertyTypes` | Booking.com searches: `apartment`, `holiday_home` (hotels register elsewhere). |
| `onlyVerdicts` | Keep only the results with these verdicts (e.g. `never_issued`, `not_in_register`, `over_capacity`). |
| `regions` | Keep only the results of these regions (`mainland`, `madeira`, `azores`, `other`). |
| `holderType`, `onlyWithPhone` | Keep only the results whose registered holder is a private person or a company (`any`, `person`, `company`); only those with a phone in the register. |
| `hostType` | `any`, `business` or `individual` hosts. |
| `minRating`, `excludeKeywords` | Minimum Airbnb rating out of 5; words that drop a listing whose title contains them. |
| `gpsToleranceKm` | Distance above which the registered property is another one (`1.5` km by default: Airbnb blurs positions). |
| `includeHostProfile` | Read each Airbnb host's profile once for the number of listings they manage (default off). |
| `includeBusinessContact` | Ask Booking.com for the business e-mail and phone of its professional hosts (default off: charged per Booking.com property whose row carries one). |
| `includeProHostContact` | Add the business e-mail and phone of professional Airbnb hosts, from publicly available sources, when the listing has none yet (default off: charged per listing given a contact; only when a company name is known, never under a person's name). |
| `downloadPhotos`, `maxPhotosPerListing` | Download the first photos of each listing into the run's storage and give their links, hashes and date (default off: charged per photo delivered; the second field is the number of photos per listing, 5 by default). |
| `cardsOnly` | Deliver only the card of each Airbnb search result and open no listing (default off: no number, no verdict; a price per card, nothing else charged). |
| `includeRiskScore` | Give each listing a risk score from 0 to 100 and its reasons (default off: charged per listing whose row carries a score). |
| `includeAiLabels` | Label the description of each Airbnb listing with four AI labels (default off: charged per listing given its labels; needs 2 GB of memory, otherwise skipped and not charged). |
| `includeComparables`, `maxComparablesPerListing` | Add the neighbouring Airbnb listings of each Airbnb listing and their median price per night (default off: charged per listing given comparables; the second field is the most kept per listing, 10 by default). |
| `onlyNew`, `stateKey`, `resetState` | Monitoring: only the results never delivered under this memory key; `resetState` forgets the memory. |
| Advanced | `proxyConfiguration` (Apify proxy by default, included in the price; the residential proxy is not available), `maxConcurrency`, `maxRequestsPerMinute`, `minRequestIntervalMs`, `maxRequestRetries`, `debugLog`. |

### 📦 Output

A real result of Booking.com, Lisbon (shortened: some fields left out; the holder's e-mail and phone masked here):

```json
{
    "id": "4340822",
    "source": "booking_listing",
    "url": "https://www.booking.com/hotel/pt/charming-city-centre-apartment.html",
    "title": "Charming City Centre Apartment",
    "verdict": "valid",
    "verdictReasons": [],
    "verdictNote": "64452/AL is in the register (Lisboa, floor 2 Esq).",
    "isSuspicious": false,
    "region": "mainland",
    "registrationText": "License number: 64452/AL",
    "licensePhrases": [
        "License number: 64452/AL"
    ],
    "licenseNumber": "64452/AL",
    "licenseNumberNormalized": "64452/AL",
    "otherLicenseNumbers": [],
    "exemption": null,
    "numberSharedWith": [],
    "registerFound": true,
    "registerNumber": "64452/AL",
    "registerUrl": "https://rnt.turismodeportugal.pt/RNT/RNAL.aspx?nr=64452",
    "registerName": "IVY APARTMENTS",
    "registerType": "Apartamento",
    "registerDate": "2018-02-14",
    "registerOpeningDate": "2018-02-14",
    "registerHolder": "IVY - APARTMENTS, UNIPESSOAL LDA",
    "registerHolderTaxId": "514996668",
    "registerHolderType": "company",
    "registerHolderRole": "tenant",
    "registerHolderEmail": "jac•••@gmail.com",
    "registerHolderPhone": null,
    "registerHolderMobile": "91•••2412",
    "registerHolders": [
        {
            "name": "IVY - APARTMENTS, UNIPESSOAL LDA",
            "taxId": "514996668",
            "type": "company",
            "role": "tenant",
            "roleText": "Arrendatário",
            "email": "jac•••@gmail.com",
            "phone": null,
            "mobile": "91•••2412"
        }
    ],
    "registerAddress": "Rua Passadiço 120, 2 Esq, 1150-256 Lisboa",
    "registerStreet": "Rua Passadiço",
    "registerStreetNumber": "120",
    "registerFloor": "2",
    "registerSide": "Esq",
    "registerPostalCode": "1150-256",
    "registerParish": "Santo António",
    "registerMunicipality": "Lisboa",
    "registerDistrict": "Lisboa",
    "registerPlaces": 3,
    "registerBedrooms": 1,
    "registerBeds": 2,
    "registerInsurer": "Companhia de Seguros Allianz Portugal, S.A.",
    "registerInsuranceEnd": "2027-06-26",
    "registerLatitude": 38.7229392215195,
    "registerLongitude": -9.14413037293316,
    "registerPositionReliability": "reliable",
    "distanceKm": 0,
    "registerSource": "Turismo de Portugal — Registo Nacional de Alojamento Local (RNAL)",
    "registerCheckedAt": "2026-09-26T12:34:15.441Z",
    "propertyType": "APARTMENT",
    "city": "Lisboa",
    "latitude": 38.7229818,
    "longitude": -9.1441565,
    "reviewsCount": 134,
    "badges": [],
    "locationText": "Rua Passadiço, 120 2 Esq",
    "highlights": [],
    "houseRules": [],
    "sleepingArrangements": [],
    "amenities": [],
    "images": [
        "https://cf.bstatic.com/xdata/images/hotel/square600/171685746.webp?k=a10d0a375917789fbff91dc18bba0de7caccacdea4c60cdad954672a10975d0b&o="
    ],
    "hostType": "business",
    "coHosts": [],
    "hostListingIds": [],
    "priceDetails": [],
    "bookingId": "4340822",
    "bookingPageName": "charming-city-centre-apartment",
    "isTrader": true,
    "riskReasons": [],
    "riskChecksSkipped": [],
    "comparables": [],
    "photoFiles": [],
    "photoSha256": [],
    "proHostEmails": [],
    "proHostPhones": [],
    "scrapedAt": "2026-09-26T12:34:13.421Z"
}
```

You can download the dataset in various formats such as JSON, HTML, CSV or Excel. The **Overview**, **Registered holders and contacts**, **Register record** and **Hosts and business details** views of the Output tab show the main columns.

#### All 143 fields

| Fields | What you get |
| --- | --- |
| `id`, `source`, `url`, `title` | **Result**: Airbnb id, Booking.com id, the licence number given alone or the register number; `airbnb_listing` / `booking_listing` / `license_number` / `register_list`; link; title or registered name |
| `verdict`, `verdictReasons`, `verdictNote`, `isSuspicious`, `region` | **Verdict**: see the table of verdicts below; the reasons found; one sentence; `mainland`, `madeira`, `azores`, `other` |
| `registrationText`, `licensePhrases`, `licenseNumber`, `licenseNumberNormalized`, `otherLicenseNumbers`, `exemption`, `numberSharedWith` | **Licence number**: the block or sentences as shown, the number as written and as the register writes it, other numbers shown, the exemption claimed, the other listings of the run with the same number |
| `registerFound`, `registerNumber`, `registerUrl`, `registerName`, `registerType`, `registerDate`, `registerOpeningDate` | **Register**: found or not, the number, the public page of the record, the registered name and kind, registration and opening dates |
| `registerHolder`, `registerHolderTaxId`, `registerHolderType`, `registerHolderRole`, `registerHolderEmail`, `registerHolderPhone`, `registerHolderMobile`, `registerHolders` | **Registered holder**: name, NIF / NIPC, `person` / `company`, `owner` / `tenant` / `borrower` / `assignee`…, e-mail, landline, mobile; every holder of the record |
| `registerAddress`, `registerStreet`, `registerStreetNumber`, `registerFloor`, `registerSide`, `registerPostalCode`, `registerLocality`, `registerParish`, `registerMunicipality`, `registerDistrict` | **Where the licence is**: `Rua Passadiço 120, 2 Esq, 1150-256 Lisboa`, its parts, parish, municipality, district |
| `registerPlaces`, `registerBedrooms`, `registerBeds`, `registerDormitories`, `registerBunkBeds`, `registerOccupancyPermit`, `registerBuiltAfter1951` | authorised guests, bedrooms, beds, dormitories and bunk beds of a hostel, occupancy permit, built after 1951 |
| `registerInsurer`, `registerInsurancePolicy`, `registerInsuranceStart`, `registerInsuranceEnd` | liability insurance |
| `registerLatitude`, `registerLongitude`, `registerPositionReliability`, `distanceKm`, `registerHighestNumber`, `registerSource`, `registerCheckedAt` | position of the registered property (mainland), how reliable it is, km to the listing, highest number issued, source, time of the lookup |
| `propertyType`, `roomType`, `city`, `latitude`, `longitude`, `isExactLocation`, `locationText`, `locationDescription` | **Listing**: `Entire rental unit`, `Entire home/apt`, city, position (blurred by Airbnb), Airbnb's exact-location flag, area (address on Booking.com), the host's text about the neighbourhood |
| `personCapacity`, `bedrooms`, `beds`, `bathrooms`, `sleepingArrangements` | guests, rooms, where you'll sleep |
| `rating`, `reviewsCount`, `ratingAccuracy`, `ratingCheckin`, `ratingCleanliness`, `ratingCommunication`, `ratingLocation`, `ratingValue` | Airbnb ratings out of 5 and number of reviews |
| `isSuperhost`, `isGuestFavorite`, `isNewListing`, `homeTier`, `badges`, `highlights` | Superhost, Guest favourite, new listing, tier, search badges, highlights |
| `description`, `descriptionLanguage`, `houseRules`, `houseRulesAdditional`, `amenities`, `images` | full description, its language, house rules, the host's own additional rules, amenities, photo links |
| `hostId`, `hostName`, `hostUrl`, `hostType`, `hostIsVerified`, `hostYearsHosting` | **Host**: id, name, profile link, `business` / `individual`, verified, years hosting |
| `hostResponseRate`, `hostResponseTime`, `hostRating`, `hostReviewsCount`, `hostAbout`, `hostPictureUrl`, `hostLocation`, `coHosts` | response rate and time, rating and reviews over all their listings, presentation, photo, where they live, co-hosts |
| `hostListingsCount`, `hostListingIds` | with **Host's listing count**: how many listings they manage, the IDs their profile shows (10 at most) |
| `businessName`, `businessRegistry`, `businessTaxId`, `businessEmail`, `businessPhone`, `businessAddress` | **Business host details** (EU rule for professional hosts) |
| `price`, `currency`, `pricePerNight`, `priceText`, `priceDetails`, `priceNights`, `checkIn`, `checkOut` | **Price** from the Airbnb search results: total, currency, per night, as shown, breakdown, nights, dates |
| `searchUrl`, `bookingId`, `bookingPageName`, `isTrader` | the search the listing was found by; **Booking.com** id, page name, professional host |
| `riskScore`, `riskReasons`, `riskChecksSkipped` | **Risk score** (option): 0 to 100, the codes of the rules that gave it, the rules that could not play for lack of data |
| `photoFiles`, `photoSha256`, `photosDownloadedAt` | **Photos** (option): the public links of the photos kept in the run's storage, their SHA-256, the time of the download |
| `proHostCompany`, `proHostWebsite`, `proHostEmails`, `proHostPhones`, `proHostContactSourceUrl`, `proHostContactConfidence` | **Professional host contact** (option): the company of a professional Airbnb host, its website, its business e-mails and phones, the page they come from, how sure the contact is |
| `aiLabels`, `aiLabelScores` | **AI labels** (option): four yes / no labels read in the description and the confidence behind each |
| `comparables`, `comparablesMedianPrice` | **Comparables** (option): the nearest Airbnb listings of the same type within one bedroom (id, link, price per night, currency, bedrooms, rating, distance) and their median price per night |
| `scrapedAt` | time of the check |

### 💡 Tips

#### What each verdict means

When a listing has several problems, its verdict is the highest one in this table, and `verdictReasons` lists them all.

| Verdict | Meaning |
| --- | --- |
| `valid` | The number is in the register; the registered property is near the listing and the guests fit the authorised guests (otherwise `verdictNote` says what could not be checked: no position in Madeira, no guests on Booking.com). |
| `never_issued` | Not in the register, and higher than any AL number ever issued: an invented number. |
| `not_in_register` | A real AL number but not in the register: cancelled, or never registered (the register does not say which). |
| `other_property` | The number belongs to a property far from the listing (more than **Distance tolerance**), or to another region (a mainland number on a Madeira listing). |
| `over_capacity` | The listing takes more guests than the licence allows. |
| `unknown_format` | The text shown is not an AL number (`0000`, `1819/18`, seven digits). |
| `no_number` | The listing shows no licence number. |
| `exempt_claimed` | The listing says it needs none (Airbnb's `Exempt`, Booking.com's "doesn't require a short-term rental license"). |
| `other_register` | A hotel: hotels are registered in RNET, not in the AL register (a hotel room without a number, or an `RNET` number). |
| `region_not_covered` | The Azores (their own register, RRAL) or outside Portugal: the number is given, not checked. |
| `register_unavailable` | The register could not be read in this run, after 3 tries on 3 different IPs. |

#### Risk score (option)

Tick **Risk score (0-100)** to get, for each Airbnb listing and Booking.com property, one number from 0 (nothing wrong) to 100 and the codes of the rules behind it. The rules add their weights up, 100 at most, the verdict first:

| Rule (code in `riskReasons`) | Points |
| --- | --- |
| Verdict `never_issued` (`verdict_never_issued`) | 80 |
| Verdict `not_in_register` (`verdict_not_in_register`) | 65 |
| Verdict `other_property` (`verdict_other_property`) | 55 |
| Verdict `no_number` (`verdict_no_number`) | 50 |
| Verdict `unknown_format` (`verdict_unknown_format`) | 40 |
| Verdict `over_capacity` (`verdict_over_capacity`) | 35 |
| Verdict `exempt_claimed` (`verdict_exempt_claimed`) | 20 |
| Verdict `other_register` (`verdict_other_register`) | 10 |
| Verdict `region_not_covered` (`verdict_region_not_covered`) | 10 |
| The same number shown by another listing of the run (`number_shared`) | 20 |
| The registered address is more than 0.3 km from the listing (`distance_over_300m`) | 10 |
| The listing says an apartment where the register says a house (Moradia), or the other way round (`property_type_mismatch`) | 10 |
| The liability insurance of the register ended (`insurance_expired`) / the register shows none (`no_insurance`) | 15 / 10 |
| The host manages 3 listings or more (`host_3_or_more_listings`) / 2 listings (`host_2_listings`) | 25 / 10 |

The host's listings count only with **Host's listing count** ticked; this Actor reads no availability calendar, so the "open more than 180 nights" rule never plays and is always named in `riskChecksSkipped`. A rule whose data is not read is skipped, named there, and never counted as a risk; a property type or a distance the register cannot give (number not found) is skipped the same way. When the register could not be read in the run (`register_unavailable`) there is nothing to score: no score, nothing charged. It is a guide to which listings to look at first, not a finding of fault.

#### AI labels (option)

Tick **AI labels** to have the description of each Airbnb listing read for four things, each a yes / no in `aiLabels` with its confidence (0 to 1) in `aiLabelScores`:

| Label (key) | What it says | True from |
| --- | --- | --- |
| `managed_by_company` | The listing is run by a company or a property manager | 0.50 |
| `self_check_in` | Guests check in by themselves (lockbox, keypad, code) | 0.60 |
| `long_stay` | Monthly or long stays (28 nights or more) | 0.50 |
| `mentions_licence` | The text mentions a licence or a permit (not the registration block Airbnb adds) | 0.50 |

The labels are read in the host's own text and are **indications, not facts**: the cut-offs are set high so that a label marked true is rarely wrong, and a host who does not write it down gets `false` (a long description is read to its end, up to about 6,000 characters). The cut-offs were set on 40 English Airbnb descriptions read by hand (Toronto, September 2026) — a small sample, not measured again on Portuguese listings: expect some misses and some false alarms. **Only English descriptions are read**: a description in Portuguese, Spanish or another language, a Booking.com property or a listing without a description gets `null` and is not charged. The option needs **2 GB of memory** (Run options → Memory): on a smaller run it is skipped, the log says so, and nothing is charged. The descriptions are read one at a time, so a run with the option is slower and costs more compute; it is charged once per listing given its labels (`ai-labels`).

#### Comparables (option)

Tick **Comparable listings** to get, for each Airbnb listing, `comparables`: the Airbnb listings around it that are of the same type of place (entire home, private room…) and within one bedroom of it, the nearest first, up to **Max comparables per listing** (10 by default) — each with its link, `pricePerNight`, `bedrooms`, `rating` and `distanceKm` — and `comparablesMedianPrice`, their median price per night. Give **Check-in** and **Check-out** to get the prices (the nightly rate of those dates, before taxes and fees, in the currency of the run); without dates the neighbours carry no price and there is no median.

The neighbours are read from the search results around the listing, not from their own pages, and one search serves all the listings of the same area (about 500 m), type of place and size: a run over a whole district costs a few searches, not one per listing (a district with every size of home costs one search per type of place and size). Airbnb shows the 18 best results of an area, so the neighbours are those of that page that fit: a quiet area may give fewer than the maximum; a listing whose type or position is unknown, or an entire home whose bedrooms are unknown, gets none. A listing is charged `comparables` only when its row carries at least one neighbour.

#### Business contact (option)

A professional Booking.com host (`isTrader`: a company, as Booking.com labels it) shows a business e-mail and phone on its property page. Tick **Business contact (Booking.com)** to get them in `businessEmail` and `businessPhone` of the Booking.com rows - for the professional hosts only: a private host's contact is not given. Of 40 properties of Lisbon (apartments and holiday homes, October 2026), 29 were professional and all 29 gave both. A property is charged `business-contact` once, when its row carries an e-mail or a phone; a row without either costs nothing extra. The e-mail and phone of the professional block that Airbnb shows (EU rule) stay in the Airbnb rows for free, as before: this option does not touch them. These are professional contact details published by the host on Booking.com; you are responsible for using them in compliance with the applicable law (see the FAQ). Not available with **Cards only (fast)**.

#### Professional host contact (option)

The register gives the holder's e-mail on nearly every record, and Airbnb shows an e-mail or a phone for the professional hosts who declare a business block; for the others - an invented or cancelled number, a record without a contact, a host that is a company - there is none. Tick **Professional host contact** to get, **only for those listings**, the **business email and phone of professional hosts, from publicly available sources**: `proHostEmails` and `proHostPhones` (3 each at most, phones as `+351 912 345 678`), with `proHostContactSourceUrl` (the page they were read from), `proHostCompany` and `proHostWebsite`, and `proHostContactConfidence` (`high` when an e-mail is on the company's own domain, `medium` otherwise). A listing that already has a contact in its `businessEmail` or `businessPhone` or in the registered holder's e-mail, phone or mobile is not looked up. A host is looked up only when a company name is known: the business name Airbnb gives, or a host or co-host whose name is a company's. A host with a person's name only is never looked up, however many listings it manages. A company is looked up once per run, however many listings it has; its own website is searched in Portugal (`.pt`, `.com`) and must name the company and place it in Portugal. When no contact is found, the listing is delivered as it is and not charged; you pay `pro-host-contact` once per listing whose row carries an e-mail or a phone. Not available with **Cards only (fast)**; for Booking.com properties see **Business contact**.

#### Photos (option)

The links of a listing's photos are in `images` in every run, for free. Tick **Download photos** to also keep the photos themselves: the first **Max photos per listing** (5 by default) of each Airbnb listing - a Booking.com property has its main photo - are downloaded into the key-value store of your run, and the row gets `photoFiles` (the public link of each, in the order of the listing's photos), `photoSha256` (the SHA-256 of each) and `photosDownloadedAt` (the time of the download). It is a dated copy of what the listing showed that day, and the hash shows that a file is the one that was downloaded. A photo that cannot be had - gone, not an image, too big - is left out and not charged; you pay `photo-download` for each photo delivered. Photos are the sites' own files, kept as they are: your storage grows by their weight (a few hundred KB each), and the records follow the retention of your run's storage. Not available with **Cards only (fast)**.

#### Cards only (option)

Tick **Cards only (fast)** to get just what Airbnb shows in its search results, without opening the listings: the link, title, type of place (`propertyType`: Flat, Room…), price, rating, position, bedrooms and the dates of the search. It is faster and cheaper than a full check, and the right choice to list or monitor what is offered; the rows have `source` set to `airbnb_card` and `verdict` set to `unchecked` - **no licence number, no verdict, nothing from the register**. A run in this mode is charged one `listing-card` per card, and nothing else (no check fee for a card your filters drop: minimum rating, host type, excluded words and the dates and prices of the search still apply).

It needs a place, a map area or an Airbnb search URL. It cannot be mixed with what needs the listing page or the register - host profile, risk score, comparables, AI labels, listing URLs and IDs, Booking.com, licence numbers, register lists (municipalities, districts), and the filters on verdicts, regions, registered holder and holder phone: the run is refused at the start, naming each one.

#### How to cover a whole city

Airbnb shows at most 270 listings per search. With **Split full areas** on (default), a full search is cut into 4 smaller map areas, again and again, until each shows everything; add **Map areas** (`boundingBoxes`) to be sure a whole town is covered. Booking.com shows 1,000 properties per search: a bigger one is also read district by district (Lisbon counts about 5,400 flats and holiday homes).

#### Every AL of a municipality, without Airbnb

Fill **Register lists: municipalities** (`Lisboa`, `Porto`, `Albufeira`…) or **districts** (`Faro` = the Algarve): the Actor lists every AL registered there (Lisbon about 11,900, the district of Faro about 45,000), newest first, and reads each record — holder, contacts, address. Narrow them with **Registered on or after** (the new operators of the month) and **Kind of accommodation**. Mainland only: the open list of the register has no Madeira or Azores (their numbers are checked all the same when a listing or a number alone shows them — Madeira's only, the Azores keep their own register).

#### How to reduce costs

The levers are `maxItems`, `maxItemsPerQuery`, **Keep only these verdicts**, **Registered holder** and **Holder phone only** (a result dropped costs only the filter fee), turning **Host's listing count**, **Risk score (0-100)**, **AI labels** and **Comparable listings**, **Business contact (Booking.com)**, **Professional host contact** and **Download photos** off (the default), using **Cards only (fast)** when you do not need the licence number, and `onlyNew` for recurring runs (you never pay twice for the same result); **Host's listing count** is off by default.

#### Several searches in one run

Fill `locations` and / or `boundingBoxes`, or paste several search URLs: one search each (up to 100 places, 100 map areas and 1,000 URLs per run), and up to 100 municipalities. A listing found by several searches is saved — and charged — once. Set `maxItemsPerQuery` to give every search its own cap.

#### Monitoring: only the new listings

Tick **Only new listings** (`onlyNew`) and schedule the Actor. The first run returns everything; each later run skips what was already delivered: not saved, not charged, and its page not even opened. With **Register lists**, a weekly run returns the new AL registrations of the municipality. The memory lives in a named key-value store of your account (`airbnb-portugal-license-checker-seen`, up to 150,000 listings per key) and is only updated with results that really reached the dataset, plus, apart, the Airbnb listings your filters dropped: an Airbnb listing your filters drop is checked (and charged) once; the next runs with the same filters skip it for free. Change a filter, or tick `resetState`, to check them again. Give each schedule its own `stateKey`, and tick `resetState` once to start over. A result saved while the register could not be read (`register_unavailable`) is not remembered, saved or dropped: the next run checks its licence, and charges it, again. A listing whose licence changed is not returned again: to re-check known listings, give their IDs in a run without **Only new listings** (or with another `stateKey`).

#### What the register can and cannot say

The register lists the active licences: a number that is absent was cancelled or never registered, and the register does not say which (`not_in_register`); a number above the highest ever issued was never issued (`never_issued`). It publishes, by law (Decree-Law 128/2014, article 10), the holder of every licence and their contacts: an e-mail on every record, a phone on about 1 record in 3; a floor on 6 in 10, the insurance on 3 in 4 (September 2026). Positions come from Turismo de Portugal's open list (mainland only) and are blurred on Airbnb by a few hundred metres: `other_property` is only raised past **Distance tolerance**. Booking.com does not say how many guests a property takes: `over_capacity` is never given there. On Airbnb in Lisbon and Porto, about 1 listing in 3 shows no number: nearly all of them are hotel rooms (`other_register`).

### 🔌 Integrations and API

Call the Actor via the Apify API, the JavaScript or Python clients, or connect it with integrations and webhooks (Make, Zapier, n8n, Google Sheets, Slack, Airtable…). The dataset can be fetched as JSON or CSV from any tool.

### 🤖 Use with AI agents (MCP)

AI agents (Claude, ChatGPT, Cursor…) can find and run this Actor through the [Apify MCP server](https://mcp.apify.com), billed to their Apify account like any run. It returns one item per listing checked (or per licence number, or per register record). Actor id: `nice_dev/airbnb-portugal-license-checker`; MCP server with this Actor only: `https://mcp.apify.com/?tools=fetch-actor-details,nice_dev/airbnb-portugal-license-checker`.

Smallest input, for a cheap first call:

```json
{
    "licenseNumbers": ["42391/AL"],
    "location": "Lagos, Portugal",
    "maxItems": 5
}
```

Key output fields: `url`, `verdict`, `verdictNote`, `licenseNumber`, `registerHolder`, `registerHolderEmail`, `registerPlaces`, `personCapacity`.

Cost: see the prices on the Pricing tab. Cap each call with `maxItems` and, through the API, with the run option `maxTotalChargeUsd`.

### ❓ FAQ

#### Is it legal to scrape Airbnb, Booking.com and use the register?

The Actor only reads what Airbnb and Booking.com show publicly to any anonymous visitor, and the public pages of Turismo de Portugal's register, whose holders and contacts are published by law (Decree-Law 128/2014, article 10); each result names its source. It logs in to nothing. The register's own terms say its contents may not be used outside its portal without Turismo de Portugal's written consent: check that your use is allowed. Results contain personal data (host names, and for about half of the licences a private person as holder, with tax number, e-mail and phone), which is protected by GDPR: do not store or contact it without a legitimate reason and a lawful basis. The business e-mail and phone of the **Business contact (Booking.com)** option are professional contact details that a professional host publishes on its own property page; sending commercial messages to them is governed by the law of the recipient's country (in the EU, the e-privacy rules and GDPR): you answer for how you use them. The **Professional host contact** option returns business contact details of companies, taken from publicly available sources, with the page each one comes from; it never looks up a private person, and the same duties apply to how you use them. You are responsible for using the data in compliance with the platforms' Terms of Service, the register's terms and applicable law. This Actor is not affiliated with Airbnb, Booking.com, Turismo de Portugal or any Portuguese administration.

#### Does it need a login or a proxy?

No login. The proxy is included in the price: leave the default setting (the residential proxy is not available). A request the site turns away is retried at once on a new proxy session, up to 10 times on top of the retries (without a proxy, after a pause of 5 seconds, doubled at each retry up to 150 seconds).

#### Is the data safe to open in Excel or to show on a web page?

Titles and descriptions are the hosts' own words, copied as they are; the register fields are copied as the register writes them. A text can begin with `-`, `+`, `=` or `@` (a phone number can start with `+`): Excel and Google Sheets may read such a cell of a CSV file as a formula or as a number, and a tax number or a postal code may lose a leading `0`. The Actor leaves the text as it is, so that the JSON and the API give the real value: when you open a CSV, import these columns as text. On a web page, escape every field like any text written by a stranger.

#### Known limitations

- The price comes from the Airbnb search results: listings given by URL or ID, and Booking.com properties, have none.
- The Azores keep their own register (RRAL), not read here: their listings get `region_not_covered`, their number given.
- The municipality and district lists cover mainland Portugal (the register's open list has no Madeira or Azores).
- Booking.com shows no guest count: its properties are never `over_capacity`; its score (out of 10) is not given in `rating`.
- The business details are shown by Airbnb only for the hosts who declare themselves as a business; Booking.com's contact of a professional host is given only with **Business contact (Booking.com)**.
- A host profile shows 10 of its listings at most: `hostListingsCount` is the full count, `hostListingIds` the first ones.
- `onlyNew` remembers ids, not their content: a listing whose licence changed is not returned again.

**A run the platform stops without warning** (out of memory, run timeout)

- Resurrect it: it goes on from where it stood at most a minute before the stop. What it had read since is read again, and what was already saved is skipped: nothing is delivered or charged twice, and `maxItems` still counts it.
- With `onlyNew`, the memory is saved after each write (at most once every 2 seconds): resurrect the stopped run and the results it had saved meanwhile join the memory; leave it stopped for good, and the next run may return the results of its last 2 seconds once more.

#### Something doesn't work?

The last line of the log counts the results saved, filtered out and no longer on the platform (removed while the run was reading them), and the requests that failed after every retry. Those requests and the removed listings are listed, with the reason, in the `FAILED_REQUESTS` record of the run's key-value store. A run that saved nothing and had failed requests fails, and its last message gives the cause. A register record that cannot be read does not fail the run: its listing gets `register_unavailable`. While the register answers a listing, the log may show `… read again` for it: it is read again once the answer is there, nothing is lost or charged twice.

If Airbnb or Booking.com change their pages, you are told instead of paying for blank rows. A results page that gives no listing the Actor can read is an error (listed in `FAILED_REQUESTS`), never a quiet "No listings found". If the first 20 listings read all lack their title, position, guests, room type, host, photos or registration block (hotels aside), the run saves nothing more, stops and fails, and its last message names the missing field: at most those first listings are charged. A listing a filter drops because such a field is missing counts among those 20. On Booking.com, 20 properties in a row without any licence field stop the whole run the same way. If Booking.com's API no longer accepts the Actor's request (a field it renamed), no longer answers at its address, or serves results none of which can be read, the run stops at once and fails with that reason, instead of trying every property again.

### 🛟 Support

Open an issue in the **Issues** tab with a link to your run: the run log and the `FAILED_REQUESTS` record of the key-value store show exactly which URLs failed and why.

# Actor input Schema

## `sources` (type: `array`):

Where the places are searched: Airbnb, Booking.com, or both (map areas: Airbnb only). Booking shows the AL number on nearly every holiday flat and says when a host claims not to need one. Listing URLs and IDs are read on their own platform whatever this says.

## `startUrls` (type: `array`):

Airbnb listing URLs (`https://www.airbnb.com/rooms/12345`, any Airbnb domain such as airbnb.pt) and/or Airbnb search URLs (`https://www.airbnb.com/s/Lisbon--Portugal/homes`, map searches included: their filters are kept, pagination and map splitting are automatic). Max 1 000 URLs.

## `listingIds` (type: `array`):

Airbnb listing IDs alone (the digits after `/rooms/`), one per line — checked in this order, before any search: with a result limit, the first ones are the ones saved. Max 1 000.

## `bookingUrls` (type: `array`):

Booking.com property pages (`https://www.booking.com/hotel/pt/alfama-sunny-flat.html`), one per line — checked in this order, before any search. Max 1 000.

## `location` (type: `string`):

A place in Portugal, as typed in the platforms' search box (e.g. `Lisbon, Portugal`, `Porto`, `Albufeira`, `Funchal`). Searched on each platform of **Platforms**; each listing found is opened and its AL licence checked in the national register (RNAL).

## `locations` (type: `array`):

Several places in one run (one search each, max 100). Added to **Place**; a listing found by several searches is saved once.

## `boundingBoxes` (type: `array`):

Map rectangles to search, one per line as `south latitude, west longitude, north latitude, east longitude` (e.g. `38.70, -9.16, 38.73, -9.12` for central Lisbon), on Airbnb only. The surest way to cover a whole city: Airbnb returns at most 270 listings per search, and a full area is split into smaller ones automatically.

## `licenseNumbers` (type: `array`):

AL licence numbers (RNAL) checked in the register without any Airbnb listing (e.g. `42391/AL`, `AL 57277`, `12833`). One result per licence (two spellings of one number are checked once). Several numbers in one entry (separated by commas, semicolons or line breaks) count one each. Max 1 000 numbers.

## `municipalities` (type: `array`):

Every local accommodation (AL) registered in these mainland municipalities (concelhos), listed from Turismo de Portugal's open data and read in the register one by one — holder, contacts, address — without any Airbnb search (e.g. `Lisboa`, `Porto`, `Albufeira`, `Cascais`). Newest registrations first. Mainland only: the open data has no Madeira or Azores. Max 100.

## `districts` (type: `array`):

Every local accommodation registered in these mainland districts (Faro = the Algarve), as for **Register lists: municipalities**. Newest registrations first.

## `maxItems` (type: `integer`):

Maximum number of results (listings checked + licence numbers + register records) to save for the whole run, after filters. 0 = no limit.

## `maxItemsPerQuery` (type: `integer`):

Cap for EACH search (place, map area or search URL) and each register list (municipality or district), so that the first one cannot use up the whole **Max results** budget. 0 = no per-search cap.

## `splitMap` (type: `boolean`):

Airbnb shows at most 270 listings (15 pages) per search. When a search is full, cut its map area into 4 smaller areas, again and again, to reach the listings beyond 270. Off = the first 270 of each search only.

## `cardsOnly` (type: `boolean`):

Deliver the card of each Airbnb search result - link, title, type of place, price, rating, position, bedrooms - without opening the listing: faster and cheaper, but no licence number, no verdict, nothing from the register. Charged per card (see Pricing), nothing else is charged in this mode. Needs a place, a map area or an Airbnb search URL. Not compatible with the options that read the listing (host profile, risk score, comparables, AI labels), with Airbnb listing URLs and IDs, Booking.com, licence numbers and register lists (municipalities, districts), nor with the filters on verdicts, regions, registered holder and holder phone.

## `checkIn` (type: `string`):

Travel dates of the search (`2027-07-12`). Airbnb then shows the listings free on those dates and their price for the stay; empty = Airbnb's own flexible dates. Today or later (the day in Portugal): Airbnb shows nothing for a stay that has begun.

## `checkOut` (type: `string`):

End of the stay (`2027-07-15`), after the check-in date.

## `adults` (type: `integer`):

Number of guests: only the listings that can host them. 0 = any.

## `children` (type: `integer`):

Children aged 2-12 travelling (Airbnb filter). 0 = none.

## `infants` (type: `integer`):

Infants under 2 travelling (Airbnb filter). 0 = none.

## `pets` (type: `integer`):

Pets travelling: only listings that allow pets. 0 = none.

## `currency` (type: `string`):

Currency of the prices shown on the search results.

## `priceMin` (type: `integer`):

Lowest price per night, in the currency above. 0 = no minimum.

## `priceMax` (type: `integer`):

Highest price per night, in the currency above. 0 = no maximum.

## `roomTypes` (type: `array`):

Only these kinds of place. Empty = all.

## `propertyTypes` (type: `array`):

Only these kinds of property (Airbnb filter). Empty = all.

## `minBedrooms` (type: `integer`):

Only listings with at least this many bedrooms. 0 = any.

## `minBeds` (type: `integer`):

Only listings with at least this many beds. 0 = any.

## `minBathrooms` (type: `integer`):

Only listings with at least this many bathrooms. 0 = any.

## `superhostOnly` (type: `boolean`):

Only listings of Superhosts (Airbnb filter).

## `bookingPropertyTypes` (type: `array`):

Booking.com searches: which kinds of property to list (hotels register elsewhere, not in the AL register). Empty = both.

## `registeredAfter` (type: `string`):

Only accommodations registered on this date or later (`2026-01-01`): the new operators of the area. Empty = all.

## `modalities` (type: `array`):

Only these kinds of accommodation, as registered. Empty = all.

## `onlyVerdicts` (type: `array`):

Save only the listings whose verdict is one of these — e.g. `never_issued`, `not_in_register`, `other_property`, `over_capacity`, `unknown_format` and `no_number` to get the suspicious listings only (the verdicts marked isSuspicious). Empty = every listing.

## `regions` (type: `array`):

Only listings located in these regions (a licence number or register record: the region of its registered address). Empty = all.

## `holderType` (type: `string`):

Only results whose registered holder is a private person (tax number starting 1, 2 or 3) or a company (5, 6, 9…), as the register gives it.

## `onlyWithPhone` (type: `boolean`):

Only results whose registered holder has a phone number in the register (about 1 holder in 3; every holder has an e-mail).

## `hostType` (type: `string`):

Only listings of business hosts (companies and professionals, who must show their business details) or of individual hosts, as Airbnb labels them on the search results (on the listing page for listing URLs and IDs).

## `minRating` (type: `number`):

Only listings rated at least this much out of 5 (listings without a rating are dropped). Airbnb listings only (Booking.com properties are not filtered by this). 0 = any.

## `excludeKeywords` (type: `array`):

Drop the listings whose title contains one of these words (case and accents ignored).

## `gpsToleranceKm` (type: `number`):

Airbnb blurs a listing's position by a few hundred metres. A registered property farther than this from the listing gives the verdict `other_property` (position from Turismo de Portugal's open data: mainland only; in Madeira only the island is compared).

## `includeHostProfile` (type: `boolean`):

Open the host's public profile (1 extra request per host, not per listing) for the number of listings they manage and their IDs. Charged per host profile (see Pricing).

## `includeRiskScore` (type: `boolean`):

Give each Airbnb listing and Booking.com property a risk score from 0 to 100 and the short codes of the rules behind it: the verdict first, then a number shown by several listings, a registered address far from the listing, a type of home that differs from the register's, a liability insurance ended or missing, and a host who manages several listings (needs **Host's listing count**). A rule whose data is not read is skipped and named, never counted as a risk. No extra request. Charged per listing whose row carries a score (see Pricing); a row whose register could not be read gets none and is not charged for it.

## `includeAiLabels` (type: `boolean`):

Label each Airbnb listing's description with four yes / no AI labels and their scores: managed by a company or a property manager, self check-in with a lockbox or a keypad, monthly or long stays (28 nights or more), mentions a licence or a permit. English descriptions only: a description in another language (Portuguese, Spanish, French…), a Booking.com property and a listing without a description get none and are not charged. The labels are read in the text of the description, they are indications, not facts. Needs 2 GB of memory (Run options → Memory): with less, the AI labels are skipped, said in the log, and nothing is charged. The descriptions are read one at a time, so a run with this option is slower. Charged per listing whose row carries its labels (see Pricing).

## `includeComparables` (type: `boolean`):

Add, to each Airbnb listing, the Airbnb listings around it: the nearest ones of the same type of place and within one bedroom of it (up to **Max comparables per listing**), each with its price per night, rating, bedrooms and distance, and the median price per night of them. Read from the cards of a search around the listing: no listing page is opened, and one search serves every listing of the same area, type of place and size. An entire home whose bedrooms are unknown gets none. Give **Check-in** and **Check-out** to get prices: without dates the comparables have no price and there is no median. Charged per listing whose row carries comparables (see Pricing).

## `maxComparablesPerListing` (type: `integer`):

Most comparable listings kept for each listing (**Comparable listings**): the nearest ones.

## `downloadPhotos` (type: `boolean`):

Download the first photos of each listing into this run's key-value store and give their public links, their SHA-256 and the time of the download: a dated copy of what the listing showed that day. The links in **Photos** (`images`) stay in every run for free. A photo that cannot be had (gone, too big, not an image) is left out and not charged. Charged per photo delivered (see Pricing). Not available with **Cards only (fast)**.

## `maxPhotosPerListing` (type: `integer`):

Photos downloaded for each listing (**Download photos**): the first ones of the listing.

## `includeBusinessContact` (type: `boolean`):

Ask Booking.com for the business e-mail and phone it shows for a professional host, on Booking.com properties: `businessEmail` and `businessPhone` of the row. Only professional hosts (traders under EU law) have them: a private host's contact is not given. The e-mail and phone of the professional block Airbnb shows stay in every Airbnb row for free, as before. Charged per Booking.com property whose row carries an e-mail or a phone (see Pricing). Not available with **Cards only (fast)**.

## `includeProHostContact` (type: `boolean`):

Add the business e-mail and phone of professional Airbnb hosts, from publicly available sources, with the page each comes from and a confidence: `proHostEmails`, `proHostPhones`, `proHostContactSourceUrl`, `proHostContactConfidence`. Only as a fallback: a listing whose professional block (Airbnb) or whose register record already gives an e-mail or a phone is not looked up. A host is looked up only when a company name is known (the business name Airbnb gives, or a host or co-host whose name is a company's), never a private person. Charged per listing whose row carries a contact (see Pricing); a listing with none is delivered as it is, not charged. Not available with **Cards only (fast)**.

## `onlyNew` (type: `boolean`):

Skip the listings (licence numbers, register records) that a previous run (same **Memory key**) already delivered: they are not saved and not charged, and their page is not even opened. First run = everything is new.

## `stateKey` (type: `string`):

Name of the memory used by **Only new listings**. Give each schedule / task its own key (e.g. `lisbon-weekly`) so that they do not share their memory. Letters, digits, `-` and `_`.

## `resetState` (type: `boolean`):

Forget everything remembered under this **Memory key** before the run: this run returns (and charges) every listing again. Untick it afterwards.

## `proxyConfiguration` (type: `object`):

Apify Proxy or your own proxies, for the Airbnb pages and the register. Keep the default: it is included in the price. The residential Apify proxy is not available in this Actor.

## `maxConcurrency` (type: `integer`):

Maximum number of Airbnb pages processed in parallel.

## `maxRequestsPerMinute` (type: `integer`):

Most requests to Airbnb in any 60 seconds, all of them counted: search pages, listing pages and host profiles. A budget, not an even pace: up to this many can leave at once when the minute starts (spread them with the minimum delay below). Lower it if Airbnb answers HTTP 429 / 403 in the log.

## `minRequestIntervalMs` (type: `integer`):

Smallest gap between two requests to Airbnb, in milliseconds. Unlike the per-minute rate, this spreads the requests evenly instead of letting them go out in a burst. 0 = no gap.

## `maxRequestRetries` (type: `integer`):

Retries per request before it is marked as failed. Behind a proxy, a request Airbnb turns away is also retried on a new proxy session up to 10 times without using up these retries.

## `debugLog` (type: `boolean`):

Include debug messages in the run log.

## Actor input object example

```json
{
  "sources": [
    "airbnb",
    "booking"
  ],
  "startUrls": [],
  "listingIds": [],
  "bookingUrls": [],
  "location": "Lisbon, Portugal",
  "locations": [],
  "boundingBoxes": [],
  "licenseNumbers": [],
  "municipalities": [],
  "districts": [],
  "maxItems": 100,
  "maxItemsPerQuery": 0,
  "splitMap": true,
  "cardsOnly": false,
  "adults": 0,
  "children": 0,
  "infants": 0,
  "pets": 0,
  "currency": "EUR",
  "priceMin": 0,
  "priceMax": 0,
  "roomTypes": [],
  "propertyTypes": [],
  "minBedrooms": 0,
  "minBeds": 0,
  "minBathrooms": 0,
  "superhostOnly": false,
  "bookingPropertyTypes": [
    "apartment",
    "holiday_home"
  ],
  "modalities": [],
  "onlyVerdicts": [],
  "regions": [],
  "holderType": "any",
  "onlyWithPhone": false,
  "hostType": "any",
  "minRating": 0,
  "excludeKeywords": [],
  "gpsToleranceKm": 1.5,
  "includeHostProfile": false,
  "includeRiskScore": false,
  "includeAiLabels": false,
  "includeComparables": false,
  "maxComparablesPerListing": 10,
  "downloadPhotos": false,
  "maxPhotosPerListing": 5,
  "includeBusinessContact": false,
  "includeProHostContact": false,
  "onlyNew": false,
  "stateKey": "default",
  "resetState": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "maxConcurrency": 8,
  "maxRequestsPerMinute": 120,
  "minRequestIntervalMs": 0,
  "maxRequestRetries": 5,
  "debugLog": false
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "sources": [
        "airbnb",
        "booking"
    ],
    "location": "Lisbon, Portugal",
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("nice_dev/airbnb-portugal-license-checker").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "sources": [
        "airbnb",
        "booking",
    ],
    "location": "Lisbon, Portugal",
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("nice_dev/airbnb-portugal-license-checker").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "sources": [
    "airbnb",
    "booking"
  ],
  "location": "Lisbon, Portugal",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call nice_dev/airbnb-portugal-license-checker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nice_dev/airbnb-portugal-license-checker"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/loufuu3OXxI7dMbtI/builds/XsFffQtSgeWLap9zt/openapi.json
