Localranker API
Welcome to the Localranker API. You can use our API to access all available endpoints for managing locations, reviews, publications, and statistics.
The API is organized around REST. All requests should be made over SSL. All request and response bodies, including errors, are encoded in JSON.
Base URL
All endpoints documented below are relative to this base URL.
Authentication
Authenticate your API requests by including your API key in the
x-api-key header of every request.
Your API key carries privileges — keep it secret. Do not share it in publicly accessible areas such as GitHub or client-side code.
Header
| Header | Value |
|---|---|
x-api-key |
Your secret API key (e.g. sk_live_...) |
All authenticated endpoints will return
401 Unauthorized if the key is
missing or invalid.
// Include in every request headers: { "x-api-key": "sk_live_your_api_key" }
Rate Limiting
The API enforces rate limits to ensure fair usage and availability for all users.
| Limit | Details |
|---|---|
| IP Rate Limit | 100 requests per minute per IP address |
| API Credits |
Each request consumes 1 API credit. When credits are
exhausted, the API returns 429 Too Many Requests.
|
Errors
The API uses conventional HTTP status codes to indicate the success or failure of a request.
| Code | Meaning | Description |
|---|---|---|
200 |
OK | The request succeeded. |
201 |
Created | A new resource was created successfully. |
400 |
Bad Request |
The request was invalid. Check the errors array
in the response for details.
|
401 |
Unauthorized | The API key is missing or invalid. |
403 |
Forbidden | Access denied. Your IP may have been temporarily blocked. |
429 |
Too Many Requests | You have exceeded the rate limit or your API credits are exhausted. |
500 |
Server Error | Something went wrong on our end. Please try again later. |
{
"errors": [
{
"type": "field",
"msg": "locationId must be a positive integer",
"path": "locationId",
"location": "query"
}
]
}
{
"error": "Unauthorized"
}
{
"status": 429,
"error": "Too many requests from this IP. Max: 100/min - Please try again after 1 minute."
}
Locations
List locations
Returns a paginated list of all locations (placeID, locationID, name, address) from your account. Results are paginated by 100.
As long as nextPage is present in
the response, more pages are available. Once it disappears, you have
reached the end.
Query Parameters
| Param | Type | Required | Description |
|---|---|---|---|
page |
integer | optional | Page number (1-999). Defaults to 1. |
const response = await fetch("https://developers.localranker.fr/v1/locations?page=1", { headers: { "x-api-key": "sk_live_your_api_key" } }); const data = await response.json();
{
"locations": [
{
"placeID": "ChIJh5ixZOZz5kcRtmuVD2mF07w",
"locationID": 102,
"locationName": "Localranker",
"locationAddress": "15 Rue des Halles, Paris, 75001"
}
],
"nextPage": "https://developers.localranker.fr/v1/locations?page=2",
"totalItems": 150,
"totalPages": 2
}
Opening hours
Returns opening hours for a location. Mirrors Google Business Profile Opening Hours combined with GBP Special Hours.
Only open days are returned. Closed days are omitted. If the response is empty, we do not have hours in our systems for this location.
Query Parameters
| Param | Type | Required | Description |
|---|---|---|---|
locationId |
integer | required | Location ID |
const response = await fetch("https://developers.localranker.fr/v1/locations/opening-hours?locationId=102", { headers: { "x-api-key": "sk_live_your_api_key" } }); const data = await response.json();
{
"locationId": 102,
"hours": [
{
"openDay": "MONDAY",
"openTime": { "hours": 9 },
"closeDay": "MONDAY",
"closeTime": { "hours": 18 }
},
{
"openDay": "TUESDAY",
"openTime": { "hours": 9 },
"closeDay": "TUESDAY",
"closeTime": { "hours": 18 }
}
]
}
Get location
Returns detailed information about a single location including title, opening hours, categories, services, address, and more.
Query Parameters
| Param | Type | Required | Description |
|---|---|---|---|
locationId |
integer | optional* | Location ID |
placeId |
string | optional* | Google Place ID |
locationId or placeId must be
provided, but not both.
const response = await fetch("https://developers.localranker.fr/v1/locations/location?placeId=ChIJh5ixZOZz5kcRtmuVD2mF07w", { headers: { "x-api-key": "sk_live_your_api_key" } }); const data = await response.json();
{
"title": "Localranker",
"languageCode": "fr",
"phoneNumbers": {},
"categories": {
"primaryCategory": {
"name": "categories/gcid:internet_marketing_service",
"displayName": "Service de marketing Internet"
}
},
"storefrontAddress": {
"addressLines": ["15 Rue des Halles"],
"locality": "Paris",
"postalCode": "75001",
"regionCode": "FR"
},
"websiteUri": "https://localranker.fr",
"regularHours": { /* ... */ },
"profile": {
"description": "LocalRanker est une plateforme..."
}
}
Create location
Creates a new location on Google Business Profile. Only approved accounts can use this endpoint.
The location object should mirror
Google's location API format.
Body Parameters
| Param | Type | Required | Description |
|---|---|---|---|
gbpAccountId |
string | required | Google account ID (ask your account manager) |
location |
object | required | Location data (title, categories, storefrontAddress, etc.) |
isGoogle |
boolean | required | Create on Google Business Profile |
isTestingMode |
boolean | required | If true, validates format only without creating. Does not consume credits. |
isTestingMode: true first to validate your request
format before creating a real location.
const response = await fetch("https://developers.localranker.fr/v1/locations/location", { method: "POST", headers: { "x-api-key": "sk_live_your_api_key", "Content-Type": "application/json" }, body: JSON.stringify({ isGoogle: true, isTestingMode: true, gbpAccountId: "123456789", location: { title: "My New Location", storefrontAddress: { addressLines: ["12 rue de la paix"], locality: "Paris", postalCode: "75001", regionCode: "FR" }, categories: { primaryCategory: { name: "categories/gcid:internet_marketing_service" } } } }) });
{
"success": true,
"data": {
"message": "TEST MODE - Location created successfully",
"requestId": "d08c141b-15d3-44ad-...",
"gbpAccountId": "123456789"
}
}
Upload media
Uploads photos to a location on Google Business Profile. Supports 1 to 5 photos per request.
Body Parameters
| Param | Type | Required | Description |
|---|---|---|---|
locationId |
integer | optional* | Location ID |
placeId |
string | optional* | Google Place ID |
photos |
array | required |
Array of 1-5 photo objects with url and optional
category
|
isTestingMode |
boolean | optional | If true, validates without uploading |
COVER, PROFILE,
LOGO, EXTERIOR, INTERIOR,
PRODUCT, AT_WORK,
FOOD_AND_DRINK, MENU,
COMMON_AREA, ROOMS, TEAMS,
ADDITIONAL
const response = await fetch("https://developers.localranker.fr/v1/locations/media", { method: "POST", headers: { "x-api-key": "sk_live_your_api_key", "Content-Type": "application/json" }, body: JSON.stringify({ locationId: 102, photos: [ { url: "https://example.com/photo1.jpg", category: "EXTERIOR" }, { url: "https://example.com/photo2.jpg", category: "INTERIOR" } ] }) });
{
"success": true,
"message": "All photos uploaded successfully",
"results": [
{ "url": "https://example.com/photo1.jpg", "status": "success" },
{ "url": "https://example.com/photo2.jpg", "status": "success" }
]
}
Update location
Updates an existing location on Google Business Profile. Pass only
the fields you want to update. Either
location or
attributes (or both) must be
provided.
Body Parameters
| Param | Type | Required | Description |
|---|---|---|---|
locationId |
integer | optional* | Location ID |
placeId |
string | optional* | Google Place ID |
location |
object | optional** | Location fields to update (mirrors GBP format) |
attributes |
object | optional** | Attributes to update (e.g. social links) |
isTestingMode |
boolean | required | If true, validates format only without applying changes. Does not consume credits. |
locationId or placeId must be
provided, but not both.** At least one of
location or attributes must be provided.
Allowed location fields
| Field | Type | Description |
|---|---|---|
title |
string | Business name |
storeCode |
string | External store code identifier |
phoneNumbers |
object |
primaryPhone (string) and
additionalPhones (array, max 2)
|
categories |
object |
primaryCategory and optional
additionalCategories array
|
storefrontAddress |
object |
Address with regionCode,
addressLines, locality,
postalCode, etc.
|
regularHours |
object | Regular opening hours (periods array) |
specialHours |
object |
Special / exceptional hours (specialHourPeriods
array)
|
openInfo |
object |
Open status (OPEN,
CLOSED_TEMPORARILY,
CLOSED_PERMANENTLY), canReopen,
openingDate
|
latlng |
object |
latitude and longitude (numbers)
|
websiteUri |
string |
Website URL (must start with http:// or
https://)
|
profile |
object | Business description (max 700 characters) |
serviceItems |
array | Service items with optional pricing and structured or free-form definitions |
latlng is required when updating
storefrontAddress to prevent PIN_DROP_REQUIRED errors
from Google. Always include both fields together.
Allowed attributes fields
| Field | Type | Description |
|---|---|---|
socials |
array |
Array of { type, url } objects. Valid types:
url_facebook, url_instagram,
url_tiktok, url_youtube,
url_linkedin, url_pinterest,
url_twitter, url_whatsapp,
url_appointment
|
const response = await fetch("https://developers.localranker.fr/v1/locations/location", { method: "PUT", headers: { "x-api-key": "sk_live_your_api_key", "Content-Type": "application/json" }, body: JSON.stringify({ locationId: 102, isTestingMode: false, location: { title: "Updated Location Name", websiteUri: "https://newwebsite.fr" } }) });
const response = await fetch("https://developers.localranker.fr/v1/locations/location", { method: "PUT", headers: { "x-api-key": "sk_live_your_api_key", "Content-Type": "application/json" }, body: JSON.stringify({ locationId: 102, isTestingMode: true, location: { storefrontAddress: { regionCode: "FR", addressLines: ["20 rue de Rivoli"], locality: "Paris", postalCode: "75004" }, latlng: { latitude: 48.8566, longitude: 2.3522 } } }) });
const response = await fetch("https://developers.localranker.fr/v1/locations/location", { method: "PUT", headers: { "x-api-key": "sk_live_your_api_key", "Content-Type": "application/json" }, body: JSON.stringify({ locationId: 102, isTestingMode: false, attributes: { socials: [ { type: "url_instagram", url: "https://instagram.com/mybusiness" }, { type: "url_facebook", url: "https://facebook.com/mybusiness" } ] } }) });
{
"message": "Request received and is processing",
"requestId": 42
}
Publications
Get publications
Returns the last 10 Google Posts for a given location.
Query Parameters
| Param | Type | Required | Description |
|---|---|---|---|
locationId |
integer | required | Location ID |
const response = await fetch("https://developers.localranker.fr/v1/publications?locationId=102", { headers: { "x-api-key": "sk_live_your_api_key" } }); const data = await response.json();
{
"posts": [
{
"title": "New blog post about local SEO",
"content": "Discover our latest tips...",
"imageUrl": "https://...",
"publishedAt": "2025-03-01T10:00:00.000Z"
}
],
"totalPostsReturned": 1
}
Statistics
Get statistics
Returns review and performance statistics for your locations over a date range, including review counts, average ratings, response rates, and interval breakdowns.
Query Parameters
| Param | Type | Required | Description |
|---|---|---|---|
locationsIds |
string | required |
"all" or comma-separated location IDs (e.g.
"102,132")
|
startDate |
string | required | Start date in YYYY-MM-DD format |
endDate |
string | required | End date in YYYY-MM-DD format |
interval |
string | required |
One of: day, week,
month, year
|
const url = "https://developers.localranker.fr/v1/stats" + "?locationsIds=all&startDate=2025-01-01&endDate=2025-03-01&interval=month"; const response = await fetch(url, { headers: { "x-api-key": "sk_live_your_api_key" } }); const data = await response.json();
{
"reviews": {
"reviews_count": 87,
"nbReplied": 72,
"responseRate": 83,
"averageRate": 4.52
},
"report": { /* GBP performance stats */ }
}
Reviews
Get reviews
Returns a paginated list of reviews with powerful filtering options. Supports Google, Facebook, and Trustpilot reviews.
If neither locationId nor
placeId is provided, returns
reviews for all locations in your account.
Ideal for building custom review widgets, exporting review data, or integrating reviews into your own applications.
Query Parameters
| Param | Type | Required | Description |
|---|---|---|---|
locationId |
integer | optional | Filter by location ID |
placeId |
string | optional | Filter by Google Place ID |
page |
integer | optional | Page number. Default: 1 |
limit |
integer | optional | Results per page (1-100). Default: 20 |
platform |
string | optional |
Filter by platform: google,
facebook, trustpilot, or
all. Default: all
|
startDate |
string | optional | Filter reviews from this date (YYYY-MM-DD) |
endDate |
string | optional | Filter reviews until this date (YYYY-MM-DD) |
minRating |
integer | optional | Minimum rating (1-5) |
maxRating |
integer | optional | Maximum rating (1-5) |
sortBy |
string | optional |
Sort field: review_date or rating.
Default: review_date
|
sortOrder |
string | optional |
Sort direction: asc or desc.
Default: desc
|
includeAnswer |
boolean | optional | Include owner reply fields. Default: true |
hasAnswer |
boolean | optional |
Filter: only answered (true) or unanswered
(false) reviews
|
page × limit must not exceed 10,000.
const response = await fetch("https://developers.localranker.fr/v1/reviews?locationId=102&limit=20", { headers: { "x-api-key": "sk_live_your_api_key" } }); const data = await response.json();
const url = "https://developers.localranker.fr/v1/reviews" + "?platform=google&minRating=4&startDate=2025-01-01&endDate=2025-12-31" + "&sortBy=rating&sortOrder=desc&includeAnswer=false"; const response = await fetch(url, { headers: { "x-api-key": "sk_live_your_api_key" } });
{
"reviews": [
{
"reviewId": "AbCdEf123...",
"platform": "google",
"author": "Jean Dupont",
"authorPhoto": "https://lh3.googleusercontent.com/...",
"rating": 5,
"content": "Excellent service, highly recommended!",
"reviewDate": "2025-06-15T00:00:00.000Z",
"mediaUrls": [],
"locationName": "Localranker",
"locationAddress": "15 Rue des Halles, Paris, 75001",
"placeId": "ChIJh5ixZOZz5kcRtmuVD2mF07w",
"locationId": 102,
"ownerAnswer": "Merci beaucoup Jean!",
"ownerAnswerDate": "2025-06-16T00:00:00.000Z"
}
],
"pagination": {
"page": 1,
"limit": 20,
"totalItems": 150,
"totalPages": 8,
"nextPage": "https://developers.localranker.fr/v1/reviews?page=2&limit=20"
}
}