FreeState Remote State Backend API (1.0.0)

Download OpenAPI specification:

A solution to enable remote state for Terraform and OpenTofu that offers a "does one job well" approach to state storage and locking.

This API provides:

  • Terraform HTTP backend compatibility for state CRUD operations
  • Distributed locking using PostgreSQL to prevent concurrent writes
  • Organization and workspace management with plan-based limits
  • User management with admin/user roles and API key authentication
  • State versioning, diffing, and rollback capabilities

API Specification Split

FreeState's API is split into two separate specifications:

Main Backend API (this specification):

  • URL: https://spec.freestate.cloud
  • Purpose: Core Terraform/OpenTofu state backend operations
  • Audience: Terraform CLI, automation tools, CI/CD pipelines
  • Endpoints: State CRUD, locking, versioning, basic workspace/user management

Portal Management API:

This separation ensures:

  • Clear API boundaries between infrastructure operations and management UI
  • Independent evolution of backend and portal features
  • Reduced complexity for Terraform/automation consumers
  • Better security boundaries between operational and administrative functions

API Versioning

This API supports both path-based and Accept header-based versioning:

Path-based versioning (current):

  • /api/v1/... - Version 1 endpoints

Accept header versioning (recommended):

  • Accept: application/vnd.freestate.v1+json - Version 1
  • Accept: application/vnd.freestate.v2+json - Version 2

Response headers:

  • FreeState-API-Version - Indicates the API version being used
  • Deprecation - Present when using a deprecated version
  • Sunset - Date when deprecated version will be removed
  • Warning - Deprecation warning message

Default behavior:

  • If no version is specified, defaults to v1
  • Unknown Accept headers are tolerated and default to v1
  • Accept header versioning takes precedence over path-based versioning

Health

Service health monitoring

Health check endpoint

Returns the health status of the service and database connectivity

Responses

Response Headers
FreeState-API-Version
string
Example: "v1"

The API version being used for this response

Response Schema:
status
required
string
Enum: "healthy" "unhealthy"
uptime
string

Service uptime

version
string

Application version

Response samples

Content type
{
  • "status": "healthy",
  • "version": "string",
  • "uptime": "string"
}

Authentication

User authentication and session management

Authenticate user and get JWT token

Login with username and password to receive an authentication token

Request Body schema: application/json
required
password
required
string non-empty
username
required
string non-empty

Responses

Response Schema: application/json
expires_at
required
string <date-time>

Token expiration time

token
required
string

JWT authentication token

required
object (UserInfo)

Request samples

Content type
application/json
{
  • "username": "string",
  • "password": "string"
}

Response samples

Content type
application/json
{
  • "token": "string",
  • "user": {
    },
  • "expires_at": "2019-08-24T14:15:22Z"
}

Organizations

Organization management and tenant isolation

Create a new organization

Create a new organization with specified plan limits

Request Body schema: application/json
required
name
required
string non-empty ^[a-zA-Z0-9]([a-zA-Z0-9_-]*[a-zA-Z0-9])?$
plan
string
Default: "free"
Enum: "free" "pro" "enterprise"

Responses

Response Schema: application/json
active
required
boolean
created_at
required
string <date-time>
id
required
string <uuid>
max_state_size
required
integer <int64>

Maximum state size in bytes

max_users
required
integer

Maximum number of users allowed

max_workspaces
required
integer

Maximum number of workspaces allowed

name
required
string
plan
required
string
Enum: "free" "pro" "enterprise"
updated_at
required
string <date-time>

Request samples

Content type
application/json
{
  • "name": "string",
  • "plan": "free"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "plan": "free",
  • "created_at": "2019-08-24T14:15:22Z",
  • "updated_at": "2019-08-24T14:15:22Z",
  • "active": true,
  • "max_workspaces": 0,
  • "max_state_size": 0,
  • "max_users": 0
}

Users

User account management

Create initial admin user

Bootstrap endpoint for creating the first admin user in an organization

Request Body schema: application/json
required
email
required
string <email>
organization
required
string non-empty
password
required
string >= 8 characters
role
string
Default: "user"
Enum: "admin" "user"
username
required
string non-empty

Responses

Response Schema: application/json
active
required
boolean
created_at
required
string <date-time>
email
required
string <email>
id
required
string <uuid>
organization
required
string
role
required
string
Enum: "admin" "user"
updated_at
required
string <date-time>
username
required
string

Request samples

Content type
application/json
{
  • "username": "string",
  • "email": "user@example.com",
  • "password": "stringst",
  • "organization": "string",
  • "role": "admin"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "username": "string",
  • "email": "user@example.com",
  • "organization": "string",
  • "role": "admin",
  • "created_at": "2019-08-24T14:15:22Z",
  • "updated_at": "2019-08-24T14:15:22Z",
  • "active": true
}

Create a new user

Create a new user in the organization (requires admin role)

Authorizations:
BearerAuthApiKeyAuthBasicAuth
Request Body schema: application/json
required
email
required
string <email>
organization
required
string non-empty
password
required
string >= 8 characters
role
string
Default: "user"
Enum: "admin" "user"
username
required
string non-empty

Responses

Response Schema: application/json
active
required
boolean
created_at
required
string <date-time>
email
required
string <email>
id
required
string <uuid>
organization
required
string
role
required
string
Enum: "admin" "user"
updated_at
required
string <date-time>
username
required
string

Request samples

Content type
application/json
{
  • "username": "string",
  • "email": "user@example.com",
  • "password": "stringst",
  • "organization": "string",
  • "role": "admin"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "username": "string",
  • "email": "user@example.com",
  • "organization": "string",
  • "role": "admin",
  • "created_at": "2019-08-24T14:15:22Z",
  • "updated_at": "2019-08-24T14:15:22Z",
  • "active": true
}

Get current user information

Get information about the currently authenticated user

Authorizations:
BearerAuthApiKeyAuthBasicAuth

Responses

Response Schema: application/json
active
required
boolean
created_at
required
string <date-time>
email
required
string <email>
id
required
string <uuid>
organization
required
string
role
required
string
Enum: "admin" "user"
updated_at
required
string <date-time>
username
required
string

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "username": "string",
  • "email": "user@example.com",
  • "organization": "string",
  • "role": "admin",
  • "created_at": "2019-08-24T14:15:22Z",
  • "updated_at": "2019-08-24T14:15:22Z",
  • "active": true
}

API Keys

API key management for automation

Create a new API key

Create a new API key for authentication

Authorizations:
BearerAuthApiKeyAuthBasicAuth
Request Body schema: application/json
required
expires_at
string or null <date-time>
name
required
string non-empty

Responses

Response Schema: application/json
created_at
required
string <date-time>
expires_at
string or null <date-time>
id
required
string <uuid>
key
required
string

The actual API key (only returned once)

name
required
string

Request samples

Content type
application/json
{
  • "name": "string",
  • "expires_at": "2019-08-24T14:15:22Z"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "key": "string",
  • "name": "string",
  • "created_at": "2019-08-24T14:15:22Z",
  • "expires_at": "2019-08-24T14:15:22Z"
}

List API keys

List all API keys for the current user

Authorizations:
BearerAuthApiKeyAuthBasicAuth

Responses

Response Schema: application/json
Array
active
required
boolean
created_at
required
string <date-time>
expires_at
string or null <date-time>
id
required
string <uuid>
name
required
string
organization
required
string
user_id
required
string <uuid>

Response samples

Content type
application/json
[
  • {
    }
]

Delete an API key

Delete an API key by ID

Authorizations:
BearerAuthApiKeyAuthBasicAuth
path Parameters
id
required
string <uuid>

API key ID

Responses

Response samples

Content type
application/json
{
  • "error": "string"
}

Workspaces

Terraform workspace management

List workspaces

List all workspaces in the organization

Authorizations:
BearerAuthApiKeyAuthBasicAuth

Responses

Response Schema: application/json
Array
created_at
required
string <date-time>
id
required
string <uuid>
lock_id
string or null
object (LockInfo)
locked
required
boolean
name
required
string
organization
required
string
updated_at
required
string <date-time>

Response samples

Content type
application/json
[
  • {
    }
]

Create a new workspace

Create a new workspace in the organization

Authorizations:
BearerAuthApiKeyAuthBasicAuth
Request Body schema: application/json
required
name
required
string non-empty ^[a-zA-Z0-9]([a-zA-Z0-9_-]*[a-zA-Z0-9])?$

Responses

Response Schema: application/json
created_at
required
string <date-time>
id
required
string <uuid>
lock_id
string or null
object (LockInfo)
locked
required
boolean
name
required
string
organization
required
string
updated_at
required
string <date-time>

Request samples

Content type
application/json
{
  • "name": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "organization": "string",
  • "created_at": "2019-08-24T14:15:22Z",
  • "updated_at": "2019-08-24T14:15:22Z",
  • "locked": true,
  • "lock_id": "string",
  • "lock_info": {
    }
}

Get workspace information

Get information about a specific workspace

Authorizations:
BearerAuthApiKeyAuthBasicAuth
path Parameters
name
required
string

Workspace name

Responses

Response Schema: application/json
created_at
required
string <date-time>
id
required
string <uuid>
lock_id
string or null
object (LockInfo)
locked
required
boolean
name
required
string
organization
required
string
updated_at
required
string <date-time>

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "organization": "string",
  • "created_at": "2019-08-24T14:15:22Z",
  • "updated_at": "2019-08-24T14:15:22Z",
  • "locked": true,
  • "lock_id": "string",
  • "lock_info": {
    }
}

Delete a workspace

Delete a workspace and all associated state data

Authorizations:
BearerAuthApiKeyAuthBasicAuth
path Parameters
name
required
string

Workspace name

Responses

Response samples

Content type
application/json
{
  • "error": "string"
}

State Management

Terraform state storage and retrieval (HTTP Backend Protocol)

Get current state

Get the current Terraform state for a workspace (Terraform HTTP Backend protocol)

Authorizations:
BearerAuthApiKeyAuthBasicAuth
path Parameters
organization
required
string

Organization name

workspace
required
string

Workspace name

Responses

Response Schema: application/json
object

Terraform state data

Response samples

Content type
application/json
{ }

Update state

Update the Terraform state for a workspace (Terraform HTTP Backend protocol)

Authorizations:
BearerAuthApiKeyAuthBasicAuth
path Parameters
organization
required
string

Organization name

workspace
required
string

Workspace name

query Parameters
ID
string

Lock ID for state locking

Request Body schema: application/json
required
object

Terraform state data

Responses

Request samples

Content type
application/json
{ }

Response samples

Content type
application/json
{
  • "error": "string"
}

Delete state

Delete the Terraform state for a workspace (Terraform HTTP Backend protocol)

Authorizations:
BearerAuthApiKeyAuthBasicAuth
path Parameters
organization
required
string

Organization name

workspace
required
string

Workspace name

Responses

Response samples

Content type
application/json
{
  • "error": "string"
}

Lock state (Preferred - REST API)

Lock the Terraform state for a workspace to prevent concurrent modifications (Terraform HTTP Backend protocol using standard REST methods - preferred for new implementations)

Authorizations:
BearerAuthApiKeyAuthBasicAuth
path Parameters
organization
required
string

Organization name

workspace
required
string

Workspace name

Request Body schema: application/json
required
Created
required
string <date-time>

When the lock was created

ID
required
string

Unique lock identifier

Info
required
string

Additional information about the lock

Operation
required
string

Operation being performed

Path
required
string

State path

Version
required
string

Terraform version

Who
required
string

User who created the lock

Responses

Response Schema: application/json
Created
required
string <date-time>

When the lock was created

ID
required
string

Unique lock identifier

Info
required
string

Additional information about the lock

Operation
required
string

Operation being performed

Path
required
string

State path

Version
required
string

Terraform version

Who
required
string

User who created the lock

Request samples

Content type
application/json
{
  • "ID": "string",
  • "Operation": "string",
  • "Info": "string",
  • "Who": "string",
  • "Version": "string",
  • "Created": "2019-08-24T14:15:22Z",
  • "Path": "string"
}

Response samples

Content type
application/json
{
  • "ID": "string",
  • "Operation": "string",
  • "Info": "string",
  • "Who": "string",
  • "Version": "string",
  • "Created": "2019-08-24T14:15:22Z",
  • "Path": "string"
}

Unlock state (Preferred - REST API)

Unlock the Terraform state for a workspace (Terraform HTTP Backend protocol using standard REST methods - preferred for new implementations)

Authorizations:
BearerAuthApiKeyAuthBasicAuth
path Parameters
organization
required
string

Organization name

workspace
required
string

Workspace name

Request Body schema: application/json
required
ID
required
string

Lock ID to verify unlock authorization

Responses

Request samples

Content type
application/json
{
  • "ID": "string"
}

Response samples

Content type
application/json
{
  • "error": "string"
}

State Versioning

State versioning, history, and rollback capabilities

List state versions

List all versions of state for a workspace

Authorizations:
BearerAuthApiKeyAuthBasicAuth
path Parameters
organization
required
string

Organization name

workspace
required
string

Workspace name

Responses

Response Schema: application/json
Array
created_at
required
string <date-time>
created_by
string or null <uuid>
hash
required
string
id
required
string <uuid>
size
required
integer <int64>
version
required
integer

Response samples

Content type
application/json
[
  • {
    }
]

Get specific state version

Get a specific version of state for a workspace

Authorizations:
BearerAuthApiKeyAuthBasicAuth
path Parameters
organization
required
string

Organization name

version
required
integer

State version number

workspace
required
string

Workspace name

Responses

Response Schema: application/json
created_at
required
string <date-time>
created_by
string or null <uuid>
hash
required
string
id
required
string <uuid>
size
required
integer <int64>
state_data
object

The actual Terraform state data

version
required
integer
workspace_id
required
string <uuid>

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "workspace_id": "0967198e-ec7b-4c6b-b4d3-f71244cadbe9",
  • "version": 0,
  • "size": 0,
  • "hash": "string",
  • "state_data": { },
  • "created_at": "2019-08-24T14:15:22Z",
  • "created_by": "ee824cad-d7a6-4f48-87dc-e8461a9201c4"
}

Compare state versions

Compare two versions of state and return the differences

Authorizations:
BearerAuthApiKeyAuthBasicAuth
path Parameters
organization
required
string

Organization name

workspace
required
string

Workspace name

query Parameters
from
required
integer

Source version number

to
required
integer

Target version number

Responses

Response Schema: application/json
created_at
required
string <date-time>
diff
required
object

Structured difference between state versions

from_version
required
integer
summary
required
string

Human-readable summary of changes

to_version
required
integer

Response samples

Content type
application/json
{
  • "from_version": 0,
  • "to_version": 0,
  • "diff": { },
  • "summary": "string",
  • "created_at": "2019-08-24T14:15:22Z"
}

Rollback to previous state version

Rollback workspace state to a specific version

Authorizations:
BearerAuthApiKeyAuthBasicAuth
path Parameters
organization
required
string

Organization name

version
required
integer

Version to rollback to

workspace
required
string

Workspace name

Responses

Response Schema: application/json
created_at
required
string <date-time>
created_by
string or null <uuid>
hash
required
string
id
required
string <uuid>
size
required
integer <int64>
state_data
object

The actual Terraform state data

version
required
integer
workspace_id
required
string <uuid>

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "workspace_id": "0967198e-ec7b-4c6b-b4d3-f71244cadbe9",
  • "version": 0,
  • "size": 0,
  • "hash": "string",
  • "state_data": { },
  • "created_at": "2019-08-24T14:15:22Z",
  • "created_by": "ee824cad-d7a6-4f48-87dc-e8461a9201c4"
}

Encryption Management

BYOK configuration and KEK rotation operations

Get organization encryption status

Get the current encryption configuration and status for an organization

Authorizations:
BearerAuthApiKeyAuthBasicAuth
path Parameters
organization
required
string

Organization name

Responses

Response Headers
FreeState-API-Version
string
Example: "v1"

The API version being used for this response

Response Schema: application/json
byok_enabled
required
boolean

Whether customer-provided BYOK is active

encryption_enabled
required
boolean

Whether envelope encryption is enabled

encryption_enabled_at
string or null <date-time>
kek_id
string

Current KEK identifier (ARN or logical ID)

kek_status
string
Enum: "active" "rotating" "deprecated" "disabled"

KEK status

key_type
string
Enum: "managed" "byok"

Key type (managed or byok)

kms_provider
string
Enum: "aws-kms" "azure-keyvault" "gcp-kms" "local"

KMS provider (aws-kms, azure-keyvault, gcp-kms, local)

organization_id
required
string <uuid>

Response samples

Content type
application/json
{
  • "organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
  • "encryption_enabled": true,
  • "byok_enabled": true,
  • "encryption_enabled_at": "2019-08-24T14:15:22Z",
  • "kek_id": "string",
  • "kms_provider": "aws-kms",
  • "key_type": "managed",
  • "kek_status": "active"
}

Configure BYOK (Bring Your Own Key)

Configure customer-provided KMS key for envelope encryption. This enables BYOK mode where the customer controls the KEK. All workspace DEKs will be re-encrypted with the new BYOK KEK.

Authorizations:
BearerAuthApiKeyAuthBasicAuth
path Parameters
organization
required
string

Organization name

Request Body schema: application/json
required
kek_id
required
string

Customer-provided KEK identifier (AWS KMS ARN, Azure Key Vault key ID, or GCP KMS key path)

kms_provider
required
string
Enum: "aws-kms" "azure-keyvault" "gcp-kms"

KMS provider type

object

Optional provider-specific metadata (e.g., region, resource group)

Responses

Response Headers
FreeState-API-Version
string
Example: "v1"

The API version being used for this response

Response Schema: application/json
kek_id
required
string
message
required
string
organization_id
required
string <uuid>
rotation_duration
string

Time taken to complete the rotation (e.g., "2.5s")

success
required
boolean
workspaces_reencrypted
required
integer

Number of workspaces that had their DEKs re-encrypted

Request samples

Content type
application/json
{
  • "kek_id": "arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012",
  • "kms_provider": "aws-kms",
  • "metadata": { }
}

Response samples

Content type
application/json
{
  • "success": true,
  • "message": "string",
  • "organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
  • "kek_id": "string",
  • "workspaces_reencrypted": 0,
  • "rotation_duration": "string"
}

Remove BYOK configuration

Remove customer-provided KMS key and revert to FreeState-managed encryption. All workspace DEKs will be re-encrypted with a new FreeState-managed KEK.

Authorizations:
BearerAuthApiKeyAuthBasicAuth
path Parameters
organization
required
string

Organization name

Responses

Response Headers
FreeState-API-Version
string
Example: "v1"

The API version being used for this response

Response Schema: application/json
message
required
string
new_kek_id
required
string

New FreeState-managed KEK ID

organization_id
required
string <uuid>
rotation_duration
string

Time taken to complete the rotation

success
required
boolean
workspaces_reencrypted
required
integer

Number of workspaces that had their DEKs re-encrypted

Response samples

Content type
application/json
{
  • "success": true,
  • "message": "string",
  • "organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
  • "new_kek_id": "string",
  • "workspaces_reencrypted": 0,
  • "rotation_duration": "string"
}

Validate BYOK KEK

Validate that FreeState can access the customer-provided KMS key. This should be called before configuring BYOK to ensure proper setup.

Authorizations:
BearerAuthApiKeyAuthBasicAuth
path Parameters
organization
required
string

Organization name

Request Body schema: application/json
required
kek_id
required
string

KEK identifier to validate

kms_provider
required
string
Enum: "aws-kms" "azure-keyvault" "gcp-kms"

KMS provider type

object

Optional provider-specific metadata

Responses

Response Headers
FreeState-API-Version
string
Example: "v1"

The API version being used for this response

Response Schema: application/json
kek_id
string
kms_provider
string
message
required
string

Validation result message

valid
required
boolean

Whether the KEK is accessible and valid

Request samples

Content type
application/json
{
  • "kek_id": "string",
  • "kms_provider": "aws-kms",
  • "metadata": { }
}

Response samples

Content type
application/json
{
  • "valid": true,
  • "message": "string",
  • "kek_id": "string",
  • "kms_provider": "string"
}

Rotate KEK (Key Encryption Key)

Rotate the organization's KEK. All workspace DEKs will be re-encrypted with the new KEK. This operation does not re-encrypt workspace state data. For BYOK customers, provide a new KEK ID. For managed encryption, a new FreeState-managed KEK will be generated automatically.

Authorizations:
BearerAuthApiKeyAuthBasicAuth
path Parameters
organization
required
string

Organization name

Request Body schema: application/json
optional
object

Optional provider-specific metadata

new_kek_id
string or null

Optional new KEK ID for BYOK customers. If not provided for managed encryption, a new KEK will be automatically generated.

Responses

Response Headers
FreeState-API-Version
string
Example: "v1"

The API version being used for this response

Response Schema: application/json
completed_at
required
string <date-time>
duration
required
string

Duration of the rotation operation (e.g., "3.2s")

errors
Array of strings

List of any errors encountered during rotation

message
required
string
new_kek_id
required
string
old_kek_id
required
string
started_at
required
string <date-time>
success
required
boolean
workspaces_rotated
required
integer

Number of workspaces that had their DEKs re-encrypted

Request samples

Content type
application/json
{
  • "new_kek_id": "string",
  • "metadata": { }
}

Response samples

Content type
application/json
{
  • "success": true,
  • "message": "string",
  • "old_kek_id": "string",
  • "new_kek_id": "string",
  • "workspaces_rotated": 0,
  • "duration": "string",
  • "started_at": "2019-08-24T14:15:22Z",
  • "completed_at": "2019-08-24T14:15:22Z",
  • "errors": [
    ]
}

Get encryption audit log

Get audit log of all encryption operations for an organization, including KEK rotations, BYOK configuration changes, and DEK operations.

Authorizations:
BearerAuthApiKeyAuthBasicAuth
path Parameters
organization
required
string

Organization name

query Parameters
limit
integer [ 1 .. 1000 ]
Default: 100

Maximum number of audit entries to return (default 100, max 1000)

offset
integer >= 0
Default: 0

Number of audit entries to skip (for pagination)

Responses

Response Headers
FreeState-API-Version
string
Example: "v1"

The API version being used for this response

Response Schema: application/json
required
Array of objects (EncryptionAuditEntry)
limit
required
integer

Number of entries returned in this response

offset
required
integer

Offset used for this response

total
required
integer

Total number of audit entries available

Response samples

Content type
application/json
{
  • "entries": [
    ],
  • "total": 0,
  • "limit": 0,
  • "offset": 0
}