Database schema
PostgreSQL 15 or newer. db/schema.sql is applied idempotently at API startup and is additive: tables and columns are created if missing and never dropped. Column types are shown as written in the schema; columns marked added later arrived through an ALTER TABLE in a newer release.
There are 80 tables.
account_suspension_events · account_suspensions · allocations · api_tokens · audit_events · auth_challenges · backups · billing_customers · billing_events · branding_blobs · branding_history · collaborators · console_events · console_interests · console_nodes · email_outbox · email_templates · failover_events · file_transfers · invoices · jobs · login_attempts · node_events · nodes · notification_channels · notification_deliveries · notification_emissions · notifications · orders · passkeys · plan_prices · plans · plugin_kv · plugin_logs · plugins · recovery_codes · request_limits · schedule_runs · schedules · server_addons · server_events · server_metrics · servers · sessions · settings · sftp_tokens · signup_invites · subscription_events · subscriptions · support_article_search · support_article_votes · support_articles · support_attachments · support_categories · support_drafts · support_events · support_group_members · support_groups · support_hours · support_inbound_messages · support_macros · support_messages · support_presence · support_rules · support_ticket_reads · support_tickets · support_tiers · team_transfers · template_versions · templates · usage_reporting · user_tokens · users · vm_addresses · vm_console_tickets · vm_media · vm_networks · vm_profiles · vm_snapshots · webauthn_challenges
account_suspension_events
| Column | Type | |
|---|---|---|
id | bigserial | |
suspension_id | uuid | |
kind | text | |
actor | uuid | |
data | jsonb | |
created_at | timestamptz |
account_suspensions
| Column | Type | |
|---|---|---|
id | uuid | |
user_id | uuid | |
reference | text | |
reason | text | |
source | text | |
message | text | |
internal_note | text | |
stop_servers | boolean | |
stopped_server_ids | uuid[] | |
allow_backup_download | boolean | |
allow_account_deletion | boolean | |
lift_on_payment | boolean | |
notify | boolean | |
until | timestamptz | |
created_by | uuid | |
created_at | timestamptz | |
lifted_at | timestamptz | |
lifted_by | uuid | |
lift_note | text | |
retention_notified_at | timestamptz |
allocations
| Column | Type | |
|---|---|---|
node_id | uuid | |
server_id | uuid | |
port | integer | |
protocol | text |
api_tokens
| Column | Type | |
|---|---|---|
id | uuid | |
user_id | uuid | |
name | text | |
token_hash | text | |
scopes | text[] | |
expires_at | timestamptz | |
created_at | timestamptz |
audit_events
| Column | Type | |
|---|---|---|
id | bigserial | |
actor_id | uuid | |
action | text | |
target_type | text | |
target_id | text | |
detail | jsonb | |
created_at | timestamptz |
auth_challenges
| Column | Type | |
|---|---|---|
token_hash | text | |
user_id | uuid | |
expires_at | timestamptz | |
attempts | integer |
backups
| Column | Type | |
|---|---|---|
id | uuid | |
server_id | uuid | |
job_id | uuid | |
object_key | text | |
state | text | |
size_bytes | bigint | |
error | text | |
created_at | timestamptz | |
completed_at | timestamptz |
billing_customers
| Column | Type | |
|---|---|---|
user_id | uuid | |
provider | text | |
livemode | boolean | |
provider_customer_id | text | |
created_at | timestamptz |
billing_events
The webhook inbox: stored first, acknowledged, processed with retries. Unique per provider event.
| Column | Type | |
|---|---|---|
id | bigserial | |
provider | text | |
event_id | text | |
type | text | |
livemode | boolean | |
refs | jsonb | |
received_at | timestamptz | |
processed_at | timestamptz | |
attempts | integer | |
next_attempt_at | timestamptz | |
error | text |
branding_blobs
0.6.2.1 "Plumage": appearance. The document is the settings row "branding"; uploaded images and the last 20 versions live here.
| Column | Type | |
|---|---|---|
sha256 | text | |
kind | text | |
mime | text | |
bytes | bytea | |
width | integer | |
height | integer | |
created_at | timestamptz |
branding_history
| Column | Type | |
|---|---|---|
id | bigserial | |
revision | integer | |
at | timestamptz | |
by | uuid | |
reason | text | |
value | jsonb |
collaborators
| Column | Type | |
|---|---|---|
server_id | uuid | |
user_id | uuid | |
permissions | text[] |
console_events
| Column | Type | |
|---|---|---|
id | bigserial | |
server_id | uuid | |
frame | jsonb | |
created_at | timestamptz |
console_interests
| Column | Type | |
|---|---|---|
replica | uuid | |
server_id | uuid | |
expires_at | timestamptz |
console_nodes
| Column | Type | |
|---|---|---|
node_id | uuid | |
replica | uuid | |
expires_at | timestamptz |
email_outbox
| Column | Type | |
|---|---|---|
id | bigserial | |
to_addr | text | |
template | text | |
user_id | uuid | |
subject | text | |
text_body | text | |
html_body | text | |
status | text | |
attempts | integer | |
next_attempt_at | timestamptz | |
last_error | text | |
dedupe_key | text | |
created_at | timestamptz | |
sent_at | timestamptz |
email_templates
Email: editable templates and a retrying outbox.
| Column | Type | |
|---|---|---|
id | text | |
subject | text | |
text_body | text | |
html_body | text | |
enabled | boolean | |
updated_at | timestamptz | |
updated_by | uuid |
failover_events
| Column | Type | |
|---|---|---|
id | uuid | |
server_id | uuid | |
kind | text | |
state | text | |
reason | text | |
from_node | uuid | |
to_node | uuid | |
backup_id | uuid | |
data_age_seconds | integer | |
error | text | |
job_id | uuid | |
actor_id | uuid | |
started_at | timestamptz | |
updated_at | timestamptz | |
finished_at | timestamptz | |
target_network_id | uuid | added later |
file_transfers
| Column | Type | |
|---|---|---|
id | uuid | |
server_id | uuid | |
user_id | uuid | |
direction | text | |
path | text | |
size_bytes | bigint | |
object_key | text | |
state | text | |
job_id | uuid | |
expires_at | timestamptz | |
store | text | added later |
invoices
| Column | Type | |
|---|---|---|
id | uuid | |
subscription_id | uuid | |
user_id | uuid | |
provider | text | |
provider_invoice_id | text | |
number | text | |
status | text | |
amount_due | bigint | |
amount_paid | bigint | |
amount_refunded | bigint | |
currency | text | |
period_start | timestamptz | |
period_end | timestamptz | |
hosted_url | text | |
pdf_url | text | |
description | text | |
livemode | boolean | |
created_at | timestamptz | |
paid_at | timestamptz |
jobs
| Column | Type | |
|---|---|---|
id | uuid | |
node_id | uuid | |
server_id | uuid | |
kind | text | |
payload | jsonb | |
state | text | |
result | jsonb | |
error | text | |
attempt | integer | |
lease_until | timestamptz | |
created_at | timestamptz | |
started_at | timestamptz | |
finished_at | timestamptz |
login_attempts
Shared login throttling survives API restarts and works across replicas.
| Column | Type | |
|---|---|---|
bucket_hash | text | |
attempts | integer | |
expires_at | timestamptz |
node_events
| Column | Type | |
|---|---|---|
id | bigserial | |
node_id | uuid | |
kind | text | |
at | timestamptz | |
detail | text |
nodes
| Column | Type | |
|---|---|---|
id | uuid | |
name | text | |
location | text | |
status | text | |
last_seen_at | timestamptz | |
draining | boolean | |
headroom_mb | integer | |
memory_mb | integer | |
cpu_percent | integer | |
disk_mb | integer | |
version | text | |
usage | jsonb | |
deleted_at | timestamptz | |
credential_hash | text | |
enrollment_hash | text | |
enrollment_expires_at | timestamptz | |
vm_enabled | boolean | |
created_at | timestamptz | |
agent | jsonb | added later |
public_host | text | added later |
notification_channels
| Column | Type | |
|---|---|---|
id | uuid | |
scope | text | |
user_id | uuid | |
name | text | |
kind | text | |
config | jsonb | |
secret | text | |
events | text[] | |
server_ids | uuid[] | |
enabled | boolean | |
last_status | text | |
last_error | text | |
last_sent_at | timestamptz | |
created_at | timestamptz |
notification_deliveries
| Column | Type | |
|---|---|---|
id | uuid | |
channel_id | uuid | |
payload | jsonb | |
attempts | integer | |
state | text | |
available_at | timestamptz | |
created_at | timestamptz |
notification_emissions
Durable external delivery and atomic event claims, shared by API replicas.
| Column | Type | |
|---|---|---|
identity | text | |
expires_at | timestamptz |
notifications
| Column | Type | |
|---|---|---|
id | bigserial | |
user_id | uuid | |
kind | text | |
severity | text | |
title | text | |
body | text | |
server_id | uuid | |
node_id | uuid | |
data | jsonb | |
created_at | timestamptz |
orders
A checkout attempt. The payment is matched to an order, never to what the browser says.
| Column | Type | |
|---|---|---|
id | uuid | |
user_id | uuid | |
plan_id | uuid | |
price_id | uuid | |
status | text | |
snapshot | jsonb | |
details | jsonb | |
provider | text | |
provider_session_id | text | |
provider_customer_id | text | |
livemode | boolean | |
terms_version | text | |
subscription_id | uuid | |
error | text | |
created_at | timestamptz | |
expires_at | timestamptz | |
paid_at | timestamptz | |
checkout_url | text | added later |
passkeys
| Column | Type | |
|---|---|---|
id | text | |
user_id | uuid | |
public_key | bytea | |
counter | bigint | |
transports | text[] | |
name | text | |
device_type | text | |
backed_up | boolean | |
created_at | timestamptz | |
last_used_at | timestamptz |
plan_prices
| Column | Type | |
|---|---|---|
id | uuid | |
plan_id | uuid | |
cycle | text | |
amount | bigint | |
currency | text | |
trial_days | integer | |
setup_fee | bigint | |
active | boolean | |
created_at | timestamptz |
plans
Plans: something that can be given or sold. A server plan carries a preset (one server per subscription); an account plan carries an allowance added to the customer's limits.
| Column | Type | |
|---|---|---|
id | uuid | |
slug | text | |
name | text | |
description | text | |
kind | text | |
visibility | text | |
active | boolean | |
sort_order | integer | |
features | jsonb | |
preset | jsonb | |
limits | jsonb | |
options | jsonb | |
stock | integer | |
per_customer_max | integer | |
trial_once | boolean | |
retention_days | integer | |
archived_at | timestamptz | |
created_at | timestamptz | |
updated_at | timestamptz | |
support_tier | text | added later |
plugin_kv
| Column | Type | |
|---|---|---|
plugin_id | text | |
key | text | |
value | jsonb |
plugin_logs
| Column | Type | |
|---|---|---|
id | bigserial | |
plugin_id | text | |
level | text | |
message | text | |
at | timestamptz |
plugins
Installed plugins. Code lives here (not on disk) so every API replica sees the same version; the plugin host receives it per call and caches it by checksum.
| Column | Type | |
|---|---|---|
id | text | |
name | text | |
version | text | |
tier | text | |
source | text | |
manifest | jsonb | |
code | text | |
code_sha256 | text | |
package_sha256 | text | |
icon | text | |
readme | text | |
changelog | text | |
enabled | boolean | |
granted_permissions | text[] | |
settings | jsonb | |
secrets | text | |
previous | jsonb | |
failure_count | integer | |
last_error | text | |
disabled_reason | text | |
installed_by | uuid | |
installed_at | timestamptz | |
updated_at | timestamptz |
recovery_codes
| Column | Type | |
|---|---|---|
user_id | uuid | |
code_hash | text |
request_limits
| Column | Type | |
|---|---|---|
bucket_hash | text | |
attempts | integer | |
expires_at | timestamptz |
schedule_runs
| Column | Type | |
|---|---|---|
id | uuid | |
schedule_id | uuid | |
server_id | uuid | |
state | text | |
step | integer | |
next_step_at | timestamptz | |
results | jsonb | |
error | text | |
trigger | text | |
started_at | timestamptz | |
finished_at | timestamptz |
schedules
| Column | Type | |
|---|---|---|
id | uuid | |
server_id | uuid | |
kind | text | |
command | text | |
interval_minutes | integer | |
next_run_at | timestamptz | |
enabled | boolean | |
created_at | timestamptz | |
name | text | added later |
cron | text | added later |
timezone | text | added later |
tasks | jsonb | added later |
missed | text | added later |
last_run_at | timestamptz | added later |
last_status | text | added later |
last_error | text | added later |
server_addons
Files that plugins installed into servers (mods and plugins), tracked so they can be updated, disabled and removed. plugin_id is not a foreign key on purpose: removing a catalog plugin leaves the installed files and their records in place.
| Column | Type | |
|---|---|---|
id | uuid | |
server_id | uuid | |
plugin_id | text | |
provider | text | |
kind | text | |
dir | text | |
project_id | text | |
project_title | text | |
project_slug | text | |
icon_url | text | |
version_id | text | |
version_label | text | |
filename | text | |
sha512 | text | |
size_bytes | bigint | |
source_url | text | |
state | text | |
disabled | boolean | |
pinned | boolean | |
is_dependency | boolean | |
error | text | |
job_id | uuid | |
installed_by | uuid | |
installed_at | timestamptz | |
updated_at | timestamptz |
server_events
| Column | Type | |
|---|---|---|
id | bigserial | |
server_id | uuid | |
kind | text | |
message | text | |
detail | jsonb | |
at | timestamptz |
server_metrics
Resource history per server: 1-minute buckets (24 h), 5-minute (7 days) and hourly (30 days).
| Column | Type | |
|---|---|---|
server_id | uuid | |
res | smallint | |
bucket | timestamptz | |
cpu_sum | double precision | |
cpu_max | real | |
mem_sum | double precision | |
mem_max | double precision | |
disk_bytes | bigint | |
n | integer |
servers
| Column | Type | |
|---|---|---|
id | uuid | |
name | text | |
owner_id | uuid | |
node_id | uuid | |
template_id | text | |
memory_mb | integer | |
cpu_percent | integer | |
disk_mb | integer | |
port | integer | |
desired_status | text | |
observed_status | text | |
suspended | boolean | |
deleted_at | timestamptz | |
variables | jsonb | |
usage | jsonb | |
created_at | timestamptz | |
updated_at | timestamptz | |
backup_retention_days | integer | added later |
verify_interval_hours | integer | added later |
verify_last_run | timestamptz | added later |
failover_enabled | boolean | added later |
template_version | integer | added later |
extra_ports | jsonb | added later |
crash_policy | jsonb | added later |
crash_state | jsonb | added later |
last_exit | jsonb | added later |
alert_state | jsonb | added later |
subscription_id | uuid | added later |
suspended_reason | text | added later |
created_via | text | added later |
pending_delete_at | timestamptz | added later |
runtime | text | added later |
vm_config | jsonb | added later |
sessions
| Column | Type | |
|---|---|---|
id | uuid | |
user_id | uuid | |
token_hash | text | |
expires_at | timestamptz | |
created_at | timestamptz | |
ip | text | added later |
user_agent | text | added later |
last_seen_at | timestamptz | added later |
stepped_up_at | timestamptz | added later |
settings
0.5.1.1: panel-managed settings (secrets AES-GCM encrypted with ENCRYPTION_KEY).
| Column | Type | |
|---|---|---|
key | text | |
value | jsonb | |
secret | text | |
updated_by | uuid | |
updated_at | timestamptz |
sftp_tokens
| Column | Type | |
|---|---|---|
token_hash | text | |
user_id | uuid | |
server_id | uuid | |
expires_at | timestamptz |
signup_invites
Invite links and codes for invite-only sign-up.
| Column | Type | |
|---|---|---|
id | uuid | |
code_hash | text | |
email | text | |
note | text | |
created_by | uuid | |
expires_at | timestamptz | |
max_uses | integer | |
uses | integer | |
plan_id | uuid | |
created_at | timestamptz |
subscription_events
| Column | Type | |
|---|---|---|
id | bigserial | |
subscription_id | uuid | |
at | timestamptz | |
from_status | text | |
to_status | text | |
reason | text | |
source | text | |
ref | text | |
detail | jsonb |
subscriptions
| Column | Type | |
|---|---|---|
id | uuid | |
user_id | uuid | |
plan_id | uuid | |
price_id | uuid | |
order_id | uuid | |
provider | text | |
provider_subscription_id | text | |
provider_customer_id | text | |
livemode | boolean | |
status | text | |
cancel_at_period_end | boolean | |
cycle | text | |
amount | bigint | |
currency | text | |
current_period_start | timestamptz | |
current_period_end | timestamptz | |
trial_end | timestamptz | |
past_due_since | timestamptz | |
suspended_at | timestamptz | |
canceled_at | timestamptz | |
ended_at | timestamptz | |
terminated_at | timestamptz | |
retention_until | timestamptz | |
manual_ends_at | timestamptz | |
note | text | |
fulfilment | text | |
fulfilment_attempts | integer | |
fulfilment_error | text | |
next_fulfilment_at | timestamptz | |
server_details | jsonb | |
dunning | jsonb | |
holds | jsonb | |
version | integer | |
created_at | timestamptz | |
updated_at | timestamptz | |
reconciled_at | timestamptz | added later |
provider_status | text | added later |
support_article_search
| Column | Type | |
|---|---|---|
query | text | |
count | integer | |
no_results | integer |
support_article_votes
| Column | Type | |
|---|---|---|
article_id | uuid | |
user_id | uuid | |
helpful | boolean |
support_articles
| Column | Type | |
|---|---|---|
id | uuid | |
slug | text | |
title | text | |
body | text | |
category | text | |
visibility | text | |
helpful_yes | integer | |
helpful_no | integer | |
updated_by | uuid | |
updated_at | timestamptz |
support_attachments
| Column | Type | |
|---|---|---|
id | uuid | |
ticket_id | uuid | |
message_id | uuid | |
sha256 | text | |
mime | text | |
name | text | |
size | integer | |
bytes | bytea | |
uploaded_by | uuid | added later |
created_at | timestamptz | added later |
support_categories
| Column | Type | |
|---|---|---|
id | uuid | |
name | text | |
group_id | uuid | |
default_priority | text | |
tier_id | text | |
public | boolean | |
sort | integer |
support_drafts
| Column | Type | |
|---|---|---|
user_id | uuid | |
ticket_id | text | |
body | jsonb | |
updated_at | timestamptz |
support_events
| Column | Type | |
|---|---|---|
id | bigserial | |
ticket_id | uuid | |
kind | text | |
actor | uuid | |
data | jsonb | |
created_at | timestamptz |
support_group_members
| Column | Type | |
|---|---|---|
group_id | uuid | |
user_id | uuid |
support_groups
Help desk data. Customer projections never select private fields or notes.
| Column | Type | |
|---|---|---|
id | uuid | |
name | text |
support_hours
| Column | Type | |
|---|---|---|
id | integer | |
timezone | text | |
weekly | jsonb | |
holidays | jsonb |
support_inbound_messages
| Column | Type | |
|---|---|---|
id | text | |
ticket_id | uuid | |
created_at | timestamptz |
support_macros
| Column | Type | |
|---|---|---|
id | uuid | |
name | text | |
shortcut | text | |
body | text | |
scope | text | |
owner_id | uuid |
support_messages
| Column | Type | |
|---|---|---|
id | uuid | |
ticket_id | uuid | |
author_user_id | uuid | |
author_kind | text | |
kind | text | |
body | text | |
via | text | |
created_at | timestamptz |
support_presence
| Column | Type | |
|---|---|---|
ticket_id | uuid | |
user_id | uuid | |
seen_at | timestamptz |
support_rules
| Column | Type | |
|---|---|---|
id | uuid | |
name | text | |
enabled | boolean | |
position | integer | |
trigger | text | |
conditions | jsonb | |
actions | jsonb |
support_ticket_reads
| Column | Type | |
|---|---|---|
ticket_id | uuid | |
user_id | uuid | |
read_at | timestamptz |
support_tickets
| Column | Type | |
|---|---|---|
id | uuid | |
number | serial | |
requester_user_id | uuid | |
requester_email | text | |
source | text | |
subject | text | |
category_id | uuid | |
priority | text | |
status | text | |
assignee_id | uuid | |
group_id | uuid | |
server_id | uuid | |
subscription_id | uuid | |
suspension_id | uuid | |
tier_id | text | |
first_reply_due_at | timestamptz | |
solve_due_at | timestamptz | |
first_reply_at | timestamptz | |
solved_at | timestamptz | |
closed_at | timestamptz | |
reopen_until | timestamptz | |
rating | smallint | |
rating_comment | text | |
tags | text[] | |
linked_ticket_ids | uuid[] | |
diagnostics | jsonb | |
last_customer_activity_at | timestamptz | |
last_agent_activity_at | timestamptz | |
paused_at | timestamptz | |
created_at | timestamptz | |
updated_at | timestamptz | |
warning_sent_at | timestamptz | |
breach_sent_at | timestamptz |
support_tiers
| Column | Type | |
|---|---|---|
id | text | |
name | text | |
first_reply_minutes | integer | |
solve_minutes | integer | |
warn_percent | integer |
team_transfers
| Column | Type | |
|---|---|---|
token_hash | text | |
sender_id | uuid | |
receiver_id | uuid | |
expires_at | timestamptz | |
created_at | timestamptz |
template_versions
| Column | Type | |
|---|---|---|
template_id | text | |
version | integer | |
snapshot | jsonb | |
created_by | uuid | |
created_at | timestamptz |
templates
| Column | Type | |
|---|---|---|
id | text | |
name | text | |
image | text | |
startup | text | |
internal_ports | jsonb | |
env | jsonb | |
memory_mb | integer | |
cpu_percent | integer | |
disk_mb | integer | |
editable_variables | text[] | |
official | boolean | |
created_at | timestamptz | |
stop_command | text | added later |
addons | jsonb | added later |
description | text | added later |
variables | jsonb | added later |
version | integer | added later |
quick_commands | jsonb | added later |
updated_at | timestamptz | added later |
customer_visible | boolean | added later |
customer_description | text | added later |
runtime | text | added later |
vm_config | jsonb | added later |
usage_reporting
Reporting is disabled until a super-administrator explicitly consents and connects GitHub.
| Column | Type | |
|---|---|---|
singleton | boolean | |
consent | boolean | |
consent_at | timestamptz | |
policy_hash | text | |
installation_id | text | |
secret | text | |
last_activity_at | timestamptz | |
last_report_day | date | |
last_report_version | text | |
next_attempt_at | timestamptz | |
last_error | text | |
withdrawal_pending | boolean | |
withdrawal_until | timestamptz | |
updated_at | timestamptz |
user_tokens
| Column | Type | |
|---|---|---|
token_hash | text | |
user_id | uuid | |
kind | text | |
expires_at | timestamptz | |
created_at | timestamptz | |
payload | jsonb | added later |
users
| Column | Type | |
|---|---|---|
id | uuid | |
email | text | |
password_hash | text | |
role | text | |
disabled | boolean | |
totp_secret | text | |
totp_pending | text | |
created_at | timestamptz | |
quota | jsonb | added later |
notifications_seen_id | bigint | added later |
preferences | jsonb | added later |
status | text | added later |
email_verified_at | timestamptz | added later |
signup_source | text | added later |
terms_version | text | added later |
terms_accepted_at | timestamptz | added later |
terms_ip_hash | text | added later |
deletion_at | timestamptz | added later |
display_name | text | added later |
is_super | boolean | added later |
admin_permissions | text[] | added later |
vm_addresses
| Column | Type | |
|---|---|---|
network_id | uuid | |
address | inet | |
server_id | uuid |
vm_console_tickets
| Column | Type | |
|---|---|---|
token_hash | text | |
server_id | uuid | |
user_id | uuid | |
session_hash | text | |
mode | text | |
expires_at | timestamptz | |
used_at | timestamptz | |
agent_connected | boolean | added later |
vm_media
| Column | Type | |
|---|---|---|
id | uuid | |
name | text | |
kind | text | |
url | text | |
sha256 | text | |
size_bytes | bigint | |
enabled | boolean | |
os | text | |
created_at | timestamptz |
vm_networks
| Column | Type | |
|---|---|---|
id | uuid | |
name | text | |
libvirt_name | text | |
mode | text | |
node_ids | uuid[] | |
gateway | inet | |
prefix | integer | |
dns | inet[] | |
enabled | boolean | |
created_at | timestamptz |
vm_profiles
| Column | Type | |
|---|---|---|
id | uuid | |
name | text | |
config | jsonb | |
enabled | boolean | |
created_at | timestamptz |
vm_snapshots
| Column | Type | |
|---|---|---|
id | uuid | |
server_id | uuid | |
name | text | |
state | text | |
size_mb | bigint | |
job_id | uuid | |
created_at | timestamptz |
webauthn_challenges
| Column | Type | |
|---|---|---|
user_id | uuid | |
kind | text | |
challenge | text | |
expires_at | timestamptz |
