{"openapi":"3.1.0","info":{"title":"Flanner control plane","version":"1"},"paths":{"/v1/invitations/accept":{"post":{"summary":"Accept","description":"Join an organization and enrol the machine doing it, in one step.\n\nThe invitation is the only credential, and it is spent here.\nSplitting this into \"join\" then \"enrol\" would need a second secret\nto carry the new member between the two, which is a worse thing to\nput in an email than the one we already send.","operationId":"accept_v1_invitations_accept_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AcceptInvitation"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Accept V1 Invitations Accept Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/devices/enroll":{"post":{"summary":"Enroll","description":"Redeem an enrolment code and return this device's first entitlement.","operationId":"enroll_v1_devices_enroll_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrollDevice"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Enroll V1 Devices Enroll Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/entitlements":{"post":{"summary":"Refresh","description":"Reissue an entitlement to a device that proves it holds its key.","operationId":"refresh_v1_entitlements_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Refresh V1 Entitlements Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/devices/codes":{"post":{"summary":"Mint Code","description":"Mint an enrolment code for another of the caller's own machines.\n\nThis is what makes the console self-service. A member with one\nworking install adds the next one themselves, because the machine\nthey already hold vouches for the request.","operationId":"mint_code_v1_devices_codes_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Mint Code V1 Devices Codes Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/devices/list":{"post":{"summary":"List Own Devices","description":"Every machine enrolled under the caller's membership.","operationId":"list_own_devices_v1_devices_list_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response List Own Devices V1 Devices List Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/devices/keyring":{"post":{"summary":"Keyring","description":"Every enrolled device's public key, for this caller's organization.\n\nWhat a device needs to verify a teammate's artifact without asking\nanyone at the moment of verification (PRD §14.4). It matters that\nthis covers the whole organization and not just the peer in front\nof you: a peer relays artifacts authored by devices you may never\nconnect to directly, and each is verified against its own author's\nkey.\n\nPublic keys only, so this discloses which machines exist and\nnothing they could be impersonated with.","operationId":"keyring_v1_devices_keyring_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Keyring V1 Devices Keyring Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/devices/revoke":{"post":{"summary":"Revoke","description":"Retire a machine. Members may retire their own, admins any.\n\nA lost laptop is what this exists for, and the person who lost it\nshould not have to wait for an operator to act on it.","operationId":"revoke_v1_devices_revoke_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Revoke V1 Devices Revoke Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/auth/link":{"post":{"summary":"Request Link","description":"Mail a single-use link to an address.\n\nAlways answers the same way, whether or not the address is known.\nSaying which addresses have accounts would turn this into a way to\ntest whether a colleague uses flanner, and it is unauthenticated by\nnecessity.","operationId":"request_link_v1_auth_link_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestSignInLink"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Request Link V1 Auth Link Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/auth/sign-up":{"post":{"summary":"Sign Up","description":"Create a team from a verified address, and start its trial.\n\nThe last thing only an operator could do. Safe to expose because\nit needs a link somebody proved they can read, and it starts a\ntrial rather than handing out free capacity.","operationId":"sign_up_v1_auth_sign_up_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompleteSignUp"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Sign Up V1 Auth Sign Up Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/auth/redeem":{"post":{"summary":"Redeem","description":"Spend a sign-in link and get a code to enrol this machine.\n\nThe bridge from a person to a device: signing in exists so a\nmachine can join, and joining enrols the machine the person is\nactually sitting at.","operationId":"redeem_v1_auth_redeem_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RedeemLink"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Redeem V1 Auth Redeem Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/relay/access":{"post":{"summary":"Relay Access","description":"Whether the endpoint asking to use the relay may have it.\n\nThe relay expects a 200 whose body is exactly ``true``, and treats\neverything else as a refusal. So this never raises: a 500 would\ndeny, but it would also make an outage look like a policy, and the\nrelay logs would blame the wrong thing.\n\nNot signed like the rest of this API. The caller is our own relay,\nnot a device, and it has no key of ours; a shared secret is what it\ncan present. Being wrong here costs bandwidth, not access, because\nthe relay carries traffic it cannot read either way.","operationId":"relay_access_v1_relay_access_post","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/v1/billing/webhook":{"post":{"summary":"Named","operationId":"named_v1_billing_webhook_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Named V1 Billing Webhook Post"}}}}}}},"/v1/billing/webhook/paystack":{"post":{"summary":"Named","operationId":"named_v1_billing_webhook_paystack_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Named V1 Billing Webhook Paystack Post"}}}}}}},"/v1/billing/checkout":{"post":{"summary":"Billing Checkout","description":"A link for an admin to start or change a subscription.\n\nThe interval is validated here, before a provider sees it. An\nunrecognised one is refused rather than defaulted: silently\ncharging monthly for an annual request, or the reverse, is a\nbilling error nobody notices until an invoice is wrong.","operationId":"billing_checkout_v1_billing_checkout_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Billing Checkout V1 Billing Checkout Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/billing/status":{"post":{"summary":"Billing Status","description":"What this organization is entitled to, and until when.","operationId":"billing_status_v1_billing_status_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Billing Status V1 Billing Status Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/members/invite":{"post":{"summary":"Invite","description":"Invite someone. Consumes no seat until they accept (§18.1).","operationId":"invite_v1_members_invite_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Invite V1 Members Invite Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/members/list":{"post":{"summary":"List Org Members","description":"Who is in this organization, and how many seats that comes to.","operationId":"list_org_members_v1_members_list_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response List Org Members V1 Members List Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/members/remove":{"post":{"summary":"Remove","description":"Remove a member, revoking their devices in the same operation.","operationId":"remove_v1_members_remove_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Remove V1 Members Remove Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sign-in":{"get":{"summary":"Sign In Page","operationId":"sign_in_page_sign_in_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}},"post":{"summary":"Sign In","description":"Mail a link. Answers the same way whatever the address.\n\nOtherwise this page is a way to test whether a colleague uses\nflanner, and it is unauthenticated by necessity.","operationId":"sign_in_sign_in_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_sign_in_sign_in_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/{token}":{"get":{"summary":"Redeem","description":"Spend a mailed link.\n\nA sign-up link is not spent here. It has one use and creating the\nteam needs it, so this only asks whether the token is a live\nsign-up link and, if so, shows the form that will spend it.","operationId":"redeem_auth__token__get","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Redeem Auth  Token  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sign-up":{"get":{"summary":"Sign Up Page","operationId":"sign_up_page_sign_up_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}},"post":{"summary":"Sign Up Request","description":"Mail a link that can create a team.\n\nAnswers the same way whatever the address, for the same reason\nsigning in does: this page is unauthenticated, and a different\nanswer for a known address would say who already has an account.","operationId":"sign_up_request_sign_up_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_sign_up_request_sign_up_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sign-up/team":{"post":{"summary":"Sign Up Complete","description":"Spend the link, create the team, and sign the browser in.\n\nNo CSRF token guards this, because there is no session yet to bind\none to. What stands in for it is the link itself: a submission\nwithout a live sign-up token creates nothing.","operationId":"sign_up_complete_sign_up_team_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_sign_up_complete_sign_up_team_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sign-out":{"post":{"summary":"Sign Out","operationId":"sign_out_sign_out_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_sign_out_sign_out_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/":{"get":{"summary":"Overview","operationId":"overview__get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/members":{"get":{"summary":"Members Page","operationId":"members_page_members_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/members/invite":{"post":{"summary":"Invite","operationId":"invite_members_invite_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_invite_members_invite_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/members/resend":{"post":{"summary":"Resend","description":"Send a pending invitation again, with a fresh token.\n\nSeparate from remove-then-invite, which was the only way to do this\nand is a poor substitute: it reads as destructive, and on an active\nmember it genuinely is — removal revokes every device they enrolled.","operationId":"resend_members_resend_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_resend_members_resend_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/members/remove":{"post":{"summary":"Remove","operationId":"remove_members_remove_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_remove_members_remove_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/devices":{"get":{"summary":"Devices Page","operationId":"devices_page_devices_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/devices/revoke":{"post":{"summary":"Revoke","operationId":"revoke_devices_revoke_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_revoke_devices_revoke_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/devices/add":{"post":{"summary":"Add Device","description":"Mint a code for the machine the person is sitting at.\n\nThe one thing a browser session can do that matters: a page cannot\nenrol a machine, but it can hand over a code to type on one.","operationId":"add_device_devices_add_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_add_device_devices_add_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/workspaces":{"get":{"summary":"Workspaces Page","description":"Workspaces and who may enter them. Never what is in them.","operationId":"workspaces_page_workspaces_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/workspaces/grant":{"post":{"summary":"Grant","operationId":"grant_workspaces_grant_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_grant_workspaces_grant_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/workspaces/create":{"post":{"summary":"Create Workspace","operationId":"create_workspace_workspaces_create_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_create_workspace_workspaces_create_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing":{"get":{"summary":"Billing Page","operationId":"billing_page_billing_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/billing/subscribe":{"post":{"summary":"Subscribe","description":"Start a subscription, on the provider's own hosted page.","operationId":"subscribe_billing_subscribe_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_subscribe_billing_subscribe_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/portal":{"post":{"summary":"Portal","description":"Send an existing customer to manage their own card and invoices.","operationId":"portal_billing_portal_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_portal_billing_portal_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/done":{"get":{"summary":"Billing Done","description":"Where the provider sends someone after they pay.\n\nThis existed as a URL in the checkout call and as nothing else, so\npaying ended on a 404. It deliberately does not claim the\nsubscription is active: the webhook decides that, and it may not have\narrived yet.","operationId":"billing_done_billing_done_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/billing/cancelled":{"get":{"summary":"Billing Cancelled","description":"Backing out of checkout is not an error, so it just goes back.","operationId":"billing_cancelled_billing_cancelled_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/audit":{"get":{"summary":"Audit Page","description":"Who changed access, and when (PRD §17.2).\n\nDeliberately coarse. It answers \"when did this device lose access\"\nand refuses to become a behavioural log, which is why there is no\nfilter by person and no export.","operationId":"audit_page_audit_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/privacy":{"get":{"summary":"Privacy","description":"What this service stores, and what it cannot (PRD §17.3).\n\nA page rather than a policy document, because the claim is checkable\nand the specifics are the point.","operationId":"privacy_privacy_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/health":{"get":{"summary":"Health","description":"Liveness only. Says nothing about who is using the service.\n\nAn unauthenticated endpoint that reported seat counts or key ids\nwould be a small, permanent information leak in exchange for\nconvenience nobody asked for.","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Health Health Get"}}}}}}}},"components":{"schemas":{"AcceptInvitation":{"properties":{"token":{"type":"string","minLength":1,"title":"Token"},"public_key":{"type":"string","minLength":1,"title":"Public Key"},"user_id":{"type":"string","minLength":1,"title":"User Id"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"platform":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Platform"}},"type":"object","required":["token","public_key","user_id"],"title":"AcceptInvitation","description":"Join an organization and enrol the machine doing it, in one step."},"Body_add_device_devices_add_post":{"properties":{"csrf":{"type":"string","title":"Csrf","default":""}},"type":"object","title":"Body_add_device_devices_add_post"},"Body_create_workspace_workspaces_create_post":{"properties":{"label":{"type":"string","title":"Label","default":""},"csrf":{"type":"string","title":"Csrf","default":""}},"type":"object","title":"Body_create_workspace_workspaces_create_post"},"Body_grant_workspaces_grant_post":{"properties":{"workspace_id":{"type":"string","title":"Workspace Id"},"membership_id":{"type":"string","title":"Membership Id"},"role":{"type":"string","title":"Role"},"csrf":{"type":"string","title":"Csrf","default":""}},"type":"object","required":["workspace_id","membership_id","role"],"title":"Body_grant_workspaces_grant_post"},"Body_invite_members_invite_post":{"properties":{"email":{"type":"string","title":"Email"},"csrf":{"type":"string","title":"Csrf","default":""}},"type":"object","required":["email"],"title":"Body_invite_members_invite_post"},"Body_portal_billing_portal_post":{"properties":{"csrf":{"type":"string","title":"Csrf","default":""}},"type":"object","title":"Body_portal_billing_portal_post"},"Body_remove_members_remove_post":{"properties":{"membership_id":{"type":"string","title":"Membership Id"},"csrf":{"type":"string","title":"Csrf","default":""}},"type":"object","required":["membership_id"],"title":"Body_remove_members_remove_post"},"Body_resend_members_resend_post":{"properties":{"membership_id":{"type":"string","title":"Membership Id"},"csrf":{"type":"string","title":"Csrf","default":""}},"type":"object","required":["membership_id"],"title":"Body_resend_members_resend_post"},"Body_revoke_devices_revoke_post":{"properties":{"device_id":{"type":"string","title":"Device Id"},"csrf":{"type":"string","title":"Csrf","default":""}},"type":"object","required":["device_id"],"title":"Body_revoke_devices_revoke_post"},"Body_sign_in_sign_in_post":{"properties":{"email":{"type":"string","title":"Email"}},"type":"object","required":["email"],"title":"Body_sign_in_sign_in_post"},"Body_sign_out_sign_out_post":{"properties":{"csrf":{"type":"string","title":"Csrf","default":""}},"type":"object","title":"Body_sign_out_sign_out_post"},"Body_sign_up_complete_sign_up_team_post":{"properties":{"token":{"type":"string","title":"Token"},"organization_name":{"type":"string","title":"Organization Name","default":""}},"type":"object","required":["token"],"title":"Body_sign_up_complete_sign_up_team_post"},"Body_sign_up_request_sign_up_post":{"properties":{"email":{"type":"string","title":"Email"}},"type":"object","required":["email"],"title":"Body_sign_up_request_sign_up_post"},"Body_subscribe_billing_subscribe_post":{"properties":{"interval":{"type":"string","title":"Interval","default":"monthly"},"csrf":{"type":"string","title":"Csrf","default":""}},"type":"object","title":"Body_subscribe_billing_subscribe_post"},"CompleteSignUp":{"properties":{"token":{"type":"string","minLength":1,"title":"Token"},"organization_name":{"type":"string","minLength":1,"title":"Organization Name"}},"type":"object","required":["token","organization_name"],"title":"CompleteSignUp","description":"Spend a sign-up link and name the organization it creates."},"EnrollDevice":{"properties":{"enrollment_code":{"type":"string","minLength":1,"title":"Enrollment Code"},"public_key":{"type":"string","minLength":1,"title":"Public Key"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"platform":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Platform"}},"type":"object","required":["enrollment_code","public_key"],"title":"EnrollDevice","description":"Redeem an enrolment code minted by a machine the member already holds."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"RedeemLink":{"properties":{"token":{"type":"string","minLength":1,"title":"Token"}},"type":"object","required":["token"],"title":"RedeemLink","description":"Spend a sign-in link."},"RequestSignInLink":{"properties":{"email":{"type":"string","minLength":1,"title":"Email"},"purpose":{"type":"string","title":"Purpose","default":"sign_in"}},"type":"object","required":["email"],"title":"RequestSignInLink","description":"Ask for a sign-in link by email."},"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"}}}}