Skip to content
HaneDOCS日本語

Hane Platform

Organizations, projects, and environments

The hierarchy of organizations, projects, and environments, and how to manage member invitations, roles and permissions, service accounts and API keys, and suspension.

This page explains the units of access in Hane — organizations, projects, and environments — and how to manage the people and programs that use them: members, roles, service accounts, and API keys.

Level Meaning What it holds
Organization The unit that contracts with Hane. Data and permissions are separated here Members, groups, roles, the list of projects, suspension
Project The unit within an organization that separates definitions and data. Create one per business app or purpose Environments, service accounts, definitions, business data
Environment dev, stage, and prod of the same project Business data, credentials, and the active release, per environment

When you create a project, it gets three environments: dev, stage, and prod. The organization, project, and environment are not part of the URL; they are determined by the credential attached to the request.

A user signed in to the IdP can create an organization. Since they do not belong to an organization yet, they can call this with the IdP’s ID token as is. The creator becomes the organization’s owner. The name uses lowercase letters, digits, and hyphens, and serves as the identifier in URLs and commands. Where the provider limits who can create organizations, only permitted users can.

POST /v1/platform/organizations
Authorization: Bearer <ID token>
Idempotency-Key: 7d0c…
Content-Type: application/json
{ "name": "acme", "display_name": "ACME Trading" }

Create a project with POST /v1/platform/projects using the same shape (name, display_name). This requires the platform:projects.manage scope.

Users of an organization are managed as members. People’s credentials (passwords, multi-factor authentication) stay with your IdP; Hane exchanges the IdP’s ID token for a Hane access token.

To invite someone, specify an email address and roles.

POST /v1/platform/members
Authorization: Bearer <access token>
Idempotency-Key: 2f61…
Content-Type: application/json
{ "email": "sato@example.com", "roles": ["operator"], "display_name": "Sato" }

An invited member is created in the invited state. When the invited person signs in to the IdP and obtains an access token with the same email address, the member becomes active. Even before joining, a user can see the organizations they are invited to with GET /v1/auth/me.

Operation API
List members GET /v1/platform/members
Change roles PUT /v1/platform/members/{id}/roles
Remove from the organization DELETE /v1/platform/members/{id}. The person’s tokens are rejected from the next call. Only an owner can remove an owner, and the last owner cannot be removed
Create a group or replace its members PUT /v1/platform/groups/{name}. Groups are also the unit to which tasks are assigned
Delegate during an absence PUT /v1/platform/members/{id}/delegation. During the period, assignment candidates go to the delegate member instead

A member’s permissions are determined by roles. Roles apply across the organization, and each role grants a fixed set of public API scopes in the form <service>:<resource>.<action>.

Role Main capabilities
owner Everything. Only an owner can lift a suspension
admin All scopes, including managing members, service accounts, and API keys, and lifting decider overrides
developer Reads, plus applying definitions and creating and activating ReleaseBundles, writing business data, operating cases, running agents, and viewing the audit log
operator Reads, plus writing business data and confirming values, operating cases, deciding tasks and approvals, managing contacts and documents, and running agents
viewer Read access to each service only

Some operations require being a person in addition to having the scope. Confirming values and deciding tasks and approvals can be done only by human users, never by service accounts or AI.

Besides assigning roles through the API, you can add roles with a RoleBinding manifest. A RoleBinding is a setting, so it takes effect as soon as it is applied. It cannot assign owner, and it never removes roles assigned through the API.

apiVersion: platform/v1alpha1
kind: RoleBinding
metadata:
name: fleet-operators
spec:
roles: [operator]
subjects:
- { kind: Group, name: fleet-desk }
- { kind: User, name: sato@example.com }

Every time roles, groups, or API keys change, the organization’s policy epoch (policy_epoch) increases. Tokens issued under an older epoch are rejected, so removing a permission takes effect from the next call.

Create a service account for non-human callers such as your business app’s server or CI. A service account is bound to one environment of one project, and you specify the scopes it may use when you create it.

POST /v1/platform/service-accounts
Authorization: Bearer <access token>
Idempotency-Key: 9a3e…
Content-Type: application/json
{ "name": "fleet-app", "project": "fleet", "environment": "dev",
"scopes": ["data:records.read", "data:records.write", "workflows:read"] }

Issue an API key with POST /v1/platform/service-accounts/{id}/keys. You can set an expiry with expires_at; if omitted, the key does not expire.

  • The key value (secret) is returned only in the issuing response. Hane stores only a hash, so it cannot be shown again.
  • Keys start with hane_<environment>_, which makes leaked keys easier to detect.
  • Revoke a key you no longer need with DELETE /v1/platform/service-accounts/{id}/keys/{keyId}.
  • Keep API keys on the server side and never hand them to browsers. To call the API as a user’s action, use that user’s access token.

When your business app calls the API on behalf of a user, it can exchange the user’s ID token together with the app’s API key for an access token. The resulting scopes are the intersection of the user’s and the app’s scopes, and approvals and task decisions are recorded as the user. See Authentication for the steps.

If something goes wrong in your organization, you can apply a suspension to stop all APIs and executions. This requires the platform:suspend scope and a reason.

POST /v1/platform/suspension
Authorization: Bearer <access token>
Idempotency-Key: c41b…
Content-Type: application/json
{ "reason": "Erroneous messages keep being sent" }

While suspended, requests are refused with TENANT_SUSPENDED. Lift the suspension with DELETE /v1/platform/suspension; only an owner can do this.