LocalCitationPro
For agencies

Agency API

Place orders, check status and download reports from your own software — or let ChatGPT or Claude do it for you. Same packages, prices and rules as the agency dashboard.

Getting started

  1. Sign in to your agency dashboard, open API access and create a key. It is shown once — copy it somewhere safe.
  2. Send it with every request as a header: Authorization: Bearer lcp_live_…
  3. Base URL: https://localcitationpro.com/api/v1 — every path ends with a slash. Requests and responses are JSON.
  4. Errors come back as { "error": { "code": "…", "message": "…" } } with a normal HTTP status (401 bad key, 400 bad request, 429 too fast).
export LCP_API_KEY="lcp_live_…"
curl https://localcitationpro.com/api/v1/me/ -H "Authorization: Bearer $LCP_API_KEY"

Typical flow: GET /packages/ to see codes and your prices → POST /quote/ to check the cost → POST /orders/ to place → GET /orders/…/ to follow it and fetch the report when delivered.

GET https://localcitationpro.com/api/v1/me/

Who am I, and what is my balance?

The agency behind the key, its credit balance and its discount.

Example request

curl https://localcitationpro.com/api/v1/me/ -H "Authorization: Bearer $LCP_API_KEY"

Example response

{
  "agency": {
    "name": "Local Map Booster",
    "email": "[email protected]",
    "status": "approved"
  },
  "balanceCents": 52500,
  "balanceUsd": 525,
  "currency": "usd",
  "discountPercent": 0,
  "key": {
    "prefix": "lcp_live_Ab3dEf",
    "label": "Claude"
  }
}

GET https://localcitationpro.com/api/v1/packages/

What can I order, and what does it cost me?

Every package orderable from credit, grouped by service, priced after your discount, with the extras each accepts and the country capacity table for citation orders.

  • priceUsd is what your credit is charged. listPriceUsd is the website price.
  • requiresCitationCountry: true means the order needs citationCountry (2-letter ISO code).
  • citationCountries lists every country with maxListingsPerBusiness — a citation order whose sites exceed it is refused.

Example request

curl https://localcitationpro.com/api/v1/packages/ -H "Authorization: Bearer $LCP_API_KEY"

Example response

{
  "discountPercent": 0,
  "currency": "usd",
  "families": [
    {
      "key": "citation",
      "title": "Citation building",
      "packages": [
        {
          "code": "CITE-02",
          "name": "Growth",
          "tag": "50 citation sites",
          "description": "50 local directories — your choice or mine.",
          "listPriceUsd": 25,
          "priceUsd": 25,
          "deliveryDays": 3,
          "fastDeliveryUsd": 10,
          "citationSites": 50,
          "requiresCitationCountry": true,
          "extras": [
            {
              "id": "add-100",
              "name": "Add 100 more sites",
              "description": "…",
              "listPriceUsd": 35,
              "priceUsd": 35,
              "extraDays": 5,
              "citations": 100
            }
          ]
        }
      ]
    }
  ],
  "citationCountries": [
    {
      "code": "US",
      "name": "United States",
      "maxListingsPerBusiness": 1000
    },
    {
      "code": "IE",
      "name": "Ireland",
      "maxListingsPerBusiness": 100
    }
  ]
}

POST https://localcitationpro.com/api/v1/quote/

How much would this order cost?

Prices and checks an order without charging anything. Same body as placing an order.

Example request

curl -X POST https://localcitationpro.com/api/v1/quote/ -H "Authorization: Bearer $LCP_API_KEY" -H "Content-Type: application/json" -d '{"planCode":"CITE-02","citationCountry":"US","business":{"businessName":"Summit Plumbing Co.","website":"https://summitplumbing.com"}}'

Request body (JSON)

{
  "planCode": "CITE-02",
  "citationCountry": "US",
  "fastDelivery": false,
  "addons": [],
  "business": {
    "businessName": "Summit Plumbing Co.",
    "phone": "+1 (555) 012-3456",
    "address": "123 Main St, Austin, TX",
    "zip": "78701",
    "website": "https://summitplumbing.com",
    "gbp": "https://maps.app.goo.gl/example",
    "category": "Plumber",
    "email": "[email protected]",
    "hours": "Mon–Fri 9am–6pm",
    "description": "Family-run plumbing company serving Austin since 2014."
  }
}

Example response

{
  "quote": {
    "package": {
      "code": "CITE-02",
      "name": "Growth",
      "tag": "50 citation sites"
    },
    "quantity": 1,
    "extras": [],
    "fastDelivery": false,
    "citationCountry": "US",
    "listCents": 2500,
    "discountCents": 0,
    "totalCents": 2500,
    "currency": "usd",
    "deliveryDays": 3,
    "balanceCents": 52500,
    "canAfford": true
  }
}

POST https://localcitationpro.com/api/v1/orders/

Place one order

Charges your credit and creates the order in one step. Answers 201 with the order number.

Idempotency-Key
Optional but recommended: any unique string (a UUID is ideal). If your request times out and you send it again with the same key, you get the same order back — never a second one. Keys are remembered for 24 hours. Only placed orders are remembered: after an error (e.g. insufficient credit) you can retry with the same key once you have fixed the cause.
  • planCode is required. citationCountry is required for citation packages. business.businessName and either business.website or business.gbp are required.
  • business fields: businessName, phone, address, zip, website, gbp, category, email, hours, since, payments, keywords, description, socials, assets. Everything except name and a link can be added later on the order page.
  • addons is a list of extra ids from /packages/ (e.g. ["add-100"]). fastDelivery: true adds 1-day delivery where sold.
  • quantity (default 1) is the number of locations for multi-location businesses; most orders leave it out.
  • Errors: 400 invalid_order (message says what is wrong), 402/400 insufficient_credit, 409 request_in_progress, 422 idempotency_mismatch.

Example request

curl -X POST https://localcitationpro.com/api/v1/orders/ -H "Authorization: Bearer $LCP_API_KEY" -H "Content-Type: application/json" -H "Idempotency-Key: 4f1c2a9e-1b7d-4c8e-9a1f-2d3e4f5a6b7c" -d '{"planCode":"CITE-02","citationCountry":"US","fastDelivery":false,"addons":[],"business":{"businessName":"Summit Plumbing Co.","phone":"+1 (555) 012-3456","address":"123 Main St, Austin, TX","zip":"78701","website":"https://summitplumbing.com","gbp":"https://maps.app.goo.gl/example","category":"Plumber","email":"[email protected]","hours":"Mon–Fri 9am–6pm","description":"Family-run plumbing company serving Austin since 2014."}}'

Request body (JSON)

{
  "planCode": "CITE-02",
  "citationCountry": "US",
  "fastDelivery": false,
  "addons": [],
  "business": {
    "businessName": "Summit Plumbing Co.",
    "phone": "+1 (555) 012-3456",
    "address": "123 Main St, Austin, TX",
    "zip": "78701",
    "website": "https://summitplumbing.com",
    "gbp": "https://maps.app.goo.gl/example",
    "category": "Plumber",
    "email": "[email protected]",
    "hours": "Mon–Fri 9am–6pm",
    "description": "Family-run plumbing company serving Austin since 2014."
  }
}

Example response

{
  "order": {
    "orderNumber": "LCP-2026-0052",
    "status": "paid",
    "statusLabel": "Queued",
    "totalCents": 2500,
    "currency": "usd",
    "dueDate": "2026-09-24",
    "orderPageUrl": "https://localcitationpro.com/order/<token>/",
    "url": "https://localcitationpro.com/api/v1/orders/LCP-2026-0052/"
  },
  "balanceCents": 50000
}

POST https://localcitationpro.com/api/v1/orders/bulk/

Place many orders at once

Up to 500 orders in one call, each the same shape as a single order. Every order is priced first and the whole batch must fit your balance; otherwise nothing is placed (402). Orders are then placed one by one. If one fails, it stops and tells you exactly which were placed (207) so you never re-send those.

Idempotency-Key
Same as for a single order.

Example request

curl -X POST https://localcitationpro.com/api/v1/orders/bulk/ -H "Authorization: Bearer $LCP_API_KEY" -H "Content-Type: application/json" -H "Idempotency-Key: batch-2026-09-21-a" -d @orders.json

Request body (JSON)

{
  "orders": [
    {
      "planCode": "CITE-02",
      "citationCountry": "US",
      "fastDelivery": false,
      "addons": [],
      "business": {
        "businessName": "Summit Plumbing Co.",
        "phone": "+1 (555) 012-3456",
        "address": "123 Main St, Austin, TX",
        "zip": "78701",
        "website": "https://summitplumbing.com",
        "gbp": "https://maps.app.goo.gl/example",
        "category": "Plumber",
        "email": "[email protected]",
        "hours": "Mon–Fri 9am–6pm",
        "description": "Family-run plumbing company serving Austin since 2014."
      }
    },
    {
      "planCode": "CITE-02",
      "citationCountry": "US",
      "fastDelivery": false,
      "addons": [],
      "business": {
        "businessName": "Riverside Dental",
        "website": "https://riversidedental.com",
        "address": "9 Oak Ave, Denver, CO",
        "phone": "+1 (555) 987-6543"
      }
    }
  ]
}

Example response

{
  "ok": true,
  "placed": [
    {
      "orderNumber": "LCP-2026-0053",
      "status": "paid",
      "statusLabel": "Queued",
      "totalCents": 2500,
      "currency": "usd",
      "dueDate": "2026-09-24",
      "orderPageUrl": "https://localcitationpro.com/order/<token>/",
      "url": "https://localcitationpro.com/api/v1/orders/LCP-2026-0053/"
    },
    {
      "orderNumber": "LCP-2026-0054",
      "status": "paid",
      "statusLabel": "Queued",
      "totalCents": 2500,
      "currency": "usd",
      "dueDate": "2026-09-24",
      "orderPageUrl": "https://localcitationpro.com/order/<token>/",
      "url": "https://localcitationpro.com/api/v1/orders/LCP-2026-0054/"
    }
  ],
  "placedCount": 2,
  "totalCents": 5000,
  "balanceCents": 45000
}

GET https://localcitationpro.com/api/v1/orders/

List my orders

Every order on the account, newest first, with status, due date and the report link once delivered.

status
active (queued, building or submitted), paid, in_progress, submitted, delivered, cancelled, refunded
since
Only orders created on or after this date/time, e.g. 2026-09-01 or 2026-09-01T00:00:00Z
limit
Page size, default 100, max 500
offset
Skip this many, for paging

Example request

curl "https://localcitationpro.com/api/v1/orders/?status=delivered&since=2026-09-01" -H "Authorization: Bearer $LCP_API_KEY"

Example response

{
  "total": 21,
  "offset": 0,
  "limit": 100,
  "orders": [
    {
      "orderNumber": "LCP-2026-0052",
      "status": "delivered",
      "statusLabel": "Delivered",
      "package": {
        "code": "CITE-02",
        "name": "Growth",
        "tag": "50 citation sites"
      },
      "businessName": "Summit Plumbing Co.",
      "citationCountry": "US",
      "totalCents": 2500,
      "currency": "usd",
      "createdAt": "2026-09-21T10:15:00Z",
      "dueDate": "2026-09-24",
      "deliveredAt": "2026-09-23T16:02:00Z",
      "reportUrl": "https://localcitationpro.com/order/<token>/report/",
      "orderPageUrl": "https://localcitationpro.com/order/<token>/",
      "url": "https://localcitationpro.com/api/v1/orders/LCP-2026-0052/"
    }
  ]
}

GET https://localcitationpro.com/api/v1/orders/{orderNumber}/

One order in full

Business details, chosen sites, the timeline, and once delivered the report page, a print-to-PDF link, the Excel sheet and any files. File downloadUrl links are signed with the order's own token and redirect to a short-lived download.

Example request

curl https://localcitationpro.com/api/v1/orders/LCP-2026-0052/ -H "Authorization: Bearer $LCP_API_KEY"

Example response

{
  "order": {
    "orderNumber": "LCP-2026-0052",
    "status": "delivered",
    "statusLabel": "Delivered",
    "package": {
      "code": "CITE-02",
      "name": "Growth",
      "tag": "50 citation sites"
    },
    "quantity": 1,
    "extras": [],
    "business": {
      "businessName": "Summit Plumbing Co.",
      "website": "https://summitplumbing.com",
      "citationCountry": "US"
    },
    "selectedSites": [],
    "timeline": [
      {
        "at": "2026-09-21T10:15:00Z",
        "kind": "payment",
        "label": "Paid from agency credit",
        "detail": "Thank you — your order is queued and we'll begin shortly."
      },
      {
        "at": "2026-09-23T16:02:00Z",
        "kind": "status",
        "label": "Delivered",
        "detail": null
      }
    ],
    "report": {
      "viewUrl": "https://localcitationpro.com/order/<token>/report/",
      "pdfUrl": "https://localcitationpro.com/order/<token>/report/?print=1",
      "excel": {
        "name": "Summit Plumbing Co. — citations.xlsx",
        "href": "https://drive.google.com/uc?export=download&id=…"
      },
      "files": [
        {
          "id": "…",
          "title": "Screenshots.zip",
          "kind": "file",
          "sizeBytes": 1048576,
          "downloadUrl": "https://localcitationpro.com/api/report-files/<id>/?token=…"
        }
      ]
    }
  }
}

GET https://localcitationpro.com/api/v1/ledger/

Credit history

Every credit movement, newest first: top-ups, order charges, refunds, adjustments. They add up to balanceCents.

Example request

curl https://localcitationpro.com/api/v1/ledger/ -H "Authorization: Bearer $LCP_API_KEY"

Example response

{
  "balanceCents": 50000,
  "currency": "usd",
  "entries": [
    {
      "id": "…",
      "kind": "order_charge",
      "label": "Order",
      "amountCents": -2500,
      "orderNumber": "LCP-2026-0052",
      "note": "LCP-2026-0052",
      "createdAt": "2026-09-21T10:15:00Z"
    },
    {
      "id": "…",
      "kind": "topup",
      "label": "Credit added",
      "amountCents": 52500,
      "orderNumber": null,
      "note": "Card top-up",
      "createdAt": "2026-09-20T09:00:00Z"
    }
  ]
}

GET https://localcitationpro.com/api/v1/webhook/

Webhook: be told when an order is delivered

Instead of polling, give us an HTTPS URL of yours and we POST a signed JSON message to it the moment one of your orders is delivered. GET shows the current URL and the last delivery result. PUT { url } sets or replaces it and answers with a signing secret (shown once). DELETE removes it. POST sends a test message now.

  • The URL must be https:// on a public host. One URL per agency; setting a new one mints a new secret.
  • Events: order.delivered (real) and test (from the Send test button or POST). Each message is sent once per order; we retry 3 times if your server does not answer 2xx.
  • Headers on every message: X-LCP-Event, X-LCP-Timestamp (unix seconds) and X-LCP-Signature: v1=<hex>. Verify it: HMAC-SHA256 with your secret over the string "<timestamp>.<raw body>" must equal <hex>. Reject messages older than a few minutes.
  • The body has id, event, createdAt and data. data carries orderNumber, businessName, package, deliveredAt, reportUrl and url (the API link for the full order).

Example request

curl -X PUT https://localcitationpro.com/api/v1/webhook/ -H "Authorization: Bearer $LCP_API_KEY" -H "Content-Type: application/json" -d '{"url":"https://example.com/hooks/localcitationpro"}'

Request body (JSON)

{
  "url": "https://example.com/hooks/localcitationpro"
}

Example response

{
  "webhook": {
    "agency_id": "…",
    "url": "https://example.com/hooks/localcitationpro",
    "active": true,
    "last_attempt_at": null,
    "last_status": null,
    "last_error": null,
    "created_at": "2026-09-21T18:00:00Z"
  },
  "secret": "whsec_…",
  "note": "Store the secret now; it is not shown again."
}

What a webhook message looks like

POSTed to your URL when an order is delivered. Answer with any 2xx status within 10 seconds. Verify the signature before trusting it.

POST https://example.com/hooks/localcitationpro
Content-Type: application/json
X-LCP-Event: order.delivered
X-LCP-Timestamp: 1790000000
X-LCP-Signature: v1=<hex of HMAC-SHA256(secret, "1790000000." + raw body)>
{
  "id": "evt_a1B2c3D4e5F6g7H8",
  "event": "order.delivered",
  "createdAt": "2026-09-23T16:02:00Z",
  "data": {
    "orderNumber": "LCP-2026-0052",
    "status": "delivered",
    "statusLabel": "Delivered",
    "businessName": "Summit Plumbing Co.",
    "citationCountry": "US",
    "package": {
      "code": "CITE-02",
      "name": "Growth",
      "tag": "50 citation sites"
    },
    "deliveredAt": "2026-09-23T16:02:00Z",
    "reportUrl": "https://localcitationpro.com/order/<token>/report/",
    "orderPageUrl": "https://localcitationpro.com/order/<token>/",
    "url": "https://localcitationpro.com/api/v1/orders/LCP-2026-0052/"
  }
}

Verifying in Node.js

const crypto = require("crypto");
const [ts, sig] = [req.headers["x-lcp-timestamp"], req.headers["x-lcp-signature"].replace("v1=", "")];
const expected = crypto.createHmac("sha256", process.env.LCP_WEBHOOK_SECRET).update(ts + "." + rawBody).digest("hex");
const valid = crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected)) && Date.now() / 1000 - Number(ts) < 300;

Use with ChatGPT or Claude

This page and the machine-readable description at /api/v1/openapi.json are written so an AI assistant can order for you. Three ways that work today:

  • Claude Code or any coding assistant: paste your key into an environment variable and say “Read https://localcitationpro.com/agency-api/ and place a Growth citation order for the business in this spreadsheet row”. It will call the endpoints with curl.
  • ChatGPT custom GPT / Actions: import https://localcitationpro.com/api/v1/openapi.json as an Action, choose Bearer authentication and paste your key.
  • Claude Desktop, Zapier, Make, n8n: use their HTTP / “API request” step with the Bearer header. Every call is plain JSON over HTTPS.

Tip for prompts: ask the assistant to quote first and show you the price, then place with an Idempotency-Key. Placing charges your credit immediately.

Rules & limits

  • Prices are always decided by us from the catalogue and your agency discount. Anything price-like in a request is ignored.
  • An order charges your prepaid credit the moment it is placed. Refunds are handled by us, not through the API — email [email protected].
  • A key only ever sees its own agency’s orders and credit. Up to 5 active keys; revoke any of them on the dashboard at once.
  • Limits per key: 120 requests a minute overall, 60 order-placing requests an hour (a bulk call counts once, so use it for batches).
  • Monthly retainers are not orderable from credit. Citation orders must respect the country’s listing capacity (see /packages/).
  • Treat your key like a password. If it leaks, revoke it — we can also revoke it for you.

Questions or something missing? [email protected]