Skip to main content

Suprema BioStar

Commercial access control for Suprema's BioStar platform — BioStar 2 (7.10 and newer) and BioStar X — over the server's JSON REST API. One GEM device row represents the BioStar server; each GEM zone represents a door.

The split of responsibility matters and is different from an intercom or a strike wired to a relay board:

  • BioStar is the access authority. Credentials live on the panel, the reader makes the grant/deny decision, and the server logs the result. That decision happens whether or not GEM is running.
  • GEM is the building. It drives doors (open, lockdown, release), mirrors door and event state into zones and attributes so the rest of the automation system can react, and provisions users so the same person record drives lighting scenes and door access.
Driversuprema_biostar
Categoryaccess_control
TransportHTTPS + session header
Default port443
ZonesOne per door; zone.address = numeric door id

Prerequisites

  • BioStar 2 7.10+ or BioStar X with the local API enabled. In BioStar: Settings → Server → API, set it to API Standard, then restart the BioStar service. The API does not answer until the service has been restarted.
  • A BioStar operator account for GEM. Give it the smallest permission set that covers what you actually use:
    • Monitoring — required for door status and the event log.
    • Door — required for open / lock / unlock / release / clear alarm.
    • User and Access Control — required only if you turn on user provisioning.
  • Doors already configured in BioStar. GEM binds to doors; it does not create them. Door creation, reader wiring, relay assignment and anti-passback all stay in BioStar.
  • Network reach. TCP/443 (or whichever port the API listens on) from GEM to the BioStar server. The certificate is usually self-signed; the driver accepts it.

Setup

1. Enable the API

  1. Open BioStar and go to Settings → Server.
  2. Set API to API Standard.
  3. Restart the BioStar service. This step is mandatory — the setting alone does not open the listener.

2. Add the device in GEM

Under Admin → Devices → Add:

FieldValue
Driversuprema_biostar
Namee.g. biostar
Attribute ipBioStar server IP or hostname
Attribute usernameOperator account login_id
Attribute passwordOperator password (auto-encrypted)

Save. The driver logs in, reads the server settings, caches the event-type table, enumerates doors, and starts the two polling loops.

3. Discover doors

Run get_doors from the Command Console. Each row looks roughly like:

{
"id": "35",
"name": "Front Lobby",
"door_group_id": { "id": "1", "name": "All Doors" },
"entry_device_id": { "id": "542353521", "name": "BioStation 2 542353521" },
"open_duration": "5"
}

The id field is the zone address. Note it is the door id, not the reader entry_device_id — a common mix-up, and the reason state never updates when it happens.

4. Create zones — one per door

Under Admin → Zones → Add, for each door:

FieldValue
DeviceThe BioStar device from step 2
Subsystemaccess_control (or door)
AddressDoor id from get_doors, e.g. 35

Set is_elevated on any zone that should be restricted to elevated operators — the driver refuses a non-elevated caller that names an elevated zone's address, in addition to the central command gate.

5. Optional — user provisioning

See User provisioning below. It is off until an access rule points at this device, so you can stop here for pure door control.

Attributes

Required (device)

NameTypeDescription
ipstringLAN IP or hostname of the BioStar server.
usernamestringOperator account login_id.
passwordstring (secure)Operator password.

Optional (device)

NameTypeDefaultDescription
portint443API port.
sslbooltrueBioStar requires HTTPS. Only clear this behind a TLS-terminating proxy.
base_urlstringFull base URL override, e.g. https://biostar.example.com/. Wins over ip/port/ssl.
door_poll_intervalint10000Milliseconds between door-status polls.
event_poll_intervalint3000Milliseconds between event-log polls. 0 disables event mirroring.
event_limitint100Maximum events fetched per poll.
access_group_idstringBioStar access group id (or comma-separated ids) assigned to every provisioned user. Used when sync_schedules is off.
user_group_idint1BioStar user group new users are created in. 1 is All Users on a default install.
sync_schedulesboolfalseProject GEM access-rule day/hour masks into a BioStar Schedule → Access Level → Access Group chain.
schedule_week_startstringsundayWhich weekday BioStar's day_index 0 means. Switch to monday if projected schedules land one day off.
credential_event_mapjsonOverride map of event-name fragment → GEM access type, e.g. {"EXIT_BUTTON": "rex"}. Merged over the built-in map.

Populated by the driver

On the device:

NameNotes
server_versionBioStar version from /api/setting/biostar.
last_eventName of the most recent event type, e.g. VERIFY_SUCCESS.
last_event_atISO-8601 UTC timestamp of that event.
last_event_userName of the BioStar user attached to the event, if any.
last_event_deviceReader that produced the event.
last_denial / last_denial_atMost recent *_DENIED / *_FAIL event. Useful as an attribute trigger source.

On each door zone:

NameNotes
statelocked / unlocked.
door_positionopen / closed. Requires a door-position sensor wired to the reader.
door_nameFriendly name from BioStar.
last_event, last_event_at, last_event_userPer-door copy of the event fields above.

Commands

Door control

CommandArgsEndpointNotes
openaddressPOST /api/doors/openMomentary release honouring the door's Open Duration. This is the one an access rule should call.
unlockaddressPOST /api/doors/unlockManual unlock — holds until released. Lives on the panel, so it survives a GEM restart.
lockaddressPOST /api/doors/lockManual lock — refuses valid credentials. Lockdown.
close / releaseaddressPOST /api/doors/releaseClear a manual lock or unlock; the door returns to its schedule.
clear_alarmaddressPOST /api/doors/clear_alarmClear a door alarm (forced open, held open).
lockdown_allPOST /api/doors/lockManual-lock every door mapped to a zone on this device.
release_allPOST /api/doors/releaseRelease every door mapped to a zone on this device.

address accepts a comma-separated list; every id in the list is gated individually.

Read

CommandArgsNotes
get_doorsDoors with their ids.
get_door_statusaddress (optional)Raw status payload; one door when an address is given.
get_devicesReaders / controllers registered on the server.
get_server_infoBioStar settings and version.
get_eventslimit, sinceEvent log. since is ISO-8601 UTC; defaults to the last 24 hours.
get_event_typesEvent codes and names this server can emit.
get_access_groupsAccess groups.
get_schedulesSchedules.
get_usersBioStar directory.

User management

CommandArgsNotes
create_userfirst_name, last_name, pin, rfidCreate a BioStar user with optional PIN and CSN card.
set_credentialuser_id, first_name, last_name, pin, rfidUpdate an existing BioStar user.
delete_useruser_idDelete a BioStar user.
sync_usersPush every GEM user covered by an enabled access rule on this device.
sync_to_gemCreate or link GEM auth users from the BioStar directory.

Elevated only

These reach endpoints the per-address gate cannot see, so they are refused for non-elevated callers:

CommandArgsNotes
scan_carddevice_idTrigger a card scan on a reader and return the number. Blocks up to 30 s.
unlock_devicedevice_idClear a device lockout on a reader.
clear_device_alarmdevice_idClear a reader alarm.
sync_device_datadevice_id, cleanPush the server user database down to a reader.
raw_requestpath, method, bodyPass-through to any /api/* endpoint.

Events

The documented REST API has no push or subscribe channel, so the driver polls POST /api/events/search filtered to datetime greater than the newest event it has already processed. The watermark starts at connect time — GEM does not replay the panel's history on restart.

Event type names are stable ASCII constants (ACCESS_GRANTED, VERIFY_SUCCESS, VERIFY_FAIL, ACCESS_DENIED, DOOR_FORCED_OPEN, …) and are not localised, so the driver matches on them rather than on numeric codes that shift between versions.

Driving automation from events

Two mechanisms, and it is worth picking the right one:

Attribute triggers — the normal path. Every event writes last_event / last_event_at / last_event_user on the device and on the door's zone. Build an attribute trigger on those to run a macro when someone badges in. This is the mechanism for "Alice opened the front door at 07:12, so bring the lobby lights up."

Access-control rules — the narrow path. A GEM access_control rule bound to this device fires after BioStar has already decided, so it cannot be what releases the door. It is still useful for rex:

  • rex is emitted for exit-button events, carrying the door id. No credential is involved, so this maps cleanly.
  • rfid / pin are emitted only when the event payload actually carries the raw credential. GEM resolves those back to a user by credential value; synthesising one from the BioStar user id would silently attribute the event to the wrong person the moment the two directories disagree. When a mapped event arrives without a credential the driver logs it and emits nothing.

Use credential_event_map to map additional event-name fragments to access types.

User provisioning

Provisioning is gated on access rules: a GEM user is pushed only when an enabled access_control rule on this device covers them. With no rules on the device, nothing is ever written to BioStar.

The link between the two directories is an attribute on the GEM user: suprema_user_id_<deviceId>, holding the BioStar user_id. On first sync an unlinked user is matched by display name before a new record is created, so a directory that already exists is adopted rather than duplicated.

Credentials

  • PIN — GEM's pin credential is decrypted and written to the BioStar user's pin field.
  • Card — GEM's rfid credential is enrolled as a CSN card and assigned to the user. BioStar only accepts a CSN whose id is all digits and does not start with 0. A hex card number from another system is a legitimate GEM credential but cannot be created this way — the driver logs it and skips the card rather than failing the user's whole sync. Enrol those in BioStar directly, or use scan_card.
  • Fingerprint and face templates are not provisioned. They must be enrolled at a reader.

Access assignment

Two modes.

Simple (default). Set access_group_id to an access group you already built in BioStar. Every provisioned user lands in it. The schedule and door set stay entirely under BioStar's control — GEM only decides who is in the group.

Projected (sync_schedules = true). GEM turns each user's merged access-rule day/hour mask into a real BioStar access chain:

GEM <key> (Schedule) ← day_enable_mask + hour_enable_mask

GEM <key> (Access Level) ← the doors mapped to zones on this device

GEM <key> (Access Group) ← the users whose windows hash to <key>

<key> is a hash of the merged 7 × 24 window, so everyone on the same schedule shares one chain rather than getting a schedule each. A user on several rules gets the union of their windows.

The panel then enforces the window offline, with no GEM in the loop.

Two safety properties are worth stating plainly:

  • Only objects named GEM … are ever created or modified. A schedule, access level or group you built by hand cannot be captured, edited, or deleted by this driver.
  • Hand-assigned access groups on a user are preserved. Before assigning its own group, GEM removes only its own groups from that user. Somebody who is also in Contractors stays in Contractors.

If every rule covering a user excludes every hour, GEM removes its own groups from that user and leaves the account otherwise alone. An explicit GEM disable (disableUser) is different — that sets disabled on the BioStar account outright, because it is a deliberate block rather than an empty schedule.

Zone address format

The zone address is the numeric BioStar door id as a string, e.g. 35. Enumerate with get_doors.

Known limitations

  • BioStar decides, not GEM. An access rule on this device runs after the panel's decision. Use open from a macro or an attribute trigger for door release, not from an access rule expecting to be the gate.
  • Events are polled. The documented API exposes no subscribe channel. At the 3 s default an event reaches GEM within about three seconds.
  • No response sample is published for POST /api/doors/status, so field names vary between BioStar 2 and X. The driver normalises every lock / unlock / open / close spelling it recognises and leaves the zone alone for anything it does not, because the event log — which uses stable names — is the more reliable source. The first status payload of each connect is logged once so an unrecognised shape can be identified from the field.
  • Only CSN cards can be provisioned. Wiegand and smart cards need a format or key defined in BioStar and must be enrolled there.
  • Biometrics are not provisioned. Fingerprint and face enrolment happen at the reader.
  • Elevators, zones (APB / muster) and trigger-actions are not exposed. The API supports them; this driver does not model them yet.

Troubleshooting

Every call returns 401. The driver re-logs in once per 401 automatically, so a persistent 401 means the credentials are wrong or the account lacks API permission. Confirm Settings → Server → API is set to API Standard and that the service was restarted after the change.

Doors enumerate but open returns a permission error. The operator account has Monitoring but not Door. They are separate permissions in BioStar.

zone.state never changes. Almost always the address is the reader entry_device_id instead of the door id. Re-run get_doors and use the top-level id. Run get_door_status to see exactly what the server returns for that door.

Device shows offline while the BioStar web UI works. The driver marks the device offline after five consecutive failed poll cycles — including cycles where the server answered but rejected the request (401/500). Check the GEM log for the underlying error; a server that answers everything with a permission error is functionally offline for our purposes and is reported as such.

No events arrive. Check event_poll_interval is non-zero and the account has Monitoring. Run get_events to read the log directly. If the server rejects the GREATER datetime operator the driver falls back to a bounded range automatically and logs the switch once.

Projected schedules are one day off. Set schedule_week_start to monday.

Users sync but open nothing. They were provisioned with no access. Set access_group_id, or turn on sync_schedules.

Follow-ups

  • Model elevators and floor levels as zones.
  • Surface BioStar alerts (/api/alerts/search) into the GEM alarm spine.
  • Expose anti-passback reset (clear_apb_ex) as a command.
  • Pull door open/held-open thresholds from BioStar so GEM's forced-door monitoring can inherit them.

See also

  • UniFi Access — comparable commercial access-control platform.
  • 2N IP Intercom — the edge-device model, where GEM makes the access decision.