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

https://developers.localranker.fr

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.

Example header
// 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.
Cached responses also consume 1 credit. Contact your account manager to increase your credit limit.

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.
Validation error — 400
{
  "errors": [
    {
      "type": "field",
      "msg": "locationId must be a positive integer",
      "path": "locationId",
      "location": "query"
    }
  ]
}
Authentication error — 401
{
  "error": "Unauthorized"
}
Rate limit error — 429
{
  "status": 429,
  "error": "Too many requests from this IP. Max: 100/min - Please try again after 1 minute."
}

Locations

List locations

GET /v1/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.
Request
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();
Response — 200 OK
{
  "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

GET /v1/locations/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
Request
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();
Response — 200 OK
{
  "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

GET /v1/locations/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
Either locationId or placeId must be provided, but not both.
Request
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();
Response — 200 OK
{
  "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

POST /v1/locations/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.
Set isTestingMode: true first to validate your request format before creating a real location.
Rate limit: max 10 location creations per day per API key.
Request
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"
        }
      }
    }
  })
});
Response — 201 Created
{
  "success": true,
  "data": {
    "message": "TEST MODE - Location created successfully",
    "requestId": "d08c141b-15d3-44ad-...",
    "gbpAccountId": "123456789"
  }
}

Upload media

POST /v1/locations/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
Valid categories: COVER, PROFILE, LOGO, EXTERIOR, INTERIOR, PRODUCT, AT_WORK, FOOD_AND_DRINK, MENU, COMMON_AREA, ROOMS, TEAMS, ADDITIONAL
Request
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" }
    ]
  })
});
Response — 200 OK
{
  "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

PUT /v1/locations/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.
* Either 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
Rate limit: max 500 updates per hour per API key.
Request — Update basic fields
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"
    }
  })
});
Request — Update address (requires latlng)
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
      }
    }
  })
});
Request — Update social links
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" }
      ]
    }
  })
});
Response — 200 OK
{
  "message": "Request received and is processing",
  "requestId": 42
}

Publications

Get publications

GET /v1/publications

Returns the last 10 Google Posts for a given location.

Query Parameters

Param Type Required Description
locationId integer required Location ID
Request
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();
Response — 200 OK
{
  "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

GET /v1/stats

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
Request
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();
Response — 200 OK
{
  "reviews": {
    "reviews_count": 87,
    "nbReplied": 72,
    "responseRate": 83,
    "averageRate": 4.52
  },
  "report": { /* GBP performance stats */ }
}

Reviews

Get reviews

GET /v1/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.

Best practice: If you are building a custom widget or any integration that repeatedly fetches the same data, implement a caching layer on your side (e.g. cache responses for a few minutes or hours). This prevents unnecessary API calls and helps you preserve your API credits.

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.
Request — All reviews for a location
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();
Request — Filtered (4-5 stars, Google only, 2025)
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" }
});
Response — 200 OK
{
  "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"
  }
}