GuestBan Partner API — v1 Reference

GuestBan · Partner API

Version 1 reference

Three read-only reports covering yesterday's arrivals at your properties: every check-in, the guests who matched a criminal or sex-offender record, and a usage summary. Built for a nightly pull into your own systems.

Base URL
https://api.myguestban.com
Auth
X-API-Key header
Format
JSON
Released
14 Aug 2026

Getting started

One call, and you should have yesterday's arrivals.

# Every guest who checked in yesterday, across all your properties
curl -s https://api.myguestban.com/api/public/v1/guests \
  -H "X-API-Key: YOUR_API_KEY"

A successful response is the report itself — there is no wrapper object to unpack and no success flag to check. Use the HTTP status code.

Run it once before you build anything. If your key is not yet enabled for an endpoint you will get 403 rather than data, and that is far easier to diagnose now than inside a scheduled job at 3am.

Authentication

Send your key in the X-API-Key header on every request. There is no token exchange and nothing to refresh.

curl -s https://api.myguestban.com/api/public/v1/guests \
  -H "X-API-Key: YOUR_API_KEY"

Keys are 32 hexadecimal characters. GuestBan issues yours directly — it is never sent by email in the same message as this document.

Your key determines which properties you can see. There is no tenantId or propertyId parameter anywhere in this API, and no request can widen your access beyond the properties your key already covers.

Treat the key as a password. It does not expire on its own. If it is exposed, contact GuestBan support and we will issue a replacement — the old one stops working immediately, so plan a short changeover.

How it behaves

Three behaviours differ from most APIs. They are deliberate, and knowing them up front will save you a support ticket.

Rule 01

Always yesterday

Every endpoint reports the previous day. There is no date, no range, and no way to request history — so run your job daily and keep what you pull.

Rule 02

Almost no parameters

The two list endpoints accept propertyName and nothing else. The usage summary accepts nothing at all. Anything unrecognised is rejected with 400, never ignored.

Rule 03

The day is local

"Yesterday" is resolved in each property's own time zone, so a hotel's real overnight — not one shared UTC window.

Why unknown parameters are rejected

If you sent ?date=2026-01-01 and we quietly returned yesterday instead, nothing in the response would tell you the difference — you would file a year of wrong data believing it was right. So an unrecognised parameter fails loudly:

curl -s "https://api.myguestban.com/api/public/v1/guests?date=2026-01-01" \
  -H "X-API-Key: YOUR_API_KEY"

# 400 Bad Request
{
  "code": "parameter_not_supported",
  "detail": "This endpoint does not accept 'date'."
}

Naming a property

Applies to /v1/guests and /v1/criminal-arrivals only. Pass propertyName to narrow one of those reports to a single property; omit it to cover all of them. Matching tolerates casing and spacing, so WSSAddison finds WSS Addison. It is not a partial search — a name that matches nothing returns 404 property_not_found rather than an empty day, so a typo in your config surfaces immediately instead of looking like a quiet night.

curl -s "https://api.myguestban.com/api/public/v1/guests?propertyName=WSS%20Addison" \
  -H "X-API-Key: YOUR_API_KEY"

The usage summary takes no parameter at all. It always covers every property your key reaches and splits the figures out per property in its byProperty array, so there is nothing to narrow.

Guest arrivals

GET /api/public/v1/guests

Every guest who checked in yesterday. The whole day comes back in one response.

{
  "totalCount": 2,
  "propertyName": "WSS Addison",
  "reportedDateLocal": "2026-08-10",
  "message": null,
  "items": [
    {
      "propertyName": "WSS Addison",
      "propertyTimeZone": "Eastern Standard Time",
      "checkInAtUtc": "2026-08-10T21:14:03Z",
      "checkInDateLocal": "2026-08-10",
      "firstName": "ANTHONY",
      "middleName": null,
      "lastName": "RAIA",
      "dateOfBirth": "1979-04-22T00:00:00",
      "gender": "MALE",
      "identificationNumber": "S1234567",
      "documentExpirationDate": "2029-04-22T00:00:00",
      "address": "114 Mulberry St",
      "city": "Newark",
      "state": "NJ",
      "zipCode": "07102",
      "roomNumber": "412",
      "isFlagged": false,
      "hasCriminalRecord": false,
      "isSexualOffender": false,
      "matchedBanAtCheckIn": false,
      "isCurrentlyBanned": false,
      "source": "scan"
    }
  ]
}

Fields worth reading twice

FieldNotes
gender MALE, FEMALE or UNKNOWN — or null. UNKNOWN means a value was captured that we could not classify; null means nothing was captured. Machine values, not display text.
matchedBanAtCheckIn Whether screening matched a ban at the desk. Never changes for a past day. null means no screening record exists for that arrival — which is not the same as false.
isCurrentlyBanned Whether a ban exists right now. Live, so two pulls of the same day can differ — a guest banned after they left flips to true here.
isFlagged A manual staff action, not a screening outcome. For screening use the two fields above.
source scan, scan manual entry (photographed, details typed) or manual entry.

Not included: vehicle details and ID scan images are deliberately excluded from this contract, as is GuestBan's internal guest identifier. Properties are identified by name throughout, so you never need to store one of our keys.

Criminal arrivals

GET /api/public/v1/criminal-arrivals

Yesterday's arrivals that matched the criminal-records or sex-offender feed — one record per guest, however many matches they triggered.

{
  "totalCount": 1,
  "reportedDateLocal": "2026-08-10",
  "items": [
    {
      "propertyName": "WSS Addison",
      "checkInAtUtc": "2026-08-10T18:02:55Z",
      "checkInDateLocal": "2026-08-10",
      "firstName": "KAREN",
      "lastName": "KLINE",
      "gender": "FEMALE",
      "hasCriminalRecord": true,
      "isSexualOffender": false,
      "crimeTypes": ["FELONY", "MISDEMEANOR"],
      "offenseDescriptions": ["THEFT BY DECEPTION"],
      "acknowledgedAtUtc": "2026-08-10T18:04:11Z",
      "acknowledgedAtLocal": "2026-08-10 14:04:11",
      "source": "scan"
    }
  ]
}

crimeTypes and offenseDescriptions are not positionally paired. They are two independent lists — do not zip them together. Both are empty arrays, never null, when there are no criminal offenses.

Sex-offender matches are exposed as the isSexualOffender flag only; the associated offense descriptions are not disclosed. A guest can be a sex-offender match with no criminal match, in which case both offense lists are empty.

acknowledgedAtUtc is null when the alert was shown to staff but not yet acknowledged. That is distinct from a guest with no alert at all.

Usage summary

GET /api/public/v1/usage/dashboard

Yesterday's screening activity as counts, covering every property your key reaches, with a breakdown per property. Calculated once after the day closes and served from storage thereafter.

{
  "reportedDateLocal": "2026-08-10",
  "fromUtc":           "2026-08-10T04:00:00Z",
  "toUtc":             "2026-08-11T05:00:00Z",

  "reportGeneratedAt": "2026-08-11T05:12:41Z",
  "apiRequestedAt":    "2026-08-11T08:15:32Z",

  "totals": {
    "scans":              { "value": 19, "changePercent":   5.6 },
    "manualEntry":        { "value":  3, "changePercent": -25.0 },
    "bansAdded":          { "value":  1, "changePercent":  null },
    "criminalMatches":    { "value":  1, "changePercent":   0.0 },
    "sexOffenderMatches": { "value":  0, "changePercent":  null }
  },

  "alerts": {
    "banMatches":  { "value": 0, "changePercent": null },
    "criminal":    { "value": 1, "changePercent":  0.0 },
    "sexOffender": { "value": 0, "changePercent": null }
  },

  "warnings": {
    "ageAlert":   { "value": 4, "changePercent":  33.3 },
    "localAlert": { "value": 6, "changePercent": -14.3 }
  },

  "byProperty": [
    {
      "propertyName": "BHS Beavercreek",
      "scans": 2, "manualEntry": 0, "bansAdded": 0,
      "criminalMatches": 0, "sexOffenderMatches": 0,
      "banMatches": 0, "criminal": 0, "sexOffender": 0,
      "ageAlert": 1, "localAlert": 0
    },
    {
      "propertyName": "BHS Jackson MS",
      "scans": 6, "manualEntry": 2, "bansAdded": 0,
      "criminalMatches": 1, "sexOffenderMatches": 0,
      "banMatches": 0, "criminal": 1, "sexOffender": 0,
      "ageAlert": 1, "localAlert": 2
    }
    /* … one row per property */
  ],

  "activity": {
    "granularity": "DAILY",
    "points": [ { "date": "2026-08-10T04:00:00Z", "scans": 19, /* … */ } ]
  },

  "message": null
}

Two timestamps, and they mean different things

This report is calculated once, shortly after the reported day closes, and stored. Every request after that reads the stored copy rather than recounting.

FieldDescribesChanges between two identical requests?
reportGeneratedAt When GuestBan calculated and stored these figures. A property of the report.No — identical every time you pull the same day.
apiRequestedAt When we received your request. A property of the call, informational only.Yes — it is the only field that moves.

A gap of several hours between the two is normal and expected. Use it to tell how fresh the figures you are holding actually are.

Alerts and warnings are different things

This is the distinction most worth understanding before you build a report on these numbers.

BlockMeaningFields
alerts Something was found about the guest — they matched a ban, the criminal feed, or the sex-offender registry.banMatches, criminal, sexOffender
warnings Nothing was found. A threshold the property configured for itself was crossed — the guest is under the age limit, or lives inside the local radius.ageAlert, localAlert

Do not add the two blocks together. They answer different questions, and a guest who matches several sources at once contributes to each alert they matched — so the alert figures do not count guests.

bansAdded and banMatches are unrelated. bansAdded counts ban records your staff created during the day. banMatches counts arriving guests caught by a ban that already existed. A property can add bans all day and match none of them.

The per-property breakdown

byProperty carries one row for every property your key reaches — including any that recorded nothing, which appear as a row of zeros rather than disappearing. A silent property and a removed one should not look the same.

The row fields use the same names as the headline blocks, and every column adds up across the rows to its headline figure. That is guaranteed, not incidental: the rows are the same calculation split by property. If they ever disagree, tell us.

Rows carry bare numbers with no changePercent — there is no per-property comparison against the day before. Difference two days of this report if you need one.

Reading the numbers

FieldNotes
scans Guests processed at the kiosk — one per person checked in. Not a count of documents scanned.
manualEntry Of those scans, how many were typed in by staff rather than machine-read. A subset of scans, never additional to it — adding the two together double-counts every manual guest.
criminalMatches Overlaps alerts.criminal, which answers the same question from a different record. They agree on recent data and can differ on older data. The same applies to sexOffenderMatches and alerts.sexOffender.
changePercent Movement against the day before. null when there is no single comparable baseline — including any group of properties in different time zones, since each has its own day-before.
value null means "not recorded for this day", which is not zero.

Errors

Failures come back as application/problem+json. Branch on code — it is stable. The detail text is written for humans and may be reworded at any time.

{
  "type": "about:blank",
  "title": "Bad Request",
  "status": 400,
  "code": "parameter_not_supported",
  "detail": "This endpoint does not accept 'date'.",
  "correlationId": "3f9c1a4b-8e2d-47f0-a1b6-c3d5e7f80921"
}
StatusCodeWhat to do
400parameter_not_supported Remove the parameter. The list endpoints accept only propertyName; the usage summary accepts nothing.
400invalid_requestThe request was malformed. Check the URL and header syntax.
401invalid_api_keyKey missing or not recognised. Confirm the X-API-Key header is being sent.
403insufficient_scopeKey is valid but not enabled for this endpoint. Contact GuestBan support.
404property_not_foundThe name matched none of your properties. Check spelling before assuming an empty day.
404property_name_ambiguousSeveral of your properties share that name.
404not_foundNo such route. Check the path against this page.
429rate_limit_exceededToo many concurrent requests. Back off and retry — see below.
500internal_errorOur fault. Retry once, then contact support quoting the correlation id.

Retrying

Retry 429 and 500 with exponential backoff. Do not retry 400, 401, 403 or 404 — those describe something about the request that will not change on its own.

These reports cover a fixed past day, so they are safe to request more than once: pulling the same day twice returns the same data, apart from the handful of live fields noted above.

Support

Every response carries an X-Correlation-Id header — including failures that never reach our application, such as an authentication rejection.

curl -sD - -o /dev/null https://api.myguestban.com/api/public/v1/guests \
  -H "X-API-Key: YOUR_API_KEY" | grep -i correlation

x-correlation-id: 3f9c1a4b-8e2d-47f0-a1b6-c3d5e7f80921

Log it. Quoting one lets us find your exact request in seconds instead of reconstructing it from a description — it is by far the fastest route to an answer.


Suggested integration

Run once daily, after your properties' overnight has closed in every time zone you operate in. Store what you pull: there is no way to request an earlier day, so an unrun job is a gap you cannot backfill.

ID Scanning & DNR solutions for Hotels

Contact Info

Guest Ban

Address:
630 Valley Mall PKWY PMB 608, East Wenatchee, WA 98802

Phone:
(425) 484-0915

Email:
support@guestban.com

© Copyright 2026 Guest Ban by Innstrata. All Rights Reserved.
Guest Ban product is not formally endorsed by or affiliated with any logos, brands, or products displayed on this website, unless explicitly stated. All externally listed products, company names, and trademarks are the property of their respective holders. Third-party products, logos, and trademarks used on this website are for educational, informational, or compatibility purposes only and do not imply any official partnership or endorsement.