One reference per client or market

A reference is a label you choose, such as a client or market name. Give every run the reference of the client it's for. Each reference then holds that client's history: you can list its runs, compare one week with the last, count the credits it used and read it from Lighthouse tools.

In short

Give every run a label for the client or market it belongs to, and each client builds up its own history. You can then list a client's runs, compare this week with last week and count the credits each client used. It suits consultants who look after several clients.

At a glance

Who it's for Revenue consultants and teams who look after rates for several clients or markets.
What you end up with Every run filed under its client, a history of snapshots for each one, and a credit count per client.
What it costs One credit per property for each run you start. Listing, comparing and counting are free.
What you need A key with the Read and write scope to start runs, and optionally a Read key for reporting tools.

Steps

  1. Choose a reference for each client or market

    A reference is your own label, sent with every run you start with POST /v1/runs. Pick one per client, such as client-42, or one per market, such as market-york. If a client has several markets, combine them: client-42-york.

    • It can be 1 to 128 characters long.
    • It can't contain a comma. A reference with one answers 422 validation_failed, and the list filter below uses commas to separate references.
    • It doesn't have to be unique. Sending it again starts a new report and run under the same reference, which is how a history builds up.

    Keep each reference the same from run to run. A new spelling starts a new history.

    Only runs started with POST /v1/runs have a reference. Runs started in the Beacon Pro app, or with POST /v1/reports/{id}/runs, have null.

  2. Decide which key sees which runs

    A key sees either the runs it started itself (Its own runs) or every run in your company (All company runs). A key can't be limited to certain references. Choose one of these set-ups:

    • One key per tool. Each tool or script starts its own runs with its own key, set to Its own runs, and sees only those.
    • One key for reporting. One system starts every run, and a Read key with All company runs feeds your spreadsheets and dashboards. It also sees runs started in the app.

    A run a key can't see answers 404 and never appears in its lists. See API keys.

  3. Start a run with the client's reference

    Start each client's run as in the quick start, with the client's reference. Run the same reference again next week, or whenever you want a new snapshot. Each run is a new report with the same list, and older runs stay as they were.

    curl -X POST https://api.pro.getbeacon.cloud/v1/runs \
      -H "Authorization: Bearer $BEACON_KEY" \
      -H "Idempotency-Key: client-42-2026-10-05" \
      -H "Content-Type: application/json" \
      -d '{
        "reference": "client-42",
        "name": "Client 42, York",
        "currency": "GBP",
        "nights": 1,
        "properties": [
          {"url": "https://www.booking.com/hotel/gb/harbour-view.html", "name": "Harbour View Hotel"},
          {"url": "https://www.booking.com/hotel/gb/quayside-inn.html", "name": "Quayside Inn"}
        ]
      }'

    Your company can have 5 runs queued or running at once, unless Beacon has raised your company's limit. With more clients than that, start the next run when one finishes. A start over the limit answers 429 too_many_active_runs and charges nothing.

  4. List a client's runs

    GET /v1/runs with a reference returns every run with that reference that your key can see, newest first. Each run carries its status, dates and cost.

    curl "https://api.pro.getbeacon.cloud/v1/runs?reference=client-42&status=completed" \
      -H "Authorization: Bearer $BEACON_KEY"
    {
      "runs": [
        {"id": 1204, "reference": "client-42", "status": "completed", "creditsCharged": 2,
         "dateFrom": "2026-10-05", "startedAt": "2026-10-05T08:00:12Z", ...},
        {"id": 1188, "reference": "client-42", "status": "completed", "creditsCharged": 2,
         "dateFrom": "2026-09-28", "startedAt": "2026-09-28T08:00:09Z", ...}
      ],
      "nextCursor": null
    }

    You can combine these filters. A run must match all of them:

    Filter What it keeps
    reference Runs with this reference. Send up to 100, separated by commas, such as client-42,client-43. More than 100 answers 422 invalid_reference.
    status queued, running or completed.
    from Runs started on or after this date, written YYYY-MM-DD.
    to Runs started on or before this date.
    limit Runs per page, 1 to 200. The default is 50.

    When there are more runs than fit on a page, nextCursor holds a value to send back as cursor for the next page. It is null on the last page. The Python and JavaScript examples follow it for you.

  5. Compare two runs

    Each run is a snapshot, so comparing two runs of the same reference shows how prices moved between them. The quickest way is to read rates for both, which gives one price per property and check-in date, and match them on hotelId (Beacon's stable id for the property) and checkIn. The example needs at least two completed runs with the reference.

    # Uses API and HEADERS from the example above
    def rates_by_day(run_id):
        """One rate per property and check-in date, keyed by (hotelId, checkIn)."""
        r = requests.get(f"{API}/runs/{run_id}/rates", params={"persons": 2}, headers=HEADERS)
        r.raise_for_status()
        return {(rate["hotelId"], rate["checkIn"]): rate for rate in r.json()["rates"]}
    
    
    # The two newest completed runs of this client
    r = requests.get(f"{API}/runs", headers=HEADERS,
                     params={"reference": "client-42", "status": "completed", "limit": 2})
    r.raise_for_status()
    latest, previous = r.json()["runs"]
    
    now = rates_by_day(latest["id"])
    before = rates_by_day(previous["id"])
    for key, rate in now.items():
        old = before.get(key)
        if old is None or rate["price"] is None or old["price"] is None:
            continue  # no match, or no rate on one side: message says why
        if rate["price"] != old["price"]:
            print(rate["hotelName"], rate["checkIn"], old["price"], "to", rate["price"])

    By default, rates start from today's date (UTC), so both runs are compared over the same check-in dates ahead. Use the same filters, such as persons or bar, for both runs. For every room rather than one price a day, download both runs' results and compare them in your own tools instead.

    If the runs capture a stay of more than one night, add los with that number of nights, or every date answers general.missing.

  6. Count the credits each client used

    Every run carries creditsCharged. To see what each client used in a month, list the month's runs and add them up by reference:

    from collections import Counter
    
    # Uses list_runs() from the example above
    credits = Counter()
    for run in list_runs({"from": "2026-09-01", "to": "2026-09-30"}):
        credits[run["reference"] or "(no reference)"] += run["creditsCharged"]
    
    for reference, total in credits.most_common():
        print(f"{reference}: {total} credits")
    client-42: 8 credits
    client-43: 6 credits
    (no reference): 3 credits

    The total covers the runs your key can see. Use a key with All company runs to count every run in your company, including runs started in the app, which appear as (no reference).

    On an account with unlimited credits, runs aren't charged, so these totals may be 0.

  7. Read a client from Lighthouse tools

    Each reference is also a Lighthouse subscription ID. Tools written for Lighthouse, and spreadsheets that use the Lighthouse-compatible API, read the newest completed run of a client with subscriptionId=client-42, and pick up the next run as soon as it completes. /lighthouse/v3/hotels lists one entry for each reference the key can see. The example below sends the key in X-Oi-Authorization, the header Lighthouse clients already send.

    curl "https://api.pro.getbeacon.cloud/lighthouse/v3/rates?subscriptionId=client-42&format=csv" \
      -H "X-Oi-Authorization: $BEACON_READ_KEY"

    See Rates in Excel or Power BI to read a client's rates in a spreadsheet, and Switching from Lighthouse for the rest.

What to watch for

  • Deleted rows. A run whose rows were deleted still appears in the list, with resultsPurgedAt set, but its results and rates answer 410 results_purged. Its creditsCharged still counts.
  • Runs still going. Rates need a completed run, so filter the list with status=completed when you compare.
  • Different property lists. If a client's list of properties changed between runs, a property that is in only one of them can't be compared. The example skips it.
  • Stay length and currency belong to each run. Compare runs that used the same ones.
  • Upper and lower case. References are matched without regard to case or accents, so Client-42 and client-42 find the same runs. The run keeps the reference as you sent it.
  • Credits. creditsCharged is what the run cost when it was accepted. It doesn't change later.
  • Dates. The from and to filters on GET /v1/runs are UTC dates.