{"openapi":"3.1.0","info":{"title":"Nimbio Public API","description":"Programmatic access to your Nimbio keys, latches, members, and opens.\n\n**Authentication** — every endpoint (except `/healthz`) takes a bearer token:\n`Authorization: Bearer nimbio_test_…` or `nimbio_live_…`. Click **Authorize**\nand paste a key to try calls here.\n\n**Test vs live** — a `nimbio_test_*` key runs the full pipeline (auth, rate\nlimit, scope, validation) but never fires a gate, sends a message, or mutates a\nmember: writes come back `simulated` / `would_*`. Use a test key to explore\nsafely; switch to a `nimbio_live_*` key only when you want real side effects.\n\n**Account vs community keys** — there are two key types. The `/v1/account/*`\nendpoints (your keys and opening your own latches) require an account-scoped key;\nthe `/v1/community/*` endpoints require a community-scoped key (created by a\ncommunity manager in the admin portal). `/v1/me` works with either — its `key.type`\nfield tells you which one you're holding.\n","version":"0.1.0"},"paths":{"/healthz":{"get":{"summary":"Healthz","operationId":"healthz_healthz_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/me":{"get":{"tags":["Account"],"summary":"Who am I","operationId":"me_v1_me_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Key metadata and usage counters.","content":{"application/json":{"schema":{},"example":{"account_id":"a1b2…","key":{"api_key_id":"k1…","prefix":"nimbio_test_ab12cd34","name":"Integration","mode":"test","type":"account","self_service":false,"last_used_datetime":"2026-06-10T12:00:00+00:00","minute_limit":60,"minute_count":1,"month_limit":10000,"month_count":42}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"example":{"error":{"code":"unauthorized","message":"Invalid API key","request_id":"b1c2…"}}}}},"429":{"description":"Rate limit exceeded — see Retry-After.","content":{"application/json":{"example":{"error":{"code":"rate_limited","message":"Too many requests","request_id":"b1c2…"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"bearerAuth":[]}]}},"/v1/account/keys":{"get":{"tags":["Account"],"summary":"List your keys","description":"Every Nimbio key on your account, with its latches nested. Hidden keys are\nexcluded unless `include_hidden=true`.","operationId":"list_account_keys_v1_account_keys_get","parameters":[{"name":"include_hidden","in":"query","required":false,"schema":{"type":"boolean","description":"Include keys the user has hidden (default: exclude).","default":false,"title":"Include Hidden"},"description":"Include keys the user has hidden (default: exclude)."},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Your keys, each with its latches nested.","content":{"application/json":{"schema":{},"example":{"keys":[{"id":"k1…","name":"Home","home":"123 Main St","disabled":false,"hidden":false,"pending":false,"parent_name":"Maple Court Master","latches":[{"id":"l1…","name":"Front Gate","offline":false,"location":"Entrance","held_open":false}]}]}}}},"403":{"description":"This API key is bound to a community; use an account key.","content":{"application/json":{"example":{"error":{"code":"not_account_key","message":"This API key is bound to a community; use an account key","request_id":"b1c2…"}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"example":{"error":{"code":"unauthorized","message":"Invalid API key","request_id":"b1c2…"}}}}},"429":{"description":"Rate limit exceeded — see Retry-After.","content":{"application/json":{"example":{"error":{"code":"rate_limited","message":"Too many requests","request_id":"b1c2…"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"bearerAuth":[]}]}},"/v1/account/keys/{key_id}/latches/{latch_id}/open":{"post":{"tags":["Account"],"summary":"Open one of your latches","description":"Open a latch using one of your own keys.\n\nTest mode: writes `test_simulated`, returns 200 with `would_open` — box never\nfires (the latch permission is authorized on the backend only for live opens).\nLive mode: synchronous — blocks until the open settles, then returns 200 when\nthe box confirms, 403 when denied, 409 when the latch requires an NFC scan, or\n504 when the gate does not confirm within the timeout (`did_not_open`).","operationId":"open_account_latch_v1_account_keys__key_id__latches__latch_id__open_post","parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string","title":"Key Id"}},{"name":"latch_id","in":"path","required":true,"schema":{"type":"string","title":"Latch Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body","properties":{"note":{"type":"string","description":"Optional note recorded with the open in the call log."},"idempotency_key":{"type":"string","description":"Optional client token (captured, not yet de-duped)."}}},"example":{"note":"Front gate test"}}},"required":false},"responses":{"200":{"description":"Opened (live, box confirmed) or simulated (test key).","content":{"application/json":{"schema":{},"example":{"result":"opened","request_id":"b1c2…","key_log_id":9001}}}},"403":{"description":"Not permitted, the key can't open this latch, or the key is bound to a community (code `not_account_key`).","content":{"application/json":{"example":{"error":{"code":"open_denied","message":"Not permitted now","request_id":"b1c2…"}}}}},"409":{"description":"This latch requires an in-person NFC scan.","content":{"application/json":{"example":{"error":{"code":"scan_required","message":"Latch requires an NFC scan","request_id":"b1c2…"}}}}},"504":{"description":"The gate did not confirm the open within the timeout.","content":{"application/json":{"example":{"error":{"code":"did_not_open","message":"Box did not acknowledge the open within the timeout","request_id":"b1c2…"}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"example":{"error":{"code":"unauthorized","message":"Invalid API key","request_id":"b1c2…"}}}}},"429":{"description":"Rate limit exceeded — see Retry-After.","content":{"application/json":{"example":{"error":{"code":"rate_limited","message":"Too many requests","request_id":"b1c2…"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"bearerAuth":[]}]}},"/v1/community/gate-status":{"get":{"tags":["Community · Reads"],"summary":"Get gate status","description":"Latest known sensed state per latch in the key's community.","operationId":"get_gate_status_v1_community_gate_status_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Latest sensed state per latch.","content":{"application/json":{"schema":{},"example":{"latches":[{"latch_id":"l1…","latch_name":"Front Gate","status":"closed","offline":false,"latch_status_current_message":"Closed"}]}}}},"403":{"description":"This API key is not bound to a community.","content":{"application/json":{"example":{"error":{"code":"not_community_key","message":"This API key is not bound to a community","request_id":"b1c2…"}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"example":{"error":{"code":"unauthorized","message":"Invalid API key","request_id":"b1c2…"}}}}},"429":{"description":"Rate limit exceeded — see Retry-After.","content":{"application/json":{"example":{"error":{"code":"rate_limited","message":"Too many requests","request_id":"b1c2…"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"bearerAuth":[]}]}},"/v1/community/members":{"get":{"tags":["Community · Reads"],"summary":"List members","description":"Pending / accepted / removed members for the key's community.","operationId":"get_members_v1_community_members_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Pending / accepted / removed members.","content":{"application/json":{"schema":{},"example":{"accepted":[{"account_community_id":4021,"first_name":"Dana","last_name":"Lee","phone_number":"+15551234567"}],"unaccepted":[],"removed":[]}}}},"403":{"description":"This API key is not bound to a community.","content":{"application/json":{"example":{"error":{"code":"not_community_key","message":"This API key is not bound to a community","request_id":"b1c2…"}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"example":{"error":{"code":"unauthorized","message":"Invalid API key","request_id":"b1c2…"}}}}},"429":{"description":"Rate limit exceeded — see Retry-After.","content":{"application/json":{"example":{"error":{"code":"rate_limited","message":"Too many requests","request_id":"b1c2…"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"bearerAuth":[]}]},"post":{"tags":["Community · Writes"],"summary":"Add a member by phone","description":"Add a member to the community by phone number and grant them keys.\n\nIf the phone number has no Nimbio account, a pending account is created.\n`key_ids` are community key ids (from /v1/community/key-statuses); each\ngrants the member access via a new key on their account.\n\nTest mode: validate phone + key scope, write `test_simulated`, return 200 —\nno account is created and no keys are granted.","operationId":"add_member_v1_community_members_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body","properties":{"phone_number":{"type":"string","description":"E.164 phone, e.g. +15551234567."},"key_ids":{"type":"array","items":{"type":"string"},"description":"Community key ids (from key-statuses) to grant."}},"required":["phone_number","key_ids"]},"example":{"phone_number":"+15551234567","key_ids":["{{community_key_id}}"]}}},"required":true},"responses":{"201":{"description":"Live: member added + keys granted.","content":{"application/json":{"schema":{},"example":{"result":"member_added","request_id":"b1c2…","account_community_id":4021,"account_id":"a1…","keys":[{"key_id":"k1…"}]}}}},"200":{"description":"Test: validated — nothing created.","content":{"application/json":{"example":{"result":"simulated","request_id":"b1c2…"}}}},"400":{"description":"Missing phone_number or key_ids.","content":{"application/json":{"example":{"error":{"code":"missing_phone_number","message":"A 'phone_number' is required","request_id":"b1c2…"}}}}},"403":{"description":"This API key is not bound to a community.","content":{"application/json":{"example":{"error":{"code":"not_community_key","message":"This API key is not bound to a community","request_id":"b1c2…"}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"example":{"error":{"code":"unauthorized","message":"Invalid API key","request_id":"b1c2…"}}}}},"429":{"description":"Rate limit exceeded — see Retry-After.","content":{"application/json":{"example":{"error":{"code":"rate_limited","message":"Too many requests","request_id":"b1c2…"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"bearerAuth":[]}]}},"/v1/community/key-statuses":{"get":{"tags":["Community · Reads"],"summary":"Get key + latch statuses","description":"All key + latch statuses (disabled, offline, held_open, disabled_until).","operationId":"get_key_statuses_v1_community_key_statuses_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"All keys and latches with disabled / offline / held-open state.","content":{"application/json":{"schema":{},"example":{"keys":[{"id":"k1…","name":"Front Gate Key"}],"hold_opens":{}}}}},"403":{"description":"This API key is not bound to a community.","content":{"application/json":{"example":{"error":{"code":"not_community_key","message":"This API key is not bound to a community","request_id":"b1c2…"}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"example":{"error":{"code":"unauthorized","message":"Invalid API key","request_id":"b1c2…"}}}}},"429":{"description":"Rate limit exceeded — see Retry-After.","content":{"application/json":{"example":{"error":{"code":"rate_limited","message":"Too many requests","request_id":"b1c2…"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"bearerAuth":[]}]}},"/v1/community/keys":{"get":{"tags":["Community · Reads"],"summary":"List keys with restrictions","description":"List every key in the key's community with its access restrictions.\n\nRestriction-focused companion to `/v1/community/key-statuses`: that endpoint\nreports live state (offline, held-open) for monitoring; this one reports the\nconfigured limits on each key — whether it is disabled, time-restricted\n(temporal windows), expiring (`expiry`), depth-limited for resharing\n(`sharing.max_share_depth`), or per-latch restricted (scan-only, NFC-scan\nrequired, a limited number of uses).","operationId":"list_community_keys_v1_community_keys_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Every key in the community with its access restrictions — temporal windows, expiry, share depth, scan-only / NFC-scan, and limited uses.","content":{"application/json":{"schema":{},"example":{"result":"ok","keys":[{"id":"k1c2…","name":"Front Gate Key","disabled":false,"hidden":false,"pending":false,"is_favorite":false,"sharing":{"allow_subkeys":true,"max_share_depth":2,"max_share_depth_enabled":true,"parent_name":"Alice Smith"},"expiry":{"expires_at":"2026-12-31 23:59:59","active":true},"temporal":{"enabled":true,"windows":[{"days":"Mon, Wed, Fri","start_date":"2026-01-01","recurring_week":1,"times":[{"start":"09:00:00","end":"17:00:00"}]}]},"latches":[{"latch_id":"l9a8…","name":"Front Gate","scan_only":false,"require_nfc_scan":false,"numbered_use":5}]}]}}}},"403":{"description":"This API key is not bound to a community.","content":{"application/json":{"example":{"error":{"code":"not_community_key","message":"This API key is not bound to a community","request_id":"b1c2…"}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"example":{"error":{"code":"unauthorized","message":"Invalid API key","request_id":"b1c2…"}}}}},"429":{"description":"Rate limit exceeded — see Retry-After.","content":{"application/json":{"example":{"error":{"code":"rate_limited","message":"Too many requests","request_id":"b1c2…"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"bearerAuth":[]}]}},"/v1/community/latches/{latch_id}/open":{"post":{"tags":["Community · Writes"],"summary":"Issue an open","description":"Issue an open on a latch in the key's community.\n\nTest mode: validate scope, write `test_simulated`, return 200 — box never fires.\nLive mode: synchronous — blocks until the open settles, then returns 200 when\nthe box confirms it opened, 403 when the open is denied, or 504 when the gate\ndoes not confirm within the timeout (`did_not_open`).","operationId":"issue_open_v1_community_latches__latch_id__open_post","parameters":[{"name":"latch_id","in":"path","required":true,"schema":{"type":"string","title":"Latch Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body","properties":{"note":{"type":"string","description":"Optional note recorded with the open in the call log."},"idempotency_key":{"type":"string","description":"Optional client token (captured, not yet de-duped)."}}},"example":{"note":"Front gate test"}}},"required":false},"responses":{"200":{"description":"Opened (live, box confirmed) or simulated (test key).","content":{"application/json":{"schema":{},"example":{"result":"opened","request_id":"b1c2…","key_log_id":9001}}}},"403":{"description":"This API key is not bound to a community.","content":{"application/json":{"example":{"error":{"code":"not_community_key","message":"This API key is not bound to a community","request_id":"b1c2…"}}}}},"504":{"description":"The gate did not confirm the open within the timeout.","content":{"application/json":{"example":{"error":{"code":"did_not_open","message":"Box did not acknowledge the open within the timeout","request_id":"b1c2…"}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"example":{"error":{"code":"unauthorized","message":"Invalid API key","request_id":"b1c2…"}}}}},"429":{"description":"Rate limit exceeded — see Retry-After.","content":{"application/json":{"example":{"error":{"code":"rate_limited","message":"Too many requests","request_id":"b1c2…"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"bearerAuth":[]}]}},"/v1/community/messages":{"post":{"tags":["Community · Writes"],"summary":"Message all members","description":"Send a message to all community members.\n\nTest mode: validated via dry_run — no push is sent. Live mode: delivered.","operationId":"send_message_v1_community_messages_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body","properties":{"message":{"type":"string","description":"Message body. Your name is appended automatically."}},"required":["message"]},"example":{"message":"Pool maintenance Thursday 9am–noon."}}},"required":true},"responses":{"200":{"description":"Sent (live) or validated (test).","content":{"application/json":{"schema":{},"example":{"result":"sent","request_id":"b1c2…"}}}},"400":{"description":"Missing/empty message.","content":{"application/json":{"example":{"error":{"code":"missing_message","message":"A non-empty 'message' is required","request_id":"b1c2…"}}}}},"403":{"description":"This API key is not bound to a community.","content":{"application/json":{"example":{"error":{"code":"not_community_key","message":"This API key is not bound to a community","request_id":"b1c2…"}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"example":{"error":{"code":"unauthorized","message":"Invalid API key","request_id":"b1c2…"}}}}},"429":{"description":"Rate limit exceeded — see Retry-After.","content":{"application/json":{"example":{"error":{"code":"rate_limited","message":"Too many requests","request_id":"b1c2…"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"bearerAuth":[]}]}},"/v1/community/members/{account_community_id}/grant-keys":{"post":{"tags":["Community · Writes"],"summary":"Grant keys to a member","description":"Grant additional keys to an existing accepted member.\n\n`key_ids` are community key ids (from /v1/community/key-statuses). Each that\nthe member does not already have is granted; a previously disabled key is\nre-enabled; keys they already hold are left unchanged. Use POST\n/v1/community/members to add a brand-new member.\n\nTest mode: validate scope, write `test_simulated`, return 200 — no change.","operationId":"grant_member_keys_v1_community_members__account_community_id__grant_keys_post","parameters":[{"name":"account_community_id","in":"path","required":true,"schema":{"type":"integer","title":"Account Community Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body","properties":{"key_ids":{"type":"array","items":{"type":"string"},"description":"Community key ids to grant."}},"required":["key_ids"]},"example":{"key_ids":["{{community_key_id}}"]}}},"required":true},"responses":{"200":{"description":"Keys granted (live) or validated (test).","content":{"application/json":{"schema":{},"example":{"result":"keys_granted","request_id":"b1c2…","account_community_id":4021,"granted":{"created":["k1…"],"enabled":[],"exists":[]}}}}},"400":{"description":"Missing key_ids.","content":{"application/json":{"example":{"error":{"code":"missing_key_ids","message":"A non-empty 'key_ids' list is required","request_id":"b1c2…"}}}}},"403":{"description":"This API key is not bound to a community.","content":{"application/json":{"example":{"error":{"code":"not_community_key","message":"This API key is not bound to a community","request_id":"b1c2…"}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"example":{"error":{"code":"unauthorized","message":"Invalid API key","request_id":"b1c2…"}}}}},"429":{"description":"Rate limit exceeded — see Retry-After.","content":{"application/json":{"example":{"error":{"code":"rate_limited","message":"Too many requests","request_id":"b1c2…"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"bearerAuth":[]}]}},"/v1/community/members/{account_community_id}/revoke-keys":{"post":{"tags":["Community · Writes"],"summary":"Revoke keys from a member","description":"Revoke community keys from a member.\n\n`key_ids` are community key ids (from /v1/community/key-statuses). By\ndefault only those keys are removed and the member stays active; pass\n`remove_member: true` to remove the member from the community entirely.\n\nTest mode: validate scope, write `test_simulated`, return 200 — no change.","operationId":"revoke_member_keys_v1_community_members__account_community_id__revoke_keys_post","parameters":[{"name":"account_community_id","in":"path","required":true,"schema":{"type":"integer","title":"Account Community Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body","properties":{"key_ids":{"type":"array","items":{"type":"string"},"description":"Community key ids to revoke."},"remove_member":{"type":"boolean","default":false,"description":"True removes the member from the community entirely."}},"required":["key_ids"]},"example":{"key_ids":["{{community_key_id}}"],"remove_member":false}}},"required":true},"responses":{"200":{"description":"Keys revoked (live) or validated (test).","content":{"application/json":{"schema":{},"example":{"result":"keys_revoked","request_id":"b1c2…","account_community_id":4021,"revoked_key_ids":["k1…"],"remove_member":false}}}},"400":{"description":"Missing key_ids.","content":{"application/json":{"example":{"error":{"code":"missing_key_ids","message":"A non-empty 'key_ids' list is required","request_id":"b1c2…"}}}}},"403":{"description":"This API key is not bound to a community.","content":{"application/json":{"example":{"error":{"code":"not_community_key","message":"This API key is not bound to a community","request_id":"b1c2…"}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"example":{"error":{"code":"unauthorized","message":"Invalid API key","request_id":"b1c2…"}}}}},"429":{"description":"Rate limit exceeded — see Retry-After.","content":{"application/json":{"example":{"error":{"code":"rate_limited","message":"Too many requests","request_id":"b1c2…"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"bearerAuth":[]}]}},"/v1/community/members/{account_community_id}/keys-disabled":{"post":{"tags":["Community · Writes"],"summary":"Disable / enable a member's keys","description":"Disable or enable a member's keys (reversible — keys are not removed).\n\n`key_ids` are community key ids (from /v1/community/key-statuses). `disabled`\nis required: true disables the member's keys, false re-enables them.\n\nTest mode: validate scope, write `test_simulated`, return 200 — no change.","operationId":"set_member_keys_disabled_v1_community_members__account_community_id__keys_disabled_post","parameters":[{"name":"account_community_id","in":"path","required":true,"schema":{"type":"integer","title":"Account Community Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body","properties":{"key_ids":{"type":"array","items":{"type":"string"},"description":"Community key ids to toggle."},"disabled":{"type":"boolean","description":"True disables the keys; False re-enables them."}},"required":["key_ids","disabled"]},"example":{"key_ids":["{{community_key_id}}"],"disabled":true}}},"required":true},"responses":{"200":{"description":"Keys toggled (live) or validated (test).","content":{"application/json":{"schema":{},"example":{"result":"keys_disabled","request_id":"b1c2…","account_community_id":4021}}}},"400":{"description":"Missing key_ids or disabled.","content":{"application/json":{"example":{"error":{"code":"missing_disabled","message":"A boolean 'disabled' field is required","request_id":"b1c2…"}}}}},"403":{"description":"This API key is not bound to a community.","content":{"application/json":{"example":{"error":{"code":"not_community_key","message":"This API key is not bound to a community","request_id":"b1c2…"}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"example":{"error":{"code":"unauthorized","message":"Invalid API key","request_id":"b1c2…"}}}}},"429":{"description":"Rate limit exceeded — see Retry-After.","content":{"application/json":{"example":{"error":{"code":"rate_limited","message":"Too many requests","request_id":"b1c2…"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"bearerAuth":[]}]}},"/v1/community/members/{account_community_id}/access-logs":{"get":{"tags":["Community · Logs"],"summary":"Member access logs","description":"A member's access logs (key opens) for a 30-day window.\n\n`window` selects the range: `last_30` (default, the last 30 days), `30_60`\n(30-60 days ago), or `60_90` (60-90 days ago). Scope is the member's key(s)\nplus every descendant key (people they re-shared with); each row names the\nactual opener. Requires the community's Access Log History setting to be on.\nReads behave identically for test and live keys.","operationId":"get_member_access_logs_v1_community_members__account_community_id__access_logs_get","parameters":[{"name":"account_community_id","in":"path","required":true,"schema":{"type":"integer","title":"Account Community Id"}},{"name":"window","in":"query","required":false,"schema":{"type":"string","pattern":"^(last_30|30_60|60_90)$","default":"last_30","title":"Window"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"A member's opens for the selected 30-day window.","content":{"application/json":{"schema":{},"example":{"result":"ok","account_community_id":4021,"window":"last_30","from":"2026-05-11","to":"2026-06-10","truncated":false,"logs":[{"key_name":"Front Gate","latch_name":"Front Gate","datetime":"2026-06-09T18:02:00+00:00","open_desc":"Opened","open_result":"success","user":"Dana Lee","location":"Front Gate","reason_desc":"","source":"app"}]}}}},"404":{"description":"No such member.","content":{"application/json":{"example":{"error":{"code":"member_not_found","message":"Member not found","request_id":"b1c2…"}}}}},"403":{"description":"This API key is not bound to a community.","content":{"application/json":{"example":{"error":{"code":"not_community_key","message":"This API key is not bound to a community","request_id":"b1c2…"}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"example":{"error":{"code":"unauthorized","message":"Invalid API key","request_id":"b1c2…"}}}}},"429":{"description":"Rate limit exceeded — see Retry-After.","content":{"application/json":{"example":{"error":{"code":"rate_limited","message":"Too many requests","request_id":"b1c2…"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"bearerAuth":[]}]}},"/v1/community/access-logs":{"get":{"tags":["Community · Logs"],"summary":"Community access log","description":"The community's full access log (gate opens) for the last 90 days,\npaginated 1000 per page (`page` is 0-indexed; `has_more` says whether\nanother page exists). Each row includes the opener's `phone` when on file.\nCommercial communities name the actual opener; residential communities use a\n'<owner> Keychain' grouping. Requires the community's Access Log History on.","operationId":"get_community_access_log_v1_community_access_logs_get","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Page"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Community-wide gate opens, 1000 per page.","content":{"application/json":{"schema":{},"example":{"result":"ok","page":0,"has_more":false,"from":"2026-03-12","to":"2026-06-10","logs":[{"key_name":"Front Gate","latch_name":"Front Gate","datetime":"2026-06-09T18:02:00+00:00","open_desc":"Opened","open_result":"success","user":"Dana Lee","phone":"+15551234567","location":"Front Gate","reason_desc":"","source":"app"}]}}}},"403":{"description":"This API key is not bound to a community.","content":{"application/json":{"example":{"error":{"code":"not_community_key","message":"This API key is not bound to a community","request_id":"b1c2…"}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"example":{"error":{"code":"unauthorized","message":"Invalid API key","request_id":"b1c2…"}}}}},"429":{"description":"Rate limit exceeded — see Retry-After.","content":{"application/json":{"example":{"error":{"code":"rate_limited","message":"Too many requests","request_id":"b1c2…"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"bearerAuth":[]}]}},"/v1/community/gate-status-log":{"get":{"tags":["Community · Logs"],"summary":"Gate status-change log","description":"The community's gate status-change log (physical open/closed transitions)\nfor the last 90 days, paginated 1000 per page (`page` 0-indexed; `has_more`\nflags another page). Distinct from /v1/community/gate-status (current state).\nRequires the community's Access Log History on.","operationId":"get_community_gate_status_log_v1_community_gate_status_log_get","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Page"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Physical open/closed transitions, 1000 per page.","content":{"application/json":{"schema":{},"example":{"result":"ok","page":0,"has_more":false,"from":"2026-03-12","to":"2026-06-10","logs":[{"datetime":"2026-06-09T18:02:05+00:00","latch_name":"Front Gate","status_label":"Opened","sense_line":1,"state":"open"}]}}}},"403":{"description":"This API key is not bound to a community.","content":{"application/json":{"example":{"error":{"code":"not_community_key","message":"This API key is not bound to a community","request_id":"b1c2…"}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"example":{"error":{"code":"unauthorized","message":"Invalid API key","request_id":"b1c2…"}}}}},"429":{"description":"Rate limit exceeded — see Retry-After.","content":{"application/json":{"example":{"error":{"code":"rate_limited","message":"Too many requests","request_id":"b1c2…"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"bearerAuth":[]}]}}},"components":{"schemas":{"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}},"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"A nimbio_test_… or nimbio_live_… API key."}}},"tags":[{"name":"Account","description":"Your account: key metadata (`/v1/me`, any key), your keys and their latches, account opens, and your own call log. The keys and open endpoints require an account-scoped key."},{"name":"Community · Reads","description":"Read a community's gate status, members, and key/latch statuses. Requires a community-scoped key."},{"name":"Community · Writes","description":"Issue opens, message members, and manage member keys. Test-mode keys validate scope but never mutate or fire a gate."},{"name":"Community · Logs","description":"Access-log and gate-status-log history. Requires the community's Access Log History setting to be enabled."}],"servers":[{"url":"/","description":"This environment (the host you're viewing)"},{"url":"https://api.nimbio.com","description":"Production"},{"url":"https://api.nimbio.dev","description":"Dev"},{"url":"http://localhost:8000","description":"Local"}],"x-tagGroups":[{"name":"Account API","tags":["Account"]},{"name":"Community API","tags":["Community · Reads","Community · Writes","Community · Logs"]}]}