# BuzzerAPI agent onboarding

BuzzerAPI helps an AI agent let a visitor into an apartment or condo through a **phone-based buzzer, intercom, call box, or door-entry system that dials a phone number**. Common tasks include package and food delivery, guest check-in, a dog walker, a cleaner, and time-limited contractor access. It cannot control a hardware-only intercom.

## Browser onboarding

1. Open [Account setup](/app.html) and enter the account owner's email. The owner receives a six-digit email sign-in code; ask them to provide it through the secure login flow. Do not request the code in a chat prompt.
2. Compare public Standard and Premium monthly/yearly prices on [the pricing page](/#pricing) or through `GET /v1/plans` on the configured backend origin. Sign in, choose a plan, then open the returned **Stripe hosted checkout**. Complete payment only with the account owner's authorization and their permitted payment method. A checkout link or return page alone does not mean the subscription is active.
3. After checkout, return to the account page and refresh subscription status until it says **active**. Lowkey then provisions a virtual phone number.
4. Ask the building manager to set the apartment or condo call box to dial the provisioned number. Configure the exact door-release keypress that building requires (1–3 digits, `#`, or `*`). Test from the building entrance. An active subscription or configured access rule is not proof of a working physical connection.
5. Create an **agent API key** from the account page. It is shown once. Store it in the agent connector's secret settings. The key can manage access, register notification webhooks, and read status/logs; it cannot manage billing settings, building setup, or other keys. Enable the optional building-management permission only if the agent should add paid numbers and permanently remove buildings. Reissue before its expiration.

## Programmatic use

Set `BUZZER_API_KEY` to the scoped agent key and `BUZZER_BASE_URL` to the configured service origin. The planned public API origin is `https://api.buzzerapi.com`; confirm it is reachable before relying on it. Do not put an API key in a prompt, URL, public repository, or browser page.

- `GET /v1/account`: subscription, number, capabilities, and readiness.
- `GET /v1/setup`: connection status and instructions.
- `POST /v1/unlock`: create a timer, passcode, or Premium routine. Supply a stable `Idempotency-Key` of 16–100 letters, digits, `_`, or `-` for retries.
- `GET /v1/unlock`: list access grants. `DELETE /v1/unlock/{id}` revokes one.
- `GET /v1/logs`: review recorded access activity. This is not proof of physical entry.

A timer body is `{"type":"timer","duration_minutes":15,"label":"Package delivery"}`. A visitor passcode body is `{"type":"passcode","expires_in_minutes":60,"max_uses":1,"label":"Guest"}`. Omitting `code` generates a **four-digit** code. Explicit codes follow the Lowkey app rule: one to four numeric digits, except `1` alone. Do not use a six-digit code. The visitor dials the unit, then enters the code when prompted by Lowkey. Use a timer if the agent wants to allow a delivery without telling the driver a code.

Never grant access until the owner has confirmed the intended visitor, the access window, an active subscription, the virtual number, and a successful physical setup test. A billing checkout does not unlock a door by itself.

## Routine-use notifications

New agent keys include `webhooks:write`. Existing keys need to be reissued or explicitly delegated that scope. Register an HTTPS endpoint with:

```sh
buzzer webhooks create --url https://your-agent.example/buzzer --json
buzzer webhooks test WEBHOOK_ID --json
```

The default event is `unlock.completed`: the buzzer accepted an access rule and prepared the door-release tone. It is **not confirmation that a person entered or the physical door opened**. It applies to passcodes, timers, and recurring routines. `data.unlock_id` identifies the access rule; `data.activity_id` matches the persisted log `id`; `data.occurred_at` is the activity timestamp. Old log records may have no `unlock_id`.

Save the webhook secret when creating it; it is shown once. Verify `X-Buzzer-Signature` as HMAC-SHA256 of `timestamp.raw_request_body` using that secret (`t=timestamp,v1=hex_digest`), compare in constant time, and reject timestamps more than five minutes from your clock. Deduplicate by `eventId`, queue your work, and promptly return a 2xx response. The test event is `webhook.test` and must not trigger access actions.

Delivery retries network errors, 429, and 5xx up to three total attempts. Retries currently run in-process and can be interrupted by a service restart; callbacks are best effort. Use persisted activity logs to recover missed **use** events:

```sh
buzzer logs --follow --json
buzzer logs --since 2026-09-19T00:00:00Z --json
```

For recovery, retain a timestamp checkpoint, overlap the time window, follow every pagination cursor, and deduplicate by log `id` (or callback `data.activity_id`). Filter `succeeded: true` and `unlock_id` for the rule you care about. List webhooks periodically to detect an endpoint automatically disabled after ten failed attempts; fix the endpoint, then use `buzzer webhooks update WEBHOOK_ID --active true`. Polling needs only `logs:read` and no public callback server.

## Multiple buildings and virtual numbers

An active **Multi Building** plan lets a parent-account agent manage the existing linked buildings and their separate virtual numbers. Discover building IDs first; never guess an ID or select an entrance based only on a similar label.

```sh
buzzer buildings list --json
buzzer --building BUILDING_ID setup status --json
buzzer --building BUILDING_ID unlock create --type timer --duration 15 --json
buzzer --building BUILDING_ID logs --follow --json
buzzer --building BUILDING_ID webhooks create --url https://your-agent.example/buzzer --json
```

The API equivalent is `GET /v1/buildings`, then send `X-Buzzer-Building-Id: BUILDING_ID` on `/v1/setup`, `/v1/unlock`, `/v1/logs`, and `/v1/webhooks`. Multi-building accounts must select explicitly, including for the primary building. Single-building accounts can omit selection. Access responses include `building_id`; callbacks identify the building at the top level. Webhook subscriptions and activity logs are separate for each building, so register one subscription for each building you want to monitor (the same HTTPS destination can receive all of them).

A parent-account key covers its linked buildings within the key's scopes. A key issued for a child account can only target that building. Linked-building writes require an active Multi Building plan; reading and revoking existing access remain available after downgrade. Billing and key ownership stay with the signed-in account and do not switch with `--building`. Manage the Multi Building subscription in the Lowkey app. A parent key with `account:read` and explicit `buildings:write` can add and remove linked buildings through the preview-and-execute CLI workflow below. The website setup screen also provides explicit building selection.

## Add and remove buildings

Read the [complete website documentation](/docs.html) and [command contract](/cli-reference.json) for every command and option. A Multi Building subscription must already be active; these commands do not upgrade a Standard or Premium plan.

```sh
buzzer buildings preview-add --label "East entrance" --city Seattle --state WA --zip 98101 --unlock-tone 9 --phone-number +12065550123 --json
buzzer buildings add --quote QUOTE_ID --json
buzzer buildings operation QUOTE_ID --json
buzzer buildings preview-remove BUILDING_ID --json
buzzer buildings remove BUILDING_ID --quote QUOTE_ID --json
```

Previews purchase nothing and expire after 15 minutes. Review the exact input, number, effects, and upcoming invoice estimate before executing. Amounts are minor currency units; the estimate is not a promise of an immediate charge or refund. Additions require a US address and increase billed quantity; the maximum is 20 buildings including the primary. Connect and physically test each new number.

Removal permanently releases the linked phone number, deletes its access rules and activity, revokes its keys, disables its webhooks, and reduces billed quantity. The primary building cannot be removed here.

The quote ID is also the operation ID. The default retry ID is `building-QUOTE_ID`; reuse it and the original quote after a timeout. Check `status`: only `succeeded` confirms completion. HTTP 202 can mean `running` or `reconciliation_required`. For uncertain provider outcomes, contact support with the operation ID; do not create a new request or bypass the account lock. A stale or expired unexecuted quote requires a new preview.

## Complete REST contract

Read [the full API reference](/api-reference) or download [OpenAPI 3.1](/openapi.json) for every public `/v1` operation, field, scope, error, and callback payload. This describes the connector implementation; backend deployment and live-provider verification remain pending.

REST webhook creation requires `events`; only the CLI supplies `unlock.completed` by default. All webhook operations require an active subscription, including list/delete/test. Successful-use callbacks omit codes, but `access.denied` can include `data.attempted_passcode`; treat callbacks and activity logs as sensitive. `unlock.created` and `unlock.expired` are accepted subscription values but are not currently emitted. Manual grant deletion does not dispatch `unlock.revoked`.
