BB HTTP API Reference (Client-Facing)
This document consolidates all HTTP endpoints registered by the server handlers and provides a client-facing reference. It complements existing deep-dive docs (linked where available) and offers a single place to discover paths, auth requirements, and response conventions.
- Base URL (local dev):
http://localhost:8080or via TLS proxyhttps://localhost:10000 - Auth cookie:
cjj365=<session_id> - Response wrapper:
- success:
200/201/204with optional body{ "data": ... } - error: status ≥
400with body{ "error": { "code": int, "what": string } }
- success:
- CORS: Client must send credentials if needed; server mirrors origin and sets
Access-Control-Allow-Credentials: true. - Pagination (when applicable): cursor or offset parameters are noted per endpoint.
Links to related docs (GitHub source):
- Login & session: LOGIN_WORKFLOW.md
- Device OAuth-like flow: DEVICE_AUTH_TESTING.md
- Device updates long-poll: DEVICE_POLLING_UPDATES.md
- Refresh token: REFRESH_TOKEN_SYSTEM.md
- Device registration overview: USER_DEVICE_REGISTRATION_WORKFLOW.md
- Device certificate assignment: DEVICE_CERTIFICATE_ASSIGNMENT.md
- Payments domain plan: PAYMENT_WORKFLOW.md
Note: Schemas below reflect current server behavior and conventions. Some domains (payments) are being built out; treat those as stable path contracts with evolving payloads.
Auth & Session
General Login and Session (LoginHandler)
Paths
GET /auth/general— Auxiliary (e.g., name availability)GET /auth/status— Inspect current sessionPOST /auth/logout— Logout; clears sessionGET /auth/profile— Current profile summaryGET /auth/third-party-bindings— Linked auth providers
Notes
device_pollrequests may include a numericdevice_idalongsidedevice_code. When provided and owned by the approved user, the issued access token carries adevice_idclaim so device-scoped APIs (for example/apiv1/devices/self/updates) accept it without additional session setup.
Auth
- Most endpoints work with or without a session to report status; logout/profile/bindings require a session.
See the login workflow doc for request/response examples of /auth/general and /auth/status.
WebAuthn (WebAuthnHandler)
Paths
POST /auth/webauthn/register/optionsPOST /auth/webauthn/register/verifyPOST /auth/webauthn/login/optionsPOST /auth/webauthn/login/verifyPOST /auth/webauthn/step-up/optionsPOST /auth/webauthn/step-up/verifyGET /auth/webauthn/credentialsDELETE /auth/webauthn/credentials/:id
Auth
- Registration/login options may be unauthenticated depending on flow.
- Credentials management requires a session.
Responses
- Follows standard wrapper. Options endpoints return WebAuthn
PublicKeyCredentialoptions JSON for the browser WebAuthn API.
Weixin (WeChat) Login (WeixinLoginHandler)
Paths
GET /auth/weixin— Start Weixin login (redirect or QR)GET /auth/weixin/callback— OAuth callback target
Auth
- Unauthenticated; establishes user session upon successful OAuth.
Refresh Token (RefreshTokenHandler)
Path
POST /auth/refresh— Issue new access token/cookie session
See the refresh token doc.
Device Flow (DeviceAuthHandler)
Path
POST /auth/device— Start/poll/verify device login sequence
See the device auth testing guide.
Health
Health Check (HealthHandler)
Path
GET /health— Liveness/readiness probe
See the Docker test environment notes for examples.
Devices (DevicesHandler)
Base paths under user scope
/apiv1/users/:user_id/devices/apiv1/users/:user_id/devices/:device_id/apiv1/users/:user_id/devices/:device_id/certificates/apiv1/users/:user_id/devices/:device_id/certificates/:certificate_id/apiv1/users/:user_id/devices/:device_id/cas/apiv1/users/:user_id/devices/:device_id/cas/:ca_id/apiv1/users/:user_id/devices/:device_id/install-config/apiv1/users/:user_id/devices/:device_id/install-config/restore/apiv1/users/:user_id/devices/:device_id/install-config-histories
Auth
- Requires user session; server enforces that route
:user_idmatches session user.
Typical methods and semantics
GET /apiv1/users/:user_id/devices— List devices (owned by user)POST /apiv1/users/:user_id/devices— Register deviceGET /apiv1/users/:user_id/devices/:device_id— Device detailDELETE /apiv1/users/:user_id/devices/:device_id— Remove device
Certificates
GET /.../devices/:device_id/certificates— List assigned certificatesPOST /.../devices/:device_id/certificates— Assign/create certificate for deviceGET /.../devices/:device_id/certificates/:certificate_id— DetailDELETE /.../devices/:device_id/certificates/:certificate_id— Unassign/remove
CAs (Certificate Authorities)
GET /.../devices/:device_id/cas— List CAs associated with devicePOST /.../devices/:device_id/cas— Associate CA with deviceDELETE /.../devices/:device_id/cas/:ca_id— Disassociate CA from device
Install Configuration
GET /.../devices/:device_id/install-config— Current install config DTOPUT /.../devices/:device_id/install-config— Update/replace install configGET /.../devices/:device_id/install-config-histories— List history versionsPOST /.../devices/:device_id/install-config/restore— Restore from history- Body:
{ "version": number, "change_note": string }
- Body:
Examples
Device Management
-
List user's devices
- Request:
GET /apiv1/users/1/devices?limit=20&offset=0 - Response
200:{
"data": [
{
"id": 123,
"user_id": 1,
"device_public_id": "dev_abc123xyz",
"status": "ACTIVE",
"created_at": 1736900000000
}
]
}
- Request:
-
Register new device
- Request:
POST /apiv1/users/1/devices - Body:
{
"device_public_id": "dev_new456",
"device_secret_hash": "...",
"fp_hash": "...",
"fp_version": "1.0"
} - Response
200:{
"data": {
"id": 124,
"user_id": 1,
"device_public_id": "dev_new456",
"status": "ACTIVE",
"created_at": 1736900100000
}
}
- Request:
Certificate Assignment
-
List certificates assigned to device
- Request:
GET /apiv1/users/1/devices/123/certificates - Response
200:{
"data": [
{
"id": 1001,
"domain_name": "app.example.com",
"sans": ["app.example.com", "*.app.example.com"],
"self_signed": false,
"verified": true,
"serial_number": "04:A1:B2:C3:...",
"created_at": 1736900000000
}
]
}
- Request:
-
Assign certificate to device
- Request:
POST /apiv1/users/1/devices/123/certificates - Body:
{
"cert_id": 2
} - Response
204: No Content (success)
- Request:
-
Unassign certificate from device
- Request:
DELETE /apiv1/users/1/devices/123/certificates/2 - Response
204: No Content (success)
- Request:
Notes
- Certificate assignment deploys the certificate to the device for use.
- Devices receive encrypted private keys via the device self certificates endpoint.
- Multiple devices can be assigned the same certificate (load balancer scenario).
CA Association
-
List CAs associated with device
- Request:
GET /apiv1/users/1/devices/123/cas - Response
200:{
"data": [
{
"id": 7,
"user_id": 1,
"name": "Development CA",
"algorithm": "ECDSA",
"key_size": 256,
"country": "CN",
"organization": "MyOrg",
"common_name": "Dev Root CA",
"status": "ACTIVE",
"ca_certificate_pem": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n",
"created_at": 1736800000000
}
]
}
- Request:
-
Associate CA with device
- Request:
POST /apiv1/users/1/devices/123/cas - Body:
{
"ca_id": 7
} - Response
204: No Content (success)
- Request:
-
Disassociate CA from device
- Request:
DELETE /apiv1/users/1/devices/123/cas/7 - Response
204: No Content (success)
- Request:
Notes
- CA association allows devices to trust certificates issued by that CA.
- The CA certificate PEM is included in list responses for client trust store installation.
- Devices can have multiple CAs associated (useful for CA rotation).
Install config DTO (server-minimal; client renders platform-specific scripts):
{
"device_id": 123,
"version": 3,
"installs": [
{
"resource": "cert/main",
"kind": "copy",
"from": ["$store/cert.pem"],
"to": ["/etc/ssl/certs/cert.pem"],
"verify": true
},
{
"resource": "key/main",
"kind": "copy",
"from": ["$store/key.pem"],
"to": ["/etc/ssl/private/key.pem"],
"verify": true
},
{
"resource": "reload",
"kind": "exec",
"cmd": "systemctl reload nginx"
}
],
"installs_json": "..."
}
Notes
- The copy item uses array
from/to; one item per resource. - Restore returns the restored version in the response data.
Related reading: DEVICE_CERTIFICATE_ASSIGNMENT.md.
Device Updates (DeviceUpdatesHandler)
Path
GET /apiv1/devices/self/updates
Auth
- Device-authenticated requests (see DEVICE_POLLING_UPDATES.md). Supports long-poll with
waitquery andIf-None-MatchETag.
Device Self Certificates (DeviceSelfCertsHandler)
Path
GET /apiv1/devices/self/certificates/:certificate_id/deploy-materials(JSON only; no download semantics)
Auth
- Device-authenticated via Bearer JWT (HS256). The token must represent the device (contains
device_idclaim) and belong to the owning user.
Behavior (policy-aware)
- HYBRID (default) or DEVICE_REQUIRED: returns AEAD-wrapped bundle when device wrapping is ready.
- MASTER_ONLY with
server_decrypt_export=true: server decrypts private key and returns plaintext to the device. - MASTER_ONLY with
server_decrypt_export=false:403withCERTS::EXPORT_FORBIDDEN. - If device wrapping is pending (
enc_data_keysentinel = 48 zero bytes):409withDEVICES::WRAP_PENDING.
Query params
pack=download— if provided, adds aContent-Dispositionattachment header with a descriptive filename.
Responses
-
Success (AEAD),
200:{
"data": {
"wrap_alg": "x25519-v1",
"enc_scheme": "aes256gcm",
"device_keyfp_b64": "...",
"enc_data_key_b64": "...",
"enc_privkey_b64": "...",
"privkey_nonce_b64": "...",
"privkey_tag_b64": "..."
}
} -
Success (MASTER_ONLY plaintext),
200:{
"data": {
"enc_scheme": "plaintext",
"private_key_der_b64": "...",
"certificate_pem": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n"
}
} -
Error (pending wrap),
409:{ "error": { "code": my_errors::DEVICES::WRAP_PENDING, "what": "Device wrap pending" } } -
Error (export forbidden),
403:{ "error": { "code": my_errors::CERTS::EXPORT_FORBIDDEN, "what": "Server-decrypted export disabled by policy" } } -
Error (no encrypted key available),
404:{ "error": { "code": my_errors::GENERAL::NOT_FOUND, "what": "Encrypted private key not available" } }
Notes
- When
pack=downloadis used, the response setsContent-Dispositionto an attachment filename like:cert_<id>_bundle.json(AEAD)cert_<id>_plaintext.json(MASTER_ONLY plaintext)
- The device must poll updates or retry if
409 WRAP_PENDINGis returned; when the device-wrapped key is created, the200AEAD bundle becomes available.
API Keys (ApikeysHandler)
Paths
/apiv1/users/:user_id/apikeys/apiv1/users/:user_id/apikeys/:apikey_id
Methods
GET /.../apikeys— List API keysPOST /.../apikeys— Create API keyDELETE /.../apikeys/:apikey_id— Revoke API key
Auth
- Requires user session; keys are scoped to the user.
Certificates (CertificatesHandler)
Paths
/apiv1/users/:user_id/certificates— List/create certificates/apiv1/users/:user_id/acme-accounts/:acme_account_id/certificates— Manage by ACME account/apiv1/users/:user_id/certificates/:certificate_id— Detail/delete/update/apiv1/users/:user_id/certificates/:certificate_id/issues— List or create issuance attempts
Auth
- Requires user session.
Notes
- “Issues” resource (plural) tracks issuance attempts and renewals. POST typically initiates an issuance/renewal for the certificate.
Examples
-
Create certificate record (ACME-backed or self-signed depending on account):
- Request:
POST /apiv1/users/1/certificates - Body:
{
"domain_name": "example.com",
"sans": ["www.example.com", "api.example.com"],
"acct_id": 42,
"action": "create",
"organization": "Example Inc",
"organizational_unit": "IT",
"country": "US",
"state": "CA",
"locality": "San Jose"
} - Response
200:{ "data": { "id": 1001, "domain_name": "example.com", "acct_id": 42, "self_signed": false, "verified": false, "sans": ["www.example.com","api.example.com"], "created_at": 1736900000 } }
- Request:
-
List issuance histories for a certificate:
{
"data": [
{
"history_id": 501,
"status": "SUCCESS",
"started_at": 1736900000,
"completed_at": 1736900015,
"log": "Issued via Let's Encrypt"
}
]
}
The remaining sections continue in the repository version located at ai_docs/HTTP_API_REFERENCE.md.
✅ For the most up-to-date version with sections beyond the excerpt above (payments, invoices, and roadmap notes), see the source file in ai_docs/HTTP_API_REFERENCE.md.