Skip to content

Listing Info API

A listing's current details, read live from the platform#

Send a platform and a listing's slug or URL; Zembra reads the listing on the platform at the moment you call and returns its name, address, phone, website, categories, photos, rating, review counts, opening hours and rating breakdown in one standardized format. The answer comes back in the same response, with no job to create and nothing to poll.

  • AccessAPI key
  • Platforms133 supported
  • Endpoint GET /listing/{network} POST /batch/listing/details
  • CommitmentNone: pay per use, no minimum

At a glance

  • One GET, answered in the same response
  • Read live from the platform on every call
  • Opening hours and rating breakdown where the platform shows them
  • Pick only the fields you need with fields[]
  • 50 credits per listing; errors are free

Why teams choose Zembra for this#

Performance

Synchronous: the listing is read and returned in the same call. Up to 1,000 listings can also be sent in a single batch.

Freshness

Every call re-reads the listing on the platform. lastUpdated tells you exactly when the details were read.

Completeness

Name, address, phone, website, categories, price range, photos, profile image, global rating, review counts, opening hours and rating breakdown, plus everything else the platform shows in rawData.

Quality

One schema on every platform. Address split into street, city, region, postal code and country, plus a one-line formattedAddress.

Stable identity

When a platform changes a listing's slug, the old ones are kept as aliases and resolve to the same listing.

Fair pricing

50 credits per listing. Invalid requests, disabled platforms and platform outages cost nothing; a listing that doesn't exist costs 25.

How it works

From request to data#

  1. 1

    Send the listing

    GET /listing/{network}?slug=… with the listing's identifier, its URL or part of it. Don't have it? Find it with the Listing Lookup API.

  2. 2

    Zembra resolves it

    The slug is normalized and matched against the listings Zembra already knows, including their old slugs (aliases).

  3. 3

    The platform is read live

    Zembra reads the listing on the platform now, stores the fresh details and, with permalink, hosts permanent copies of its images.

  4. 4

    One standardized response

    The listing comes back in the same response, in the same format whatever the platform, with the credits charged and your remaining balance.

Pricing

Pay per use, no commitment#

Pay per listing, no subscription and no minimum. Credits get cheaper as your volume grows: how credit pricing works.

What a call costs#

CallCreditsStarts at
Each listing
Charged when the listing is returned.
50 $0.01
With permalink
Added to the 50 credits: permanent copies of the images.
25 $0.005
Listing not found (404)
The listing doesn't exist on the platform.
25 $0.005
Errors
Invalid parameters, platforms not enabled, rate limits and platform outages are never charged.
0 Free
Reading a batch's status and results
GET /batch/… is free.
0 Free

Examples#

ProjectCreditsPrice
1 listing 50 Free on sign-up
1,000 listings refreshed once a month 50,000 $52.00
1,000 listings with permanent images 75,000 $72.00

Prices use the credit tiers of the cost estimator, where you can estimate your own project. The first 10,000 credits are free.

API reference

Requests and parameters#

Base URL https://api.zembra.io, authenticated with Authorization: Bearer <token>. A sandbox at https://sandbox.zembra.io returns realistic dummy data without using credits.

GET /listing/{network}?slug=my-listing-slug
cURL
  • cURL
  • .Net
  • Go
  • Java
  • Node.js
  • PHP
  • Python
  • Ruby
curl --location 'https://api.zembra.io/listing/google?slug=my-listing-slug' \
--header 'Authorization: Bearer {token}'
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://api.zembra.io/listing/google?slug=my-listing-slug");
request.Headers.Add("Authorization", "Bearer {token}");
var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
Console.WriteLine(await response.Content.ReadAsStringAsync());
package main

import (
  "fmt"
  "net/http"
  "io/ioutil"
)

func main() {

  url := "https://api.zembra.io/listing/google?slug=my-listing-slug"
  method := "GET"

  client := &http.Client {
  }
  req, err := http.NewRequest(method, url, nil)

  if err != nil {
    fmt.Println(err)
    return
  }
  req.Header.Add("Authorization", "Bearer {token}")

  res, err := client.Do(req)
  if err != nil {
    fmt.Println(err)
    return
  }
  defer res.Body.Close()

  body, err := ioutil.ReadAll(res.Body)
  if err != nil {
    fmt.Println(err)
    return
  }
  fmt.Println(string(body))
}
OkHttpClient client = new OkHttpClient().newBuilder()
  .build();
MediaType mediaType = MediaType.parse("text/plain");
RequestBody body = RequestBody.create(mediaType, "");
Request request = new Request.Builder()
  .url("https://api.zembra.io/listing/google?slug=my-listing-slug")
  .method("GET", body)
  .addHeader("Authorization", "Bearer {token}")
  .build();
Response response = client.newCall(request).execute();
var myHeaders = new Headers();
myHeaders.append("Authorization", "Bearer {token}");

var requestOptions = {
  method: 'GET',
  headers: myHeaders,
  redirect: 'follow'
};

fetch("https://api.zembra.io/listing/google?slug=my-listing-slug", requestOptions)
  .then(response => response.text())
  .then(result => console.log(result))
  .catch(error => console.log('error', error));
<?php
$client = new Client();
$headers = [
  'Authorization' => 'Bearer {token}'
];
$request = new Request('GET', 'https://api.zembra.io/listing/google?slug=my-listing-slug', $headers);
$res = $client->sendAsync($request)->wait();
echo $res->getBody();
import requests

url = "https://api.zembra.io/listing/google?slug=my-listing-slug"

payload = {}
headers = {
  'Authorization': 'Bearer {token}'
}

response = requests.request("GET", url, headers=headers, data=payload)

print(response.text)
require "uri"
require "net/http"

url = URI("https://api.zembra.io/listing/google?slug=my-listing-slug")

https = Net::HTTP.new(url.host, url.port)
https.use_ssl = true

request = Net::HTTP::Get.new(url)
request["Authorization"] = "Bearer {token}"

response = https.request(request)
puts response.read_body

Response

{
    "message": "Listing found on Google",
    "data": {
        "address": {
            "street": "5621 Main St",
            "city": "Mallorca",
            "region": "QC",
            "postalCode": "78128",
            "country": "US"
        },
        "aliases": [
            "my-listing-1",
            "my-first-listing"
        ],
        "categories": [
            "Restaurant",
            "Fast Food"
        ],
        "formattedAddress": "5621 Main St, Mallorca, QC 78128, US",
        "globalRating": 4.5,
        "id": "ChIJV9OJxsOq3oARnyGzSXY0ym8",
        "lastCrawled": "2023-01-01T00:00:00Z",
        "lastUpdated": "2023-01-01T00:00:00Z",
        "link": "https://my.zembratech.com/dashboard/review-page/insights/MWJmZTc5MDZjMzg5OGI3OGMyNjJiODNjOGJjMWI3Y2Q",
        "name": "My Google Business",
        "network": "google",
        "phone": "(210) 456-0987",
        "photos": [
            "https://media2.trover.com/T/5a5eae0184b8636d6b0385f0/fixedw-1.jpg",
            "https://media2.trover.com/T/5a5eae0184b8636d6b0385f0/fixedw-2.jpg"
        ],
        "priceRange": "$$$",
        "profileImage": "https://media2.trover.com/T/5a5eae0184b8636d6b0385f0/fixedw.jpg",
        "ratingBreakdown": {
            "overall": 8.4,
            "perCriteria": [
                {
                    "criteria": "Overall",
                    "rating": 8.4
                },
                {
                    "criteria": "Cleanliness",
                    "rating": 8.9
                },
                {
                    "criteria": "Facilities",
                    "rating": 8.3
                },
                {
                    "criteria": "Location",
                    "rating": 8.7
                },
                {
                    "criteria": "Service",
                    "rating": 8.7
                },
                {
                    "criteria": "Value for money",
                    "rating": 8.2
                }
            ],
            "ratingDistribution": [
                {
                    "rating": "9+ Exceptional",
                    "count": 135
                },
                {
                    "rating": "8-9 Excellent",
                    "count": 66
                },
                {
                    "rating": "7-8 Very Good",
                    "count": 32
                },
                {
                    "rating": "6-7 Good",
                    "count": 24
                },
                {
                    "rating": "<6 Below Expectation",
                    "count": 11
                }
            ]
        },
        "rawData": [],
        "reviewCount": {
            "native": {
                "total": 6320,
                "active": 5986,
                "hidden": 334
            },
            "available": {
                "total": 6320,
                "active": 5986,
                "hidden": 334
            }
        },
        "slug": "my-listing-slug",
        "url": "https://maps.google.com/?cid=16256511492469774330",
        "website": "https://my-business.com"
    }
}
{
    "message": "Invalid slug [not-a-real-listing-slug]"
}
{
    "message": "Invalid bearer token"
}
{
    "message": "Cannot process request: balance too low!"
}
{
    "message": "Requested network [Facebook] is not enabled for your account"
}
{
    "message": "Listing not found. Maybe not a valid business."
}

GET /listing/{network}: Get a listing's details#

networkstring, required, in the path
The platform, e.g. google, yelp, booking. It must be enabled on your account.
slugstring, required, 3–1024 characters
The listing: its identifier, its URL, or part of it.
fields[]array of field names, optional
Return only these fields. Default: every field, including rawData and businessHours.
includeRawDataboolean, optional
Adds rawData when you pick fields with fields[].

POST /batch/listing/details: Send up to 1,000 listings in one batch#

bodyJSON array, 1–1,000 objects
Each object holds a network and a slug (3–1024 characters). The call returns a batchId.
GET /batch/{batchId}free
The batch's progress.
GET /batch/{batchId}/{requestIndex}free
The result of one request of the batch, by its position starting at 1.

Status codes#

200Listing returned
400Invalid parameter, slug or field name
401Missing or invalid token
402Balance too low
403Platform not enabled on your account
404The listing doesn't exist on the platform (25 credits)
429Rate limit reached
503Platform temporarily unavailable, not charged

Data

What you get back#

A listing#

id, slug, url, networkstring
The listing's ID on the platform, its slug, its public URL and the platform.
namestring
The business name as shown on the platform.
addressobject
street, city, region, postalCode, country.
formattedAddressstring
The address on one line.
phone, websitestring
Contact details, when the platform shows them.
categoriesarray of strings
The platform's categories for the business.
priceRangestring
Price level, e.g. $$, when the platform shows one.
globalRatingnumber
The overall rating shown on the platform.
reviewCountobject
native.total, native.active and native.hidden: the review counts on the platform.
ratingBreakdownobject
Where the platform provides it: the overall score, ratings per criteria (cleanliness, location…) and the distribution of ratings. The structure follows what each platform shows.
businessHoursobject
Opening hours for the next 7 days, keyed by weekday, each with a date and a list of intervals like 09:00-17:00. Empty on platforms that don't show hours.
photos, profileImagearray of URLs, URL
The listing's photos and main image.
aliasesarray of strings
Earlier slugs of the same listing.
lastUpdateddatetime, UTC
When the details were last read from the platform.
lastCrawleddatetime, UTC
When the listing's reviews were last collected, or null if never.
linkURL
The listing's page in your Zembra dashboard.
rawDataobject
Everything else the platform shows, exactly as it shows it.
Example response
{
    "status": "SUCCESS",
    "message": "Listing found on Booking",
    "data": {
        "address": {
            "street": "1250 Harbor Dr",
            "city": "San Diego",
            "region": "CA",
            "postalCode": "92101",
            "country": "US"
        },
        "aliases": [
            "hotel/us/grand-harbor-san-diego"
        ],
        "businessHours": [],
        "categories": [
            "Hotel"
        ],
        "formattedAddress": "1250 Harbor Dr, San Diego, CA 92101, US",
        "globalRating": 4.3,
        "id": "4815162",
        "lastCrawled": "2026-10-30 06:12:41",
        "lastUpdated": "2026-11-01 09:30:05",
        "link": "https://my.zembratech.com/dashboard/review-page/insights/MWJmZTc5MDZjMzg5OGI3OGMyNjJiODNjOGJjMWI3Y2Q",
        "name": "The Grand Harbor Hotel",
        "network": "booking",
        "phone": null,
        "photos": [
            "https://cf.bstatic.com/xdata/images/hotel/max1024x768/111.jpg",
            "https://cf.bstatic.com/xdata/images/hotel/max1024x768/222.jpg"
        ],
        "priceRange": null,
        "profileImage": "https://cf.bstatic.com/xdata/images/hotel/max1024x768/111.jpg",
        "ratingBreakdown": {
            "overall": 8.6,
            "perCriteria": [
                {
                    "criteria": "Staff",
                    "rating": 9.1
                },
                {
                    "criteria": "Cleanliness",
                    "rating": 8.8
                },
                {
                    "criteria": "Location",
                    "rating": 9.3
                },
                {
                    "criteria": "Value for money",
                    "rating": 7.9
                }
            ]
        },
        "rawData": {
            "…": "everything else the platform shows"
        },
        "reviewCount": {
            "native": {
                "total": 2140,
                "active": 2140,
                "hidden": 0
            }
        },
        "slug": "hotel/us/the-grand-harbor-san-diego",
        "url": "https://www.booking.com/hotel/us/the-grand-harbor-san-diego.html",
        "website": null
    },
    "cost": 50,
    "balance": 98950
}

Read live on every call#

Each call re-reads the listing on the platform, even when Zembra already knows it. If the platform can't be reached at that moment, a listing Zembra already knows is returned as last read: compare lastUpdated with the time of your call.

Slugs, URLs and aliases#

Send the listing's ID, its URL or part of it: Zembra normalizes it for the platform. When a platform changes a listing's slug, the old one is kept in aliases and still resolves to the same listing.

Choose your fields#

Without fields[] you get every field, rawData and businessHours included. Pass fields[] to get only what you need; an unknown field name returns 400. Choosing fields doesn't change the price.

Rating breakdown and opening hours#

Where the platform shows them, ratingBreakdown carries per-criteria ratings and the distribution of ratings, and businessHours the opening hours of the next 7 days. Their content follows each platform; on platforms that don't show them they're empty.

Platform image links can expire. With permalink=true, Zembra stores copies of the profile image and photos and returns links that keep working, for 25 extra credits.

Platform name variants#

Older platform name spellings, such as apartmentguide or apt-guide, are accepted and mapped to the current name; the response then carries a warning and an X-Zembra-Deprecated header telling you the name to use.

Listing Info vs Listing Lookup#

Listing Lookup finds listings from a name and an address and returns the details shown in the platform's search results. Listing Info returns the full, freshly read details of one listing you already identified.

Performance

Speed and limits#

Rate limit #

100 requests per minute by default, counted per account and per service. Beyond that you get 429 with X-RateLimit-* headers.

Batches #

Up to 1,000 listings per batch, one batch submission per minute.

Slug length #

3 to 1024 characters.

Platform access #

The platform must be enabled on your account.

Supported platforms

133 platforms, one format#

Use cases

What teams build with it#

Listing management

Check that names, addresses, phone numbers and hours are consistent across platforms.

Data enrichment

Add ratings, review counts, photos and categories to your CRM or directory.

Rating widgets

Display a business's up-to-date rating and review count from each platform.

Competitive benchmarks

Compare ratings and rating breakdowns of competing businesses, platform by platform.

FAQ

Common questions#

Is the data live?

Yes. Every call reads the listing on the platform at that moment. lastUpdated shows when the details were read. #

Which fields are returned?

Name, address, formatted address, phone, website, categories, price range, photos, profile image, global rating, review counts, rating breakdown, opening hours, aliases, URL and rawData, where the platform shows them. #

Can I pass a URL instead of a slug?

Yes. The slug parameter accepts the listing's identifier, its URL or part of it. #

What if the listing doesn't exist?

You get 404 and are charged 25 credits instead of 50. #

Am I charged for errors?

No. Invalid requests, platforms not enabled on your account and platform outages cost nothing. #

Can I send many listings at once?

Yes. POST /batch/listing/details takes up to 1,000 listings; read the results for free with GET /batch/{batchId}. #

Can I test without spending credits?

Yes. The sandbox at https://sandbox.zembra.io returns realistic dummy listings and never touches your balance. #

Start today for free

Create an account and get 10,000 free credits to try the Listing Info API and every other Zembra service. No commitment, no minimum.