ProfilePilot
Loading…
Developer API

Enterprise Store Locations API

Complete reference for pushing, listing, inspecting, and removing your organisation’s canonical store master records (/api/v1/locations) by store_code.

This guide is for engineering and data teams connecting an ERP, POS, or store master database to ProfilePilot. It documents all four store master endpoints (POST /api/v1/locations, GET /api/v1/locations, GET /api/v1/locations/{store_code}, and DELETE /api/v1/locations/{store_code}), their complete request/response schemas, authentication headers, and operational guardrails.

Prerequisites, Authentication & Guardrails

  • Commercial & Product Entitlement: Requires Developer API Access ($50/month minimum covering your first 500,000 API calls per UTC month) enabled under Settings → Usage & Add-ons, plus an active Locations & Reputation subscription.
  • API Key Creation: An organisation owner or manager creates a key in Settings → Developer API (/dashboard/settings/developer) with locations:read and/or locations:write scopes. Copy the secret immediately — it is displayed once and stored only as a salted SHA-256 hash. Both ppapi_<org>_<secret> and pploc_<org>_<secret> prefixes are accepted.
  • Authentication Headers: Call from your backend server only (never from browser or mobile client code). Send Authorization: Bearer <your_api_key> and Content-Type: application/json. You may optionally send x-org-id: <your_org_uuid> — if provided, it must match the organisation that owns the key or the request is rejected with 403 Forbidden.
  • What This API Does & Does Not Do: Each POST upserts your organisation’s canonical submitted store master by store_code. It does not automatically overwrite live Google Business Profile, Facebook, or Bing listings — public listing edits remain human-reviewed inside the Locations module. If a matching store_code exists on a connected Google listing, the response sets linked_google_location: true without exposing internal Google account IDs.

1. Create or Update Stores (POST /api/v1/locations)

Endpoint: POST https://profilepilotapp.com/api/v1/locations Required Scope: locations:write Required Product Subscription: Locations & Reputation + Developer API Access Batch Limit: Up to 100 stores per request (send { "locations": [ ... ] } or a single store JSON object with store_code).

Request Body Fields (per store object):

  • store_code (string, required) — Your stable, unique branch identifier (1–64 characters; letters, numbers, ., _, -, starting with a letter or number). Repeating an existing store_code updates that store in place.
  • name (string, required on creation, max 200 chars) — Public trading name of the store. Optional on subsequent partial updates; cannot be cleared to null or empty.
  • external_id (string | null, optional, max 128 chars) — Your internal ERP/POS primary key or cost-centre code.
  • phone (string | null, optional, max 32 chars) — Primary store phone number (digits, spaces, and + ( ) . -, e.g. "+27215550100").
  • website (string | null, optional, max 300 chars) — Store landing page URL (http:// or https://).
  • description (string | null, optional, max 1,000 chars) — Store summary or customer description.
  • status ("open" | "temporarily_closed" | "permanently_closed", optional) — Defaults to "open" when creating a new store.
  • address (object | null, optional) — Replaces the stored address object when provided (null clears it):
  • lines (string[], up to 5 street lines, max 120 chars each)
  • locality (string | null, max 80 chars) — City or town
  • region (string | null, max 80 chars) — Province or state
  • postal_code (string | null, max 16 chars) — Postal / ZIP code
  • country (string | null, 2-letter ISO-3166-1 alpha-2 code, e.g. "ZA", "GB", "US")
  • latitude & longitude (number | null, optional) — Must be sent together as decimal degrees (latitude -90 to 90, longitude -180 to 180), or both null to clear the pin. Sending only one coordinate returns an error.
  • hours (object | null, optional) — Keyed by lowercase weekday (monday, tuesday, wednesday, thursday, friday, saturday, sunday). Each open day is a single 24-hour window "HH:MM-HH:MM" (e.g. "08:30-17:30"), and closed days are "closed" or omitted. Sending hours replaces the entire weekly schedule for that store.

Response Fields (`POST /api/v1/locations`):

  • ok (boolean) — true only when every store in the payload succeeded (errors.length === 0).
  • created (number) — Count of new stores inserted in this call.
  • updated (number) — Count of existing stores updated in this call.
  • results[] — Array of { store_code, status: "created" | "updated", id } for each saved row.
  • errors[] — Array of { store_code, error } for any invalid row in the batch (valid rows in the same batch are still saved).
curl -sS -X POST "https://profilepilotapp.com/api/v1/locations" \
  -H "Authorization: Bearer ppapi_your_secret_key" \
  -H "x-org-id: YOUR_ORGANISATION_UUID" \
  -H "Content-Type: application/json" \
  -d '{
    "locations": [
      {
        "store_code": "HS-CPT-01",
        "external_id": "erp-4401",
        "name": "Harbour Stores Cape Town",
        "phone": "+27215550100",
        "website": "https://example.com/stores/cape-town",
        "description": "Flagship Foreshore branch with click-and-collect.",
        "status": "open",
        "address": {
          "lines": ["Shop 4, Example Mall", "12 Wharf Street"],
          "locality": "Cape Town",
          "region": "Western Cape",
          "postal_code": "8001",
          "country": "ZA"
        },
        "latitude": -33.9249,
        "longitude": 18.4241,
        "hours": {
          "monday": "09:00-17:00",
          "tuesday": "09:00-17:00",
          "wednesday": "09:00-17:00",
          "thursday": "09:00-17:00",
          "friday": "09:00-17:00",
          "saturday": "09:00-13:00",
          "sunday": "closed"
        }
      }
    ]
  }'
{
  "ok": true,
  "created": 1,
  "updated": 0,
  "results": [
    {
      "store_code": "HS-CPT-01",
      "status": "created",
      "id": "8f1c2b40-6a1e-4d3a-9c2e-1b7a0e5d44a1"
    }
  ],
  "errors": []
}

2. List Submitted Stores (GET /api/v1/locations)

Endpoint: GET https://profilepilotapp.com/api/v1/locations Required Scope: locations:read Required Product Subscription: Locations & Reputation + Developer API Access

Query Parameters:

  • store_code (string, optional) — Filter to an exact store_code.
  • updated_since (string, optional, ISO-8601 timestamp e.g. 2026-10-01T00:00:00Z) — Return only stores modified strictly after this timestamp.
  • limit (number, optional, 1–100, default 50) — Page size.
  • offset (number, optional, 0–10000, default 0) — Pagination offset.

Response Fields (`GET /api/v1/locations`):

  • ok (boolean), limit (number), offset (number), returned (number) — Pagination envelope.
  • locations[] — Array of public store master objects (id, store_code, external_id, name, phone, website, address, latitude, longitude, status, hours, description, linked_google_location, created_at, updated_at).
curl -sS -X GET "https://profilepilotapp.com/api/v1/locations?updated_since=2026-10-01T00:00:00Z&limit=50&offset=0" \
  -H "Authorization: Bearer ppapi_your_secret_key"
{
  "ok": true,
  "limit": 50,
  "offset": 0,
  "returned": 1,
  "locations": [
    {
      "id": "8f1c2b40-6a1e-4d3a-9c2e-1b7a0e5d44a1",
      "store_code": "HS-CPT-01",
      "external_id": "erp-4401",
      "name": "Harbour Stores Cape Town",
      "phone": "+27215550100",
      "website": "https://example.com/stores/cape-town",
      "address": {
        "lines": ["Shop 4, Example Mall", "12 Wharf Street"],
        "locality": "Cape Town",
        "region": "Western Cape",
        "postal_code": "8001",
        "country": "ZA"
      },
      "latitude": -33.9249,
      "longitude": 18.4241,
      "status": "open",
      "hours": {
        "monday": "09:00-17:00",
        "tuesday": "09:00-17:00",
        "wednesday": "09:00-17:00",
        "thursday": "09:00-17:00",
        "friday": "09:00-17:00",
        "saturday": "09:00-13:00",
        "sunday": "closed"
      },
      "description": "Flagship Foreshore branch with click-and-collect.",
      "linked_google_location": true,
      "created_at": "2026-10-01T08:12:00.000Z",
      "updated_at": "2026-10-20T09:30:11.000Z"
    }
  ]
}

3. Get Single Store by Code (GET /api/v1/locations/{store_code})

Endpoint: GET https://profilepilotapp.com/api/v1/locations/{store_code} Required Scope: locations:read Path Parameter: store_code (URL-encoded store code, e.g. HS-CPT-01). Returns 404 Not Found if the store code does not exist in your organisation’s submitted master file.

curl -sS -X GET "https://profilepilotapp.com/api/v1/locations/HS-CPT-01" \
  -H "Authorization: Bearer ppapi_your_secret_key"
{
  "ok": true,
  "location": {
    "id": "8f1c2b40-6a1e-4d3a-9c2e-1b7a0e5d44a1",
    "store_code": "HS-CPT-01",
    "external_id": "erp-4401",
    "name": "Harbour Stores Cape Town",
    "phone": "+27215550100",
    "website": "https://example.com/stores/cape-town",
    "address": {
      "lines": ["Shop 4, Example Mall", "12 Wharf Street"],
      "locality": "Cape Town",
      "region": "Western Cape",
      "postal_code": "8001",
      "country": "ZA"
    },
    "latitude": -33.9249,
    "longitude": 18.4241,
    "status": "open",
    "hours": {
      "monday": "09:00-17:00",
      "tuesday": "09:00-17:00",
      "wednesday": "09:00-17:00",
      "thursday": "09:00-17:00",
      "friday": "09:00-17:00",
      "saturday": "09:00-13:00",
      "sunday": "closed"
    },
    "description": "Flagship Foreshore branch with click-and-collect.",
    "linked_google_location": true,
    "created_at": "2026-10-01T08:12:00.000Z",
    "updated_at": "2026-10-20T09:30:11.000Z"
  }
}

4. Delete Store from Master File (DELETE /api/v1/locations/{store_code})

Endpoint: DELETE https://profilepilotapp.com/api/v1/locations/{store_code} Required Scope: locations:write Behaviour: Removes the store record from your submitted store master file in ProfilePilot. It does not delete or mark permanently closed your live Google Business Profile listing (to mark a store closed in the master file without deleting its history, POST "status": "permanently_closed" instead).

curl -sS -X DELETE "https://profilepilotapp.com/api/v1/locations/HS-CPT-01" \
  -H "Authorization: Bearer ppapi_your_secret_key"
{
  "ok": true,
  "deleted": true,
  "store_code": "HS-CPT-01"
}

5. Common Pitfalls & Troubleshooting

  • Why didn’t my `POST` immediately change Google Maps? By design, /api/v1/locations updates your organisation’s submitted store master and links matching store_code records (linked_google_location: true). Live Google, Facebook, and Bing publishing is controlled from the Locations console so unverified ERP fields cannot accidentally trigger a Google Business Profile re-verification lock.
  • HTTP `200` with `"ok": false` on batch `POST`: When you send multiple stores in locations[], valid stores are committed even if one or more rows fail validation. Always inspect both ok and errors[] ({ store_code, error }) and retry the rejected rows after fixing the field format.
  • `latitude and longitude must be provided together`: Never send latitude without longitude (or vice versa). Send both as numbers (-90..90 and -180..180), or send both as null to clear coordinates.
  • Invalid `hours.<day>` format / split shifts: Each open weekday accepts a single 24-hour range "HH:MM-HH:MM" (for example "08:00-17:00") or "closed". Multi-window split shifts (e.g. "09:00-12:00, 14:00-17:00") are rejected — send the store’s primary daily opening span.
  • `403 Forbidden` responses: Check three things: (1) Developer API Access ($50/month add-on) is enabled in Settings → Usage & Add-ons, (2) the organisation has an active Locations & Reputation subscription, and (3) the API key includes locations:read (for GET) or locations:write (for POST/DELETE) and matches x-org-id if that header was sent.
Typical Tasks
  • Confirm Developer API Access and Locations & Reputation are active for the organisation
  • Create a key with locations:read and locations:write in Settings → Developer API
  • POST up to 100 stores per batch to /api/v1/locations and inspect ok + errors[]
  • GET /api/v1/locations or /api/v1/locations/{store_code} to verify saved fields and linked_google_location
  • Use DELETE /api/v1/locations/{store_code} to remove obsolete master records

Developer API Reference

All Developer & Reporting API Modules

Manage API Keys →
Store Sync
locations:readlocations:write

Enterprise Store Locations API

Push and query your canonical store master records (up to 100 stores per batch) by store_code.

POST/api/v1/locations
GET/api/v1/locations
GET/api/v1/locations/{store_code}
DELETE/api/v1/locations/{store_code}
Local Presence & SEO
reports:readlocations:read

Locations Metrics & Local SEO Geo-Grid API

Pull Google Business Profile impressions, website clicks, phone calls, direction requests, peak footfall days, Meta store metrics, and Geo-Grid Share of Voice.

GET/api/v1/reports/locations/metrics
GET/api/v1/reports/seo-grid
Reputation & CX
reputation:readreports:read

Reputation, Reviews, Red Flags & CSAT API

Export star ratings, customer reviews, reply rates, business-hours response times, Red Flag alerts, and Customer Satisfaction cases.

GET/api/v1/reports/reputation/summary
GET/api/v1/reputation/reviews
GET/api/v1/reputation/red-flags
GET/api/v1/reputation/csat
WhatsApp Commerce
whatsapp:readreports:read

WhatsApp Commerce, Orders, Finance & Usage API

Export WhatsApp orders with normalized line items, fulfilment SLAs, paid GMV analytics, metered message volume, Auth OTP challenges, and loyalty balances.

GET/api/v1/whatsapp/orders
GET/api/v1/whatsapp/orders/{id}
GET/api/v1/whatsapp/reports/finance
GET/api/v1/whatsapp/reports/usage
Email & Marketing
email:readmarketing:readreports:read

Email Marketing, Workflows & Omnichannel Campaigns API

Pull active eligible subscriber counts, email campaign & automation engagement rates, WhatsApp marketing campaigns, and multi-platform social posts.

GET/api/v1/email/reports/overview
GET/api/v1/email/campaigns
GET/api/v1/email/workflows
GET/api/v1/marketing/campaigns
Inbox & Social Care
inbox:readsocial:readreports:read

Smart Inbox SLA & Social Inbox Engagement API

Export Smart Inbox ticket volumes and business-hours SLA metrics alongside Facebook & Instagram comment sentiment and actionable response rates.

GET/api/v1/inbox/reports/sla
GET/api/v1/social-inbox/reports
Insights & BI
insights:readreports:read

Insights Paid Media, GA4, Search Console & Attribution API

Pull paid media performance (Google Ads & Meta Ads), GA4 sessions and conversions, Google Search Console metrics, and True Attribution revenue.

GET/api/v1/insights/overview