Developer Guide
API Reference ↗ Website ↗

Advice Local API

The Warpath API gives agencies and brands programmatic control over local listing management, reputation, AI presence, and reporting — across 3.7 million+ managed locations.

v5.46 API Version
REST Architecture
JSON Response Format
HTTPS Transport

Overview

The Advice Local API — internally named Warpath — is the programmatic backbone of the entire platform. Through it, you can create and manage business locations, activate products, push rich data to hundreds of directories, and pull the reporting metrics your clients care about. Everything that happens in the Advice Local dashboard can also be driven entirely through API calls, making it straightforward to embed local listing management into your own portals, CRMs, or automated workflows.

The API is RESTful: resources are nouns, HTTP verbs express intent, and every response comes back as JSON. There is one base URL for all operations:

https://p.lssdev.com

Regardless of whether a request succeeds or fails, the response always follows the same predictable envelope. This means your error-handling logic can be written once and reused across every endpoint — check success first, then branch on data or error.

statusHTTP status code (integer) — mirrors the HTTP response code
successBoolean — true on success, false on any error
errorString error message, or null on success
dataThe response payload — object, array, or null
totalTotal record count (present on list endpoints)

Authentication

Every request to the Warpath API must include your API key. Authentication is intentionally simple: there are no OAuth flows, no token exchanges, no sessions to manage. You place your key in a single custom header called x-api-token, and the API grants access scoped to your partner account. All clients, orders, and data belonging to your account are accessible using this single credential.

Your API key is issued when your partner account is set up. If you need to locate it, log in to the Advice Local dashboard and navigate to your account settings. Treat it like a password — if it is ever compromised, contact Advice Local support to have it rotated immediately.

HeaderValueRequired
x-api-tokenYour secret API keyRequired
Content-Typeapplication/json (or application/x-www-form-urlencoded for form posts)Required

Keep your API key secret. It provides full partner-level access to all clients, orders, and billing data.

Example

GET /legacyclients/3201926 HTTP/1.1
Host:         p.lssdev.com
x-api-token:  YOUR_API_KEY
Content-Type: application/json

Errors & Responses

The Warpath API uses standard HTTP status codes, and every response — including errors — wraps its payload in the same envelope described above. When something goes wrong, the success field will be false and the error field will contain a plain-language description of what happened. The data field will be null. This consistent shape means you never need to guess whether an empty body or a 2xx status with a failure message is possible — if the request failed, success is always false.

The most common errors to handle are 401 Unauthorized (your API key is missing or wrong) and 404 Not Found (the resource ID does not exist or does not belong to your partner account). Validation errors typically come back as 400 Bad Request with a description of which field was problematic.

// Error response
{
  "status":  404,
  "success": false,
  "data":    null,
  "error":   "Sorry, there was an error retrieving the requested resource."
}
StatusMeaning
200Success
400Bad request — missing or invalid parameters
401Unauthorized — invalid or missing API key
404Resource not found
500Server error — contact support

Quickstart Flow

If you are building an integration from scratch, the quickest path to a fully live location follows five steps. Each step depends on the one before it, so it helps to understand the full sequence before you start writing code.

Before placing an order, you will need product IDs — contact your account manager to get the list of products available to your partner account. Each product has a numeric ID you will need when placing an order.

Next, create the business location using POST /legacyclients. This is where you submit the NAP data — Name, Address, Phone — along with the category, description, and any extended information. The API returns a client_id that becomes the anchor for every subsequent operation: orders, images, reports, and data queries all reference it.

With a client ID in hand, you can place an order. Orders associate one or more products with a client and charge the partner's card on file. Once the order is placed and marked isPaid: true, Advice Local begins the fulfillment process — pushing the business data out to the directories included in the ordered products.

Fulfillment is not instant. Depending on the directory, it can take anywhere from a few hours to a few days for a listing to go live. Use GET /legacyfulfillmentdatas to poll the status of each directory. When a listing is live, the url field will contain the public link to the live listing.

Once fulfillment is underway, reporting data starts to populate. Use GET /legacyclients/{id}/report to retrieve the full baseline report, or pull individual score and insight endpoints for the specific metrics you want to surface.

1 Fetch Products
Contact your account manager
2 Create Client
POST /legacyclients
3 Place Order
POST /legacyorders
4 Check Fulfillment
GET /legacyfulfillmentdatas
5 Pull Reports
GET /legacyclients/{id}/report

Cards must be added through the Advice Local dashboard — they cannot be created via API. Retrieve your saved card IDs with GET /cards before placing orders.

Clients

In Advice Local's data model, a client represents a single physical business location. If you are managing a franchise with 50 locations, that means 50 client records — one per address. Each client gets a unique numeric id assigned at creation, and that ID is the key you will pass to every other endpoint in the API: orders reference it, images attach to it, reports are scoped to it, and fulfillment data is queried by it.

Clients move through a lifecycle. When first created, a client's status is Inactive. Once an order is placed and fulfilled, it becomes Active. If the account is suspended or paused it will reflect those states too. The status field is read-only — it is managed by the platform based on subscription and billing state, not set directly via the API.

The quality and completeness of the data you submit here directly affects listing performance. Every field that you populate — category, hours, description, website, coordinates — gives the Data Amplifier Network more signals to push to directories and to use when optimizing for voice and AI-powered search. Incomplete records publish with incomplete data, which hurts NAP consistency scores. It is worth taking the time to get the full profile right at creation rather than patching it later.

The API only supports printable ASCII. All unicode characters — including smart quotes, accented characters, and emoji — will be stripped from client fields before the record is saved. Sanitize your input on the client side to avoid unexpected data loss.

Client Object Fields

FieldTypeMaxNotes
idintegerReadonlyAuto-assigned on create
namestring128RequiredBusiness name
streetstring128Required
citystring128Required
statestring64RequiredUS state code or Canadian province code
zipcodestring32Required
phonestring32Required
descriptionstringRequiredBusiness description
countrystringOptionalUS (default), CA, GB, AU, DE, NZ
websitestringOptional
emailstringOptional
categoryGooglestring255OptionalSingle GCID — strip the gcid: prefix
hoursObjectJSONOptionalStructured hours — see Hours Format
hoursSpecialObjectJSONOptionalHoliday / exception hours
LAT / LONstringOptionalGeolocation override
hidebooleanOptionalHides client address from directories
extraJSONOptionalVoice, GMB, vertical data — see Extra Object
statusstringReadonlyActive, Inactive, Paused, or Widget Lead
publicKeystringReadonlyPublic identifier

Create a Client

POST /legacyclients Create a new business location

Creating a client is the first real operation in any integration. You submit the business's core NAP data — name, address, phone — along with a description and optionally a Google category, website, hours, and geolocation. The minimum required fields will create a valid record, but a richer submission means better directory coverage from day one.

The request body can be sent as either application/x-www-form-urlencoded or application/json. Form encoding is fine for simple field sets; JSON is easier when you need to include structured values like hoursObject or extra.

Request

POST /legacyclients HTTP/1.1
Host:         p.lssdev.com
x-api-token:  YOUR_API_KEY
Content-Type: application/x-www-form-urlencoded

name=Gina+Pizza&street=3142+W+Balboa+Blvd&city=Newport+Beach
&state=CA&zipcode=92663&phone=(949)+723-4462
&description=Authentic+Italian+pizza+since+1992
&categoryGoogle=restaurant

Response

{
  "status":  200,
  "success": true,
  "error":   null,
  "data": {
    "id":         3201926,
    "status":     "Inactive",
    "name":       "Gina Pizza",
    "country":    "US",
    "publicKey":  "e343f4531abf70d03706727af93006c8",
    "partner":    7,
    "createdAt":  "2017-12-12T23:59:44.077Z"
  }
}

Save the returned id — it is the client_id used in every subsequent API call for this location.

Get / List Clients

GET /legacyclients/{id} Retrieve one client
GET /legacyclients List all clients (paginated)

Fetching a single client by ID returns the full record exactly as it is stored — all fields, including read-only values like status, publicKey, and timestamps. This is useful when you need to read the current state of a location before performing an update, or when you want to verify that a recently submitted change was applied correctly.

The list endpoint returns all clients associated with your partner account, paginated. By default it returns 20 records sorted by ID ascending, but you can tailor the query significantly using the parameters below. For large accounts managing thousands of locations, pagination and filtering are essential — pulling the full list in a single request without a limit can produce very large payloads and slow response times.

The where parameter accepts a JSON-encoded filter object using a Waterline-style query syntax. You can filter by partial string match (contains), exact value, or comparison operators. For example, to find all active locations in California: where={"state":"CA"}&status=Active.

List Query Parameters

ParameterDefaultDescription
limit20Max records per page
skip0Records to skip (offset)
sortid ASCE.g. name ASC or createdAt DESC
whereJSON filter, e.g. {"name":{"contains":"pizza"}}
statusFilter by status: Active, Inactive, Paused, Widget Lead
city / stateField-level filters
countryUSUS, GB, CA, AU, DE, or NZ
isInactiveBoolean filter for inactive clients
deletedInclude deleted clients
keywordsArray of search keywords
createdAt / updatedAtISO date-time filters
callbackJSONP callback function name

Paginated List Example

GET /legacyclients?limit=50&skip=0&sort=name%20ASC&status=Active HTTP/1.1
Host:         p.lssdev.com
x-api-token:  YOUR_API_KEY

Update a Client

PUT /legacyclients/{id} Update client fields

Updating a client is a partial update by design — you only need to include the fields you want to change. The API will merge your payload into the existing record, leaving untouched fields exactly as they were. This makes it safe to update a single field like phone without needing to re-submit the entire client object.

This is particularly important for the extra field, which is a deeply nested JSON object. If you write to extra, always read the existing value first, merge your changes in memory, and then write the merged result back. Sending only a partial extra object will replace the entire field with just the keys you submitted, silently erasing any data that was already there.

Updates to core NAP fields — name, address, phone — will propagate to all connected directories on the next sync cycle. There is no need to manually trigger a re-push after an update; Advice Local detects the change and schedules propagation automatically.

PUT /legacyclients/3201926 HTTP/1.1
Host:         p.lssdev.com
x-api-token:  YOUR_API_KEY
Content-Type: application/json

{
  "phone":   "(949) 555-0100",
  "website": "https://ginapizza.com"
}

Delete & Reactivate

DELETE /legacyclients/{id} Delete client and disable active products

Deleting a client stops the platform from managing that location. All active products associated with the client are automatically disabled — meaning directory listings will no longer be updated, rank tracking will stop, and reports will stop refreshing. The client record itself is preserved in a soft-deleted state so that its data and history remain accessible, but it will not appear in default list queries unless you pass deleted=true.

// DELETE response
{
  "status":  200,
  "success": true,
  "error":   null
}

SSO & Dashboard URLs

GET /legacyclients/{id}/sso Temporary SSO login link
GET /legacyclients/{id}/url Permanent dashboard URL
GET /legacyclients/{id}/pdf Generate baseline/progress PDF report

These endpoints are designed for white-labeling scenarios where you want to expose the Advice Local reporting interface inside your own product without requiring your customers to maintain a separate Advice Local login.

The /sso endpoint generates a short-lived, pre-authenticated URL. When a user clicks it, they land directly in the client's report view without any login prompt. Because the token expires, you should generate a fresh SSO URL each time rather than storing it. This makes it ideal for embedding in transactional emails, portal pages that are rendered server-side, or anywhere the link is consumed immediately.

The /url endpoint returns a permanent link to the same dashboard. Unlike the SSO link, this URL does not contain a one-time token — it is suitable for bookmarking or embedding in places where the same URL will be reused repeatedly. In both cases, the link goes to a white-labeled domain configured for your partner account, so the end user sees your branding rather than Advice Local's.

The PDF report endpoint (/pdf) can take up to 120 seconds to respond. The returned data field is an S3 URL to the rendered PDF file.

// SSO response
{
  "status":  200,
  "success": true,
  "data":    "https://mysite.advicelocal.com/?page=site/clients/monthly-progress&client_id=3201926&lss_token=c1c55a63"
}

Additional PDF/report endpoints available:

GET /legacyclients/{id}/gridpdf Grid/geo-rank PDF
GET /legacyclients/{id}/aipdf AI presence PDF report

Client Images

Visual assets play a significant role in how a business listing performs across directories. Advice Local supports uploading a logo, social cover images for Facebook, Google, and Twitter, and up to five gallery images that are pushed to directories supporting photo content. All images are stored in S3 and referenced by named keys — so when you retrieve the image list, each key returns both an original URL and a thumbnail URL.

Gallery images are uploaded to the untagged endpoint and are automatically slotted as gallery_image_1 through gallery_image_5. Named images — logo, cover photos — use the tagged endpoint where the tag becomes part of the URL path. To replace an existing image, simply upload a new one using the same tag; to remove it entirely, use the DELETE endpoint with the image name returned by the GET.

All image uploads should be sent as multipart/form-data with the file attached in the file field. The Google-specific image endpoints (/legacyclientimages/google/...) are managed separately and covered in the Google Images section.

POST /legacyclientimages/{id} Upload gallery image
POST /legacyclientimages/{id}/{tag} Upload tagged image (logo, cover, etc.)
GET /legacyclientimages/{id} Retrieve all images
DELETE /legacyclientimages/{id}/{image_name} Delete an image

Image Tags

TagDescription
logoBusiness logo
facebook_coverFacebook cover image
google_coverGoogle Business Profile cover
twitter_coverTwitter/X cover image
(none)Gallery images — auto-named gallery_image_1 through gallery_image_5
// Upload logo — multipart/form-data
POST /legacyclientimages/3201926/logo HTTP/1.1
Host:         p.lssdev.com
x-api-token:  YOUR_API_KEY
Content-Type: multipart/form-data; boundary=----boundary

// Attach image file in form field "file"

Get Images Response

{
  "status":  200,
  "success": true,
  "data": {
    "logo": {
      "original":  "https://s3.amazonaws.com/.../logo.jpg",
      "thumbnail": "https://s3.amazonaws.com/.../logo_thumb.jpg"
    },
    "gallery_image_1": {
      "original":  "https://s3.amazonaws.com/.../gallery_1.jpg",
      "thumbnail": "https://s3.amazonaws.com/.../gallery_1_thumb.jpg"
    }
  }
}

Extra & GMB Data

The extra field is the extensibility layer of the client record. It is a free-form JSON object where Advice Local stores data that does not fit neatly into the core NAP fields — most importantly, Google Business Profile enrichments, voice search configuration, and industry-vertical data for healthcare and legal practices.

Because extra is a single JSON blob, you must treat it carefully during updates. The golden rule is: always read before you write. Fetch the current client record, extract the existing extra value, merge your new data into it in memory, and then PUT the merged object back. If you send a partial extra object, the API will replace the entire field with what you sent — silently deleting any keys that were already there.

The most commonly used sub-structures within extra are gmbData (for Google Business Profile enrichments), voiceTemplates and voiceQuestions (for AdVoice configuration), and verticals (for healthcare and legal data required by specialized directories).

GMB Extended Properties (extra.gmbData)

PropertyTypeNotes
primaryCategoryCategory object{"categoryId":"gcid:restaurant","displayName":"Restaurant"}
secondaryCategoriesCategory[]Array of additional GCID categories
productsProduct[]See Product format below
specialHoursPeriodsPeriod[]Holiday/exception hours
appointmentLinkURL string
servicesAreastring[]ZIP codes or city names
servicesOfferedstring[]
languagesstring[]
gmbShortNamestring
callTrackingNumbernumber

Product Format

{
  "name":     "Margherita Pizza",
  "category": "Pizzas",
  "summary":  "Classic tomato sauce, fresh mozzarella, basil",
  "price":    18,
  "callToAction": {
    "actionType": "ORDER",
    "url":        "https://ginapizza.com/order"
  }
}

Valid actionType values: BOOK, ORDER, SHOP, LEARN_MORE, SIGN_UP, GET_OFFER, CALL

Voice Data (extra.voiceTemplates / extra.voiceQuestions)

AdVoice is Advice Local's voice search optimization feature. When configured, it generates a JSON-LD FAQ schema on the client's behalf that is submitted to voice assistants like Google Assistant, Siri, Bixby, and Alexa. The schema is built from two sources: questions that are automatically generated from the client's existing data (hours, location, payment methods), and custom questions you supply via voiceQuestions.

You first select an industry template using voiceTemplates — this tells the system which pre-built question categories are relevant. Only one template should be active at a time. You then provide the answers to the custom questions for that template using voiceQuestions, formatted as JSON-LD Question/Answer objects. The question strings must match the expected values exactly — they are used as lookup keys, not free-text.

{
  "voiceTemplates": ["restaurants"],
  "voiceQuestions": [
    {
      "@type": "Question",
      "name":  "What is your busiest day of the week?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text":  "Friday"
      }
    }
  ]
}

Template options: brick (brick-and-mortar retail), services, events, financial, healthcare, home (home services), legal, restaurants. Apply only one at a time.

Healthcare Vertical (extra.verticals["4130"])

Healthcare providers can submit extended clinical and credential data through the verticals["4130"] object. This data is required by several specialized health directories and improves the richness of the provider's listing. Fields include the NPI number, DEA number, insurance accepted, conditions treated, and medical training history. The updateAt timestamp (a Unix millisecond timestamp) should be set to the current time whenever you write this data, so that downstream systems know which version is most recent.

{
  "extra": {
    "verticals": {
      "4130": {
        "updateAt": 1718040420413,
        "data": {
          "conditions_treated":  "Hypertension, Diabetes",
          "insurance_accepted":  "Blue Cross, Medicare",
          "license_number":      "TX12345",
          "accepting_new_patients": "yes",
          "npi":                 "1234567890"
        }
      }
    }
  }
}

Legal Vertical (extra.verticals["4136"])

{
  "extra": {
    "verticals": {
      "4136": {
        "updateAt": 1718059904266,
        "data": {
          "state_licensed_in":     "Texas",
          "specific_practices":    "Family Law, Estate Planning",
          "year_license_received": "2002"
        }
      }
    }
  }
}

Hours Format

Business hours are one of the most important NAP fields for local listings — directories that display hours drive customer decisions directly. Advice Local uses a structured JSON format for hours rather than free-text strings, which ensures that the data can be accurately interpreted and displayed regardless of how each directory formats hours on its own end.

Hours are submitted as an array of period objects inside hoursObject. Each period defines an opening day/time and a closing day/time. When a business has the same hours every day, you submit seven identical periods (one per day). When hours vary by day, each day gets its own period. Days are full uppercase strings (MONDAY, TUESDAY, etc.) and times use 24-hour HH:MM format.

// Regular weekly hours
{
  "periods": [
    {
      "openDay":   "MONDAY",
      "openTime":  "09:00",
      "closeDay":  "MONDAY",
      "closeTime": "21:00"
    },
    {
      "openDay":   "FRIDAY",
      "openTime":  "09:00",
      "closeDay":  "SATURDAY",  // spans midnight
      "closeTime": "02:00"
    }
  ]
}

For 24-hour operation use "openTime": "00:00" and "closeTime": "00:00". Split-day periods (two entries for the same day) are supported — directories that don't support split hours will receive the earliest open and latest close time.

Special / Holiday Hours (hoursSpecialObject)

{
  "specialHourPeriods": [
    {
      "startDate": { "year": 2025, "month": 12, "day": 25 },
      "endDate":   { "year": 2025, "month": 12, "day": 25 },
      "openTime":  "12:00",
      "closeTime": "17:00"
    }
  ]
}

Orders

An order is the mechanism that activates one or more products for a client location. Think of it as the subscription record — it ties a billing card to a client and a set of products, and once placed and paid, it triggers Advice Local to begin fulfillment work on that location. Without an order, a client exists in the system but nothing is being done for them.

Orders are immutable after creation. You cannot add products to an existing order, remove individual products from it, or change the card it was charged to. If a location's service needs to change, the typical workflow is to place a new order with the updated product set. Orders can be deleted, but doing so is destructive and will disable the associated products — use that endpoint with caution.

Before you can place an order, you need two IDs: the client ID for the location, and the card_id for the billing card to charge. Payment cards must be added through the Advice Local dashboard — there is no API endpoint to create them. Use GET /cards to retrieve the IDs of cards already on file for your account.

Place an Order

POST /legacyorders Create a new order

Request Body

FieldDescription
clientRequiredClient ID from POST /legacyclients
productsRequiredArray of product IDs (contact your account manager for available product IDs)
card_idRequiredCard ID from GET /cards
POST /legacyorders HTTP/1.1
Host:         p.lssdev.com
x-api-token:  YOUR_API_KEY
Content-Type: application/json

{
  "client":   3201926,
  "products": [101, 205],
  "card_id":  "card_1AbCdEfGhIjKlMn"
}

Response

{
  "status":  200,
  "success": true,
  "data": {
    "id":           88291,
    "price":        49.00,
    "discount":     0,
    "isPaid":       true,
    "isVerified":   true,
    "isDrip":       false,
    "transactionId": "txn_abc123",
    "products": [ /* ordered product objects */ ]
  }
}

Bulk Order Creation

POST /legacyorders/bulk Place orders for multiple clients in one request

The bulk endpoint lets you activate products across many client locations in a single API call. Pass an array of client IDs and the same product set (or a package ID) applies to all of them. Orders are processed with concurrency 3 — per-client failures are captured and returned without aborting the rest of the batch.

Before committing a large batch, set test: true to do a preflight dry-run. The response will show exactly what would be created and what the total charge would be, without actually placing any orders or charging any cards.

Request Body

FieldDescription
clientsRequiredArray of client IDs to order for
productsRequired*Array of product IDs — required if package is not set
packageRequired*Package ID — required if products is not set
card_idRequiredCard ID to charge for all orders
testSet to true for a dry-run — no orders are placed, no cards charged
POST /legacyorders/bulk HTTP/1.1
Host:         p.lssdev.com
x-api-token:  YOUR_API_KEY
Content-Type: application/json

{
  "clients":  [3201926, 3201927, 3201928],
  "products": [101, 205],
  "card_id":  "card_1AbCdEfGhIjKlMn",
  "test":     true
}

Response

The response contains a results array (one entry per client) and a summary object.

{
  "status":  200,
  "success": true,
  "data": {
    "test": true,
    "summary": {
      "clientCount":  3,
      "successCount": 3,
      "errorCount":   0,
      "totalPrice":   147.00,
      "productCounts": { "101": 3, "205": 3 }
    },
    "results": [
      { "client": 3201926, "order": { /* order object */ }, "products": [ /* ... */ ] },
      { "client": 3201927, "error": "client is not active" }
    ]
  }
}
FieldDescription
summary.clientCountTotal number of clients submitted
summary.successCountNumber of clients successfully ordered
summary.errorCountNumber of clients that failed
summary.totalPriceSum of all order prices for successful orders
summary.productCountsMap of product ID → count across successful orders (excludes replacements)
results[].clientClient ID for this result entry
results[].orderCreated order object (present on success)
results[].errorError message (present on failure)
testtrue if this was a dry-run

Get / List Orders

GET /legacyorders/{order_id} Retrieve one order
GET /legacyorders List all partner orders

Fetching a single order by its ID returns the full order record including the transaction ID, charge ID, payment status, and the array of product objects that were activated. This is useful for verifying that a specific order was placed and paid successfully, or for displaying order history to a client.

The list endpoint returns all orders across your entire partner account. If you manage many locations, this can be a large dataset — use it for auditing or reconciliation purposes rather than real-time lookups. For checking what products are currently active for a specific client, use GET /legacyorderproducts.

Ordered Products Data

GET /legacyorderproducts List ordered products with filter options

This endpoint provides a flat view of all active (or disabled) products ordered within your partner account, optionally filtered by client. Where the orders endpoints show you the billing records, this endpoint shows you the operational state — which specific products are running for which clients, when they were activated, and whether they are currently enabled.

The isDisabled and disabledAt fields are particularly useful for building dashboards. A product with isDisabled: false is actively running. A product where isDisabled: true and disabledAt is set to any date other than 2017-10-01 was explicitly turned off — either the order was deleted or the product was individually disabled. The sentinel date 2017-10-01 is a special value that indicates the product was indirectly disabled because its parent client or the partner account became inactive.

Query Parameters

ParameterDescription
clientFilter by client ID
disabledtrue or false — filter by disabled status

A disabledAt value of 2017-10-01 indicates the product was indirectly disabled (e.g. inactive client or partner). Any other date means it was explicitly disabled.

Delete an Order

DELETE /legacyorders/{order_id} Permanently delete an order

Destructive and irreversible. Permanently removes the order and disables all associated products. Double-check the order ID before calling this endpoint.

Directory Data

GET /legacydirectorydatas List directory listing records for a client
GET /legacydirectorydatas/{id} Get a single directory data record

Directory data records store the per-directory listing details for a client — the NAP data as it appears on each directory, the listing URL, and the current status. Each record links a client to a specific directory. This is the raw underlying data that drives the NAP consistency reports.

Use GET /legacydirectorydatas?client_id=<id> to retrieve all directory records for a specific client. The directory field identifies which directory the record belongs to (e.g. google, yelp, bing).

Response Fields

FieldDescription
directoryDirectory identifier (e.g. google, yelp)
statusListing status on the directory
urlLive listing URL on the directory
nameBusiness name as it appears on the directory
streetStreet address on the directory
cityCity on the directory
stateState on the directory
zipZIP code on the directory
phonePhone number on the directory

Fulfillment Data

GET /legacyfulfillmentdatas Get per-directory fulfillment status

Once an order is placed, Advice Local begins distributing the business's data to each directory included in the purchased products. Fulfillment is the process of actually getting the listing live on each directory — and this endpoint lets you monitor that process in detail. You can call it at any time after an order is placed to see the current state of each individual directory submission.

The response returns one record per directory, showing whether the listing is live (status: "live"), still in progress (pending), or experiencing an issue (temporary_problem). When a listing goes live, the url field will be populated with the direct link to the listing page. The dateUrl field (available in API v4.15 and later) records the first date a URL was detected, which you can use to measure time-to-live across your client portfolio.

The type field distinguishes between directories that Advice Local manages via a direct API connection (api) and those managed manually by the fulfillment team (manual). Manual directories may have longer fulfillment timelines and might include notes from the team in the comment field.

GET /legacyfulfillmentdatas?client=3201926 HTTP/1.1
Host:         p.lssdev.com
x-api-token:  YOUR_API_KEY

Response Fields

FieldDescription
directoryDirectory name (e.g. "Yelp", "Google")
statusFulfillment status (e.g. live, temporary_problem, pending)
urlLive listing URL if available
typemanual or api
dateCreatedWhen listing data was first initialized
dateUrlDate a live URL was first detected (API v4.15+, Feb 2020)
dateUpdatedLast modified timestamp
commentNotes from fulfillment team or automated process
username / passwordCredentials used or created for the listing account
emailAccount email (may differ from business email)
statusInitialOriginal status at time of submission

Submission Data

GET /legacysubmissiondatas List submission records for a client

Submission data records capture the raw payload that was sent to a directory on behalf of a client — the exact NAP data, categories, and attributes transmitted at the time of submission. This is useful for auditing what was actually sent vs. what the current client record says, and for diagnosing NAP inconsistencies where a directory's listing doesn't match the expected data.

Filter by client_id or directory to scope the results. Each record is a point-in-time snapshot, so you can see the full history of what was submitted to a given directory over time.

Client Report

GET /legacyclients/{id}/report Full baseline & directory report

The client report is the most comprehensive data endpoint in the API. It returns everything Advice Local knows about a location's online visibility at the time of the last scan — aggregate scores for Google, Bing, and Yelp; per-directory status for every listing in the account; NAP consistency grades; voice assistant test results; and a breakdown of each local source's individual scores for claimed status, photos, reviews, hours accuracy, and website presence.

The report is structured in two layers. The data.overview section gives you the headline numbers — the same scores that appear on the dashboard summary view. The data.baseline section is the detailed breakdown: each local source (Google, Bing, Yelp) gets its own object with granular scoring, and each directory in the account gets an entry in the directories[] array showing whether it was found, what the listing URL is, and how well the NAP data matches.

Reports are generated asynchronously. The report endpoint will continue to return the previous report until a new scan completes.

GET /legacyclients/3201926/report HTTP/1.1
Host:         p.lssdev.com
x-api-token:  YOUR_API_KEY

Response Structure

PathDescription
data.overview.baselineOverviewAggregate scores: visibilityScore, gmbScore, yelpScore, bingScore, napScore, voiceScore
data.baseline.locals[]Per-source data for Google, Bing, Yelp — score, claimed, hours, reviews, photos, NAP
data.baseline.directories[]Per-directory data: name, type, found, score, link, NAP breakdown
data.baseline.voice[]Voice assistant scores — Google Assistant, Siri, Bixby, Alexa, Cortana

Directory types: directory, aggregator, ftp

Additional report aliases:

GET /legacyclients/{id}/summary Alias for the report endpoint

Reviews

GET /legacyclients/{id}/reviews Review data for a client

Reputation is one of the most visible signals in local search, and this endpoint surfaces all of the review data Advice Local has aggregated for a location across every monitored directory. The response is structured in layers: high-level totals and averages at the top, then per-source summaries, then individual review records at the bottom.

The sentiment object categorizes reviews on a five-point scale from positive to negative, giving you a quick read on how customers feel about the business overall. The score and recency objects let you spot trends — for instance, a high score.total combined with a low score.months_1 suggests recent reviews have been more negative than historical ones. The individual data[] array contains every review with full text, so you can build a reputation monitoring widget or send review alerts directly from this data.

Review data is only available for locations with active orders. Calling this endpoint for a client without an active order will return an empty or error response.

GET /legacyclients/3201926/reviews HTTP/1.1
Host:         p.lssdev.com
x-api-token:  YOUR_API_KEY

Response Structure

FieldDescription
reviewsTotal review count
score.totalOverall average score
score.months_1 / months_6Rolling 1-month and 6-month averages
recency.week_1Reviews in the last week
sentiment.positivePositive sentiment count
sentiment.negativeNegative sentiment count
sources[]Per-directory: name, score, count, logo URL
data[]Individual reviews: provider, reviewer, score, comment, replied, reviewedAt, url
summaries[]Per-directory aggregate: rating, reviews, maxRating, updatedAt

Keywords & Geo-Grid

The keyword and geo-grid system is one of the most powerful tools in the platform for demonstrating local search performance to clients. Rather than showing a single rank number for a keyword, Advice Local scans Google Maps at a grid of geographic coordinates centered on the business location. Each grid point returns the actual rank the business holds for that keyword at that specific latitude/longitude. The result is a heat map of local search dominance — you can see not just whether a business ranks, but exactly how far their ranking influence extends geographically.

This is particularly compelling for service-area businesses or franchises that need to understand how well they dominate in adjacent neighborhoods. A plumber in downtown Austin might rank #1 for "emergency plumber" within two miles but fall out of the top 10 in the suburbs — the grid makes that visible at a glance.

Keywords are tracked per client. When you add a keyword, a new tracking campaign is created and the first scan runs automatically. Each subsequent scan updates the grid[] array with fresh rank data and appends a snapshot to history[], giving you a growing archive of how rankings have changed over time. You do not need to trigger scans manually — they run on a schedule once set up.

GET /legacykeywords/{client_id} Get tracked keywords with grid data
POST /legacykeywords/{client_id} Add / track a keyword
DELETE /legacykeywords/{client_id}/{keyword} Stop tracking a keyword
DELETE /legacykeywords/{client_id} Reset all keyword campaigns
// Add a keyword to track
POST /legacykeywords/3201926 HTTP/1.1
Host:         p.lssdev.com
x-api-token:  YOUR_API_KEY
Content-Type: application/json

{ "keyword": "pizza delivery newport beach" }

Keywords don't need to match the client's city — you can track neighboring cities or alternative search terms to understand rank spread.

Response Fields

FieldDescription
keywordTracked keyword string
grid_idGrid identifier
grid_distanceDistance between grid points
grid[]Array of {LAT, LON, rank, point} — current scan data
history[]Historical snapshots with date and nested grid[]

Direct Grid Scan Endpoints

GET /legacyclients/{id}/grid Get the latest grid scan for a client
POST /legacygrid/{client_id}/{keyword} Create a new grid scan
GET /legacygrid/{client_id}/{grid_id} Get a specific grid scan
GET /legacygrid/{id} List all grid scans

GET /legacyclients/{id}/grid is a convenience shortcut — it automatically looks up the client's most recent grid scan and returns its full ranking data without needing to know the grid ID.

Rollup Report

GET https://praxis.lssdev.com/api/v2/partner/{partner_id}/rollup/get-scores/ Partner-level aggregate scores

The rollup report operates at the partner level rather than the client level — it aggregates scores across all locations in your account into a single summary. This is the data you need for executive dashboards, quarterly business reviews, and any reporting that needs to answer the question "how are all of our locations doing on average?"

Note that this endpoint lives on a different host: praxis.lssdev.com rather than p.lssdev.com. Your x-api-token header works the same way, and you will need your numeric partner ID in the URL path. The response gives you three key structures: avgs (average scores across all locations), totals (sum totals for each metric), and count (the number of locations included in the calculation). A low average alongside a high count means your portfolio is large but performance is mixed — a pattern that usually points to a subset of locations needing attention.

GET https://praxis.lssdev.com/api/v2/partner/7/rollup/get-scores/ HTTP/1.1
x-api-token:  YOUR_API_KEY
Content-Type: application/json
// Response structure
{
  "avgs": {
    "baseline_accurate": 5,
    "monthly_google":    49,
    "monthly_bing":      61,
    "monthly_yelp":      72
  },
  "count": 211,
  "totals": {
    "baseline_accurate": 1004,
    "monthly_google":    10408
  }
}

Partner: Cards

Before you can place any orders through the API, you need a payment card on file. Cards are managed through the Advice Local dashboard rather than the API — this is intentional, as it keeps raw card data out of the API surface and delegates PCI-sensitive operations to the secure dashboard flow. Once a card is added in the dashboard, it is tokenized and stored against your partner account, and you can retrieve its token via the API.

The GET /cards response returns a list of card objects. Each object contains an id field — this is the opaque token string you will pass as card_id when placing orders. The token never expires on its own, but if a card is deleted from the dashboard or expires, orders placed with that ID will fail. It is good practice to store the card ID in your own data layer alongside the user-facing description (e.g. "Visa ending 4242") so your users can identify which card they are using.

GET /cards List cards on file
POST /cards Create a card record
DELETE /cards/{id} Delete a card
GET /cards HTTP/1.1
Host:         p.lssdev.com
x-api-token:  YOUR_API_KEY
// Response
{
  "status":  200,
  "success": true,
  "data": {
    "object": "list",
    "data": [
      { "id": "card_1AbCdEfGhIjKlMn", /* use this id when placing orders */ }
    ]
  }
}

Google Images

Google Business Profile images are managed through a separate set of endpoints from the general client image system. This distinction exists because GBP images have their own identity within the Google ecosystem — they are submitted directly to Google via the GBP API and carry a Google-assigned image_id that is different from the image name used in the general image system.

When you upload an image to GBP via this endpoint, Advice Local passes it through to Google on your behalf. The image_name you provide in the request body is a reference name for the image within your system. When you delete a GBP image, you need to pass the Google-assigned image_id in the URL path — this is the identifier that appears in the GBP API responses, not the name you used when uploading.

POST /legacyclientimages/google/{client_id} Upload a Google image
DELETE /legacyclientimages/google/{client_id}/{image_id} Delete a Google image
// Upload Google image
POST /legacyclientimages/google/3201926 HTTP/1.1
Host:         p.lssdev.com
x-api-token:  YOUR_API_KEY
Content-Type: application/json

{ "image_name": "storefront.jpg" }

// Delete Google image
DELETE /legacyclientimages/google/3201926/87891723141223213241232134 HTTP/1.1
Host:         p.lssdev.com
x-api-token:  YOUR_API_KEY

Client Labels

Labels are freeform tags you can attach to clients, similar to tags in other systems. Unlike groups, which are named containers with explicit membership lists, labels are applied directly to individual client records and can be used to filter the client list. A location might have a label like premium, onboarding, needs-review, or any other tag that makes sense for your workflow. Labels are partner-scoped, so they are consistent across your entire account.

GET /legacyclients/labels List all labels
POST /legacyclients/labels/{label} Add a label
DELETE /legacyclients/labels/{label} Remove a label

Groups

Groups are a lightweight organizational layer on top of your client portfolio. A group is simply a named collection of client IDs — there is no billing significance or product association attached to a group. Their primary use is to make it easier to work with subsets of locations: you might create a group for each brand you manage, each geographic region, each tier of service, or each account manager's portfolio.

When you fetch a group with ?populate=clients, the full client records for each member are embedded in the response. This can be convenient when you need to display a group's locations in a UI, but be aware that for groups with many members this will produce a very large response — each client record includes all of its fields. For groups with more than a few dozen locations, it is usually better to fetch the group (which includes a count and list of IDs) and then query the clients endpoint separately with filtering.

GET /legacygroups List all groups
POST /legacygroups Create a group
POST /legacygroups/{id} Update a group (rename or assign clients)

Populate Clients

Append ?populate=clients to expand each group object with its full client list. Note: this can return large payloads.

GET /legacygroups?populate=clients HTTP/1.1
Host:         p.lssdev.com
x-api-token:  YOUR_API_KEY

Create a Group

POST /legacygroups HTTP/1.1
Host:         p.lssdev.com
x-api-token:  YOUR_API_KEY
Content-Type: application/json

{ "name": "California Locations" }

Assign Clients to Group

POST /legacygroups/42 HTTP/1.1
Host:         p.lssdev.com
x-api-token:  YOUR_API_KEY
Content-Type: application/json

{
  "name":    "California Locations",
  "clients": [3201926, 3201927, 3201928]
}

Appendix

This section collects reference material that applies across multiple endpoints: accepted state and province codes, supported countries, notes on the Google category taxonomy, and a complete index of every endpoint in the API.

US State Codes

Use standard two-letter state codes (e.g. CA, TX, NY, FL, WA). All 50 states plus DC are supported.

Canadian Province Codes

AB, BC, MB, NB, NL, NS, ON, PE, QC, SK, NT, NU, YT

Supported Countries

CodeCountry
USUnited States (default)
CACanada
GBUnited Kingdom
AUAustralia
DEGermany
NZNew Zealand

Google Category IDs (GCIDs)

Google uses a curated taxonomy of business category identifiers called GCIDs to classify businesses on Google Maps and in search results. Getting the category right improves ranking for relevant searches because Google uses it to match businesses to queries. The full taxonomy CSV is available from Google and contains thousands of entries — from broad categories like gcid:restaurant to highly specific ones like gcid:neapolitan_pizza_restaurant.

When submitting a category to the Advice Local API, strip the gcid: prefix — only the slug portion goes in the categoryGoogle field. Only one primary category is supported at this level; additional categories can be submitted via extra.gmbData.secondaryCategories using the full category object format.

Categories come from Google's GCID taxonomy. When submitting a category to the API, strip the gcid: prefix:

// GCID taxonomy entry:  gcid:italian_restaurant
// Send to API as:
"categoryGoogle": "italian_restaurant"

Complete Endpoint Index

MethodPathDescription
GET/legacyclientsList clients
POST/legacyclientsCreate client
GET/legacyclients/{id}Get client
PUT/legacyclients/{id}Update client
DELETE/legacyclients/{id}Delete client
GET/legacyclients/{id}/ssoSSO link
GET/legacyclients/{id}/urlPermanent URL
GET/legacyclients/{id}/reportFull report
GET/legacyclients/{id}/reviewsReview data
GET/legacyclients/{id}/pdfPDF report
GET/legacyclients/{id}/gridpdfGrid PDF
GET/legacyclients/{id}/aipdfAI PDF report
GET/legacyclients/{id}/gridLatest geo-grid scan
GET/legacyclients/labelsList labels
POST/legacyclients/labels/{label}Add label
DELETE/legacyclients/labels/{label}Remove label
POST/legacyclientimages/{id}Upload gallery image
POST/legacyclientimages/{id}/{tag}Upload tagged image
GET/legacyclientimages/{id}Get all images
DELETE/legacyclientimages/{id}/{image}Delete image
POST/legacyclientimages/google/{id}Upload Google image
DELETE/legacyclientimages/google/{id}/{image_id}Delete Google image
POST/legacyordersCreate order
POST/legacyorders/bulkBulk create orders
GET/legacyorders/{id}Get order
GET/legacyordersList orders
DELETE/legacyorders/{id}Delete order
GET/legacyorderproductsOrdered products
GET/legacydirectorydatasList directory data
GET/legacydirectorydatas/{id}Get directory data record
GET/legacyfulfillmentdatasFulfillment data
GET/legacysubmissiondatasSubmission data
GET/legacykeywords/{id}Get keywords
POST/legacykeywords/{id}Add keyword
DELETE/legacykeywords/{id}/{keyword}Remove keyword
DELETE/legacykeywords/{id}Reset keywords
POST/legacygrid/{id}/{keyword}Create grid scan
GET/legacygrid/{id}/{grid}Get grid scan
GET/legacygroupsList groups
POST/legacygroupsCreate group
POST/legacygroups/{id}Update group
GET/cardsList cards
POST/cardsCreate card
DELETE/cards/{id}Delete card
↑ Back to top