EnterRank

Integration guide

From an empty workspace to a scan you can act on, then into your own systems.

Setting up

  1. 1

    Connect your Google Business Profile

    Authorise through Google's OAuth consent screen. We request read access to reviews, posts and insights, and write access to review replies. Nothing else — we cannot change your hours, name or address.

  2. 2

    Set your brand voice

    Two sliders and two word lists. This takes about five minutes and every generated reply is bound by it afterwards, so it is worth doing properly rather than accepting defaults.

  3. 3

    Add the search terms you care about

    Start with what customers would actually type, not what you would like to rank for. Six to ten terms is plenty for a single location.

  4. 4

    Run your first grid scan

    A 7×7 grid at 500m spacing covers most city-centre service areas. Widen the spacing for rural or drive-to businesses.

Your first API call

Create a key in Settings, then confirm it works. Every endpoint on this deployment answers against sample data, so this returns real JSON immediately.

curl "https://api.enterrank.io/v1/overview" \
  -H "X-API-Key: erk_live_your_key_here"

Client examples

JavaScript

const res = await fetch("https://api.enterrank.io/v1/scans?keyword_id=kw_02", {
  headers: { "X-API-Key": process.env.ENTERRANK_KEY },
});
const { data } = await res.json();

// Points where you are not in the top 3 — the ones worth doing something about.
const weak = data.points.filter((p) => p.rank === null || p.rank > 3);
console.log(`${weak.length} of ${data.points.length} points need work`);

PHP

$ch = curl_init("https://api.enterrank.io/v1/reviews?status=needs_reply");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["X-API-Key: " . getenv("ENTERRANK_KEY")]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$payload = json_decode(curl_exec($ch), true);
foreach ($payload["data"] as $review) {
    echo $review["author"] . " — " . $review["rating"] . "\n";
}

Python

import os, requests

r = requests.get(
    "https://api.enterrank.io/v1/ai-visibility",
    headers={"X-API-Key": os.environ["ENTERRANK_KEY"]},
    timeout=10,
)
r.raise_for_status()

for probe in r.json()["data"]:
    missed = [x["engine"] for x in probe["results"] if not x["mentioned"]]
    if missed:
        print(probe["prompt"]["en"], "-> not named by", ", ".join(missed))

Verifying webhooks

Compare the signature header against an HMAC of the raw request body. Compare in constant time — a naive string equality check leaks timing information.

import crypto from "node:crypto";

export function verify(rawBody, signatureHeader, secret) {
  const expected =
    "sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");

  const a = Buffer.from(expected);
  const b = Buffer.from(signatureHeader ?? "");
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

Rate limits and retries

600 requests per minute per key. Grid scans are far more expensive than reads and are additionally limited to 60 per day. A 429 response carries Retry-After in seconds; respect it rather than backing off on a fixed timer.