Skip to Content
ArchitectureDatabase Schema

Database Schema

Auto-generated from migration SQL files. Do not edit manually. Run make schema-docs to regenerate.

Core Database

roles

ColumnTypeConstraints
idUUIDPRIMARY KEY DEFAULT uuid()
subject_typeVARCHAR(20)NOT NULL
subject_idVARCHAR(255)NOT NULL
roleVARCHAR(50)NOT NULL
merchant_idUUID
created_atTIMESTAMPTZNOT NULL DEFAULT now()
updated_atTIMESTAMPTZNOT NULL DEFAULT now()

Indexes:

  • CREATE INDEX idx_roles_subject ON roles(subject_type, subject_id)
  • CREATE INDEX idx_roles_merchant ON roles(merchant_id) WHERE merchant_id IS NOT NULL

api_keys

ColumnTypeConstraints
idUUIDPRIMARY KEY DEFAULT uuid()
merchant_idUUIDNOT NULL
prefixVARCHAR(16)NOT NULL
key_hashBYTEANOT NULL
nameVARCHAR(255)NOT NULL DEFAULT ”
scopesTEXT[]NOT NULL DEFAULT ''
key_typeVARCHAR(10)NOT NULL
environmentVARCHAR(10)NOT NULL
statusVARCHAR(20)NOT NULL DEFAULT ‘active’
rate_limit_tierVARCHAR(20)NOT NULL DEFAULT ‘standard’
last_used_atTIMESTAMPTZ
expires_atTIMESTAMPTZ
revoked_atTIMESTAMPTZ
created_atTIMESTAMPTZNOT NULL DEFAULT now()
updated_atTIMESTAMPTZNOT NULL DEFAULT now()

Indexes:

  • CREATE UNIQUE INDEX idx_api_keys_prefix_hash ON api_keys(prefix, key_hash)
  • CREATE INDEX idx_api_keys_merchant ON api_keys(merchant_id)
  • CREATE INDEX idx_api_keys_status ON api_keys(status) WHERE status = 'active'

idempotency_keys

ColumnTypeConstraints
idUUIDPRIMARY KEY DEFAULT uuid()
api_key_idUUIDNOT NULL
idempotency_keyVARCHAR(255)NOT NULL
request_methodVARCHAR(10)NOT NULL
request_pathVARCHAR(500)NOT NULL
request_hashBYTEANOT NULL
response_codeINT
response_bodyJSONB
locked_atTIMESTAMPTZ
completed_atTIMESTAMPTZ
created_atTIMESTAMPTZNOT NULL DEFAULT now()

Indexes:

  • CREATE INDEX idx_idempotency_cleanup ON idempotency_keys(created_at)

audit_log

ColumnTypeConstraints
idUUIDPRIMARY KEY DEFAULT uuid()
actor_typeVARCHAR(20)NOT NULL
actor_idVARCHAR(255)NOT NULL
actionVARCHAR(100)NOT NULL
resource_typeVARCHAR(50)NOT NULL
resource_idVARCHAR(255)NOT NULL
merchant_idUUID
metadataJSONBDEFAULT ''
ip_addressINET
correlation_idUUID
created_atTIMESTAMPTZNOT NULL DEFAULT now()

Indexes:

  • CREATE INDEX idx_audit_log_actor ON audit_log(actor_type, actor_id)
  • CREATE INDEX idx_audit_log_resource ON audit_log(resource_type, resource_id)
  • CREATE INDEX idx_audit_log_merchant ON audit_log(merchant_id) WHERE merchant_id IS NOT NULL
  • CREATE INDEX idx_audit_log_created ON audit_log(created_at)

payment_intents

ColumnTypeConstraints
idUUIDPRIMARY KEY DEFAULT uuid()
merchant_idUUIDNOT NULL
amountBIGINTNOT NULL
currencyVARCHAR(3)NOT NULL DEFAULT ‘usd’
statusVARCHAR(30)NOT NULL DEFAULT ‘requires_payment_method’
capture_methodVARCHAR(10)NOT NULL DEFAULT ‘automatic’
gateway_token_idUUID
connector_idVARCHAR(50)
connector_txn_idVARCHAR(255)
connector_statusVARCHAR(50)
error_codeVARCHAR(100)
error_messageTEXT
metadataJSONB
test_modeBOOLEANNOT NULL DEFAULT false
idempotency_keyVARCHAR(255)
created_atTIMESTAMPTZNOT NULL DEFAULT now()
updated_atTIMESTAMPTZNOT NULL DEFAULT now()
captured_atTIMESTAMPTZ
canceled_atTIMESTAMPTZ

Indexes:

  • CREATE INDEX idx_pi_merchant ON payment_intents(merchant_id)
  • CREATE INDEX idx_pi_status ON payment_intents(status) WHERE status NOT IN ('succeeded', 'canceled', 'failed')
  • CREATE INDEX idx_pi_test_mode ON payment_intents(test_mode)
  • CREATE INDEX idx_pi_connector_txn ON payment_intents(connector_txn_id) WHERE connector_txn_id IS NOT NULL
  • CREATE UNIQUE INDEX idx_pi_idempotency ON payment_intents(merchant_id, idempotency_key) WHERE idempotency_key IS NOT NULL

refunds

ColumnTypeConstraints
idUUIDPRIMARY KEY DEFAULT uuid()
payment_intent_idUUIDNOT NULL REFERENCES payment_intents(id)
amountBIGINTNOT NULL
statusVARCHAR(20)NOT NULL DEFAULT ‘pending’
reasonVARCHAR(50)
connector_refund_idVARCHAR(255)
connector_statusVARCHAR(50)
error_codeVARCHAR(100)
error_messageTEXT
test_modeBOOLEANNOT NULL DEFAULT false
idempotency_keyVARCHAR(255)
created_atTIMESTAMPTZNOT NULL DEFAULT now()
updated_atTIMESTAMPTZNOT NULL DEFAULT now()

Indexes:

  • CREATE INDEX idx_refunds_pi ON refunds(payment_intent_id)
  • CREATE INDEX idx_refunds_test_mode ON refunds(test_mode)

Alter: payment_intents

Migration: 007_add_bin_auth_data.sql

ColumnTypeNote
binVARCHAR(8)Added
auth_codeVARCHAR(20)Added
avs_resultVARCHAR(5)Added
cvv_resultVARCHAR(5)Added
decline_codeVARCHAR(50)Added
response_time_msINTEGERAdded

Indexes:

  • CREATE INDEX idx_pi_bin ON payment_intents(bin) WHERE bin IS NOT NULL

merchant_routing_configs

ColumnTypeConstraints
idUUIDPRIMARY KEY DEFAULT uuid()
merchant_idUUIDNOT NULL UNIQUE
default_connector_idVARCHAR(50)NOT NULL
failover_connector_idVARCHAR(50)
created_atTIMESTAMPTZNOT NULL DEFAULT now()
updated_atTIMESTAMPTZNOT NULL DEFAULT now()

Indexes:

  • CREATE INDEX idx_mrc_merchant ON merchant_routing_configs(merchant_id)

raw_webhook_events

ColumnTypeConstraints
idUUIDPRIMARY KEY DEFAULT uuid()
connector_idVARCHAR(50)NOT NULL
connector_event_idVARCHAR(255)
event_hashVARCHAR(64)NOT NULL
headersJSONBNOT NULL
bodyBYTEANOT NULL
signature_validBOOLEANNOT NULL DEFAULT false
processedBOOLEANNOT NULL DEFAULT false
received_atTIMESTAMPTZNOT NULL DEFAULT now()

Indexes:

  • CREATE UNIQUE INDEX idx_raw_webhook_connector_event
  • CREATE UNIQUE INDEX idx_raw_webhook_event_hash
  • CREATE INDEX idx_raw_webhook_unprocessed

webhook_endpoints

ColumnTypeConstraints
idUUIDPRIMARY KEY DEFAULT uuid()
merchant_idUUIDNOT NULL
urlVARCHAR(2048)NOT NULL
secretVARCHAR(255)NOT NULL
enabledBOOLEANNOT NULL DEFAULT true
event_typesTEXT[]NOT NULL DEFAULT ''
descriptionTEXT
created_atTIMESTAMPTZNOT NULL DEFAULT now()
updated_atTIMESTAMPTZNOT NULL DEFAULT now()

Indexes:

  • CREATE INDEX idx_webhook_endpoints_merchant
  • CREATE INDEX idx_webhook_endpoints_enabled

normalized_events

ColumnTypeConstraints
idUUIDPRIMARY KEY DEFAULT uuid()
raw_webhook_event_idUUIDNOT NULL REFERENCES raw_webhook_events(id)
event_typeVARCHAR(50)NOT NULL
payment_intent_idUUID
merchant_idUUIDNOT NULL
connector_idVARCHAR(50)NOT NULL
dataJSONBNOT NULL
created_atTIMESTAMPTZNOT NULL DEFAULT now()

Indexes:

  • CREATE INDEX idx_normalized_events_pi
  • CREATE INDEX idx_normalized_events_merchant
  • CREATE INDEX idx_normalized_events_type

webhook_delivery_attempts

ColumnTypeConstraints
idUUIDPRIMARY KEY DEFAULT uuid()
normalized_event_idUUIDNOT NULL REFERENCES normalized_events(id)
webhook_endpoint_idUUIDNOT NULL REFERENCES webhook_endpoints(id)
attempt_numberINTNOT NULL DEFAULT 1
statusVARCHAR(20)NOT NULL DEFAULT ‘pending’
response_codeINT
response_bodyTEXT
error_messageTEXT
dead_letterBOOLEANNOT NULL DEFAULT false
next_retry_atTIMESTAMPTZ
attempted_atTIMESTAMPTZNOT NULL DEFAULT now()

Indexes:

  • CREATE INDEX idx_delivery_pending
  • CREATE INDEX idx_delivery_dlq
  • CREATE INDEX idx_delivery_event

iso_entities

ColumnTypeConstraints
idUUIDPRIMARY KEY DEFAULT uuid()
parent_idUUIDREFERENCES iso_entities(id)
nameVARCHAR(255)NOT NULL
statusVARCHAR(20)NOT NULL DEFAULT ‘active’
created_atTIMESTAMPTZNOT NULL DEFAULT now()
updated_atTIMESTAMPTZNOT NULL DEFAULT now()

Indexes:

  • CREATE INDEX idx_iso_parent ON iso_entities(parent_id)

gateway_price_plans

ColumnTypeConstraints
idUUIDPRIMARY KEY DEFAULT uuid()
scopeVARCHAR(20)NOT NULL
scope_idUUID
versionINTNOT NULL DEFAULT 1
per_txn_flat_centsBIGINTNOT NULL DEFAULT 0
per_txn_basis_pointsBIGINTNOT NULL DEFAULT 0
monthly_fee_centsBIGINTNOT NULL DEFAULT 0
effective_dateTIMESTAMPTZNOT NULL DEFAULT now()
created_byVARCHAR(255)
created_atTIMESTAMPTZNOT NULL DEFAULT now()

Indexes:

  • CREATE INDEX idx_price_plan_scope ON gateway_price_plans(scope, scope_id)
  • CREATE INDEX idx_price_plan_effective ON gateway_price_plans(effective_date)

usage_events

ColumnTypeConstraints
idUUIDPRIMARY KEY DEFAULT uuid()
merchant_idUUIDNOT NULL
event_typeVARCHAR(30)NOT NULL
periodVARCHAR(7)NOT NULL
countBIGINTNOT NULL DEFAULT 1
amount_centsBIGINTNOT NULL DEFAULT 0
transaction_idUUID
created_atTIMESTAMPTZNOT NULL DEFAULT now()

Indexes:

  • CREATE INDEX idx_usage_merchant_period ON usage_events(merchant_id, period)
  • CREATE INDEX idx_usage_period ON usage_events(period)

financial_ledger

ColumnTypeConstraints
idUUIDPRIMARY KEY DEFAULT uuid()
merchant_idUUIDNOT NULL
iso_idUUID
event_typeVARCHAR(30)NOT NULL
amount_centsBIGINTNOT NULL
pricing_plan_idUUIDNOT NULL
pricing_plan_versionINTNOT NULL
transaction_idUUID
periodVARCHAR(7)NOT NULL
created_atTIMESTAMPTZNOT NULL DEFAULT now()

Indexes:

  • CREATE INDEX idx_ledger_merchant_period ON financial_ledger(merchant_id, period)
  • CREATE INDEX idx_ledger_iso_period ON financial_ledger(iso_id, period) WHERE iso_id IS NOT NULL
  • CREATE INDEX idx_ledger_transaction ON financial_ledger(transaction_id) WHERE transaction_id IS NOT NULL

pci_attestations

ColumnTypeConstraints
idUUIDPRIMARY KEY DEFAULT uuid()
merchant_idUUIDNOT NULL
attestation_typeVARCHAR(50)NOT NULL
effective_dateDATENOT NULL
expiry_dateDATENOT NULL
document_refVARCHAR(512)
reviewed_byVARCHAR(255)
review_notesTEXT
last_verified_atTIMESTAMPTZ
created_atTIMESTAMPTZNOT NULL DEFAULT now()
updated_atTIMESTAMPTZNOT NULL DEFAULT now()

Indexes:

  • CREATE INDEX idx_attestation_merchant ON pci_attestations(merchant_id)
  • CREATE INDEX idx_attestation_expiry ON pci_attestations(expiry_date)

merchants

ColumnTypeConstraints
idUUIDPRIMARY KEY DEFAULT uuid()
iso_idUUIDREFERENCES iso_entities(id)
nameVARCHAR(255)NOT NULL
statusVARCHAR(20)NOT NULL DEFAULT ‘active’
created_atTIMESTAMPTZNOT NULL DEFAULT now()
updated_atTIMESTAMPTZNOT NULL DEFAULT now()

Indexes:

  • CREATE INDEX idx_merchant_iso ON merchants(iso_id) WHERE iso_id IS NOT NULL

card_metadata

ColumnTypeConstraints
gateway_tokenTEXTPRIMARY KEY
gateway_token_idUUID
last4TEXTNOT NULL
binTEXTNOT NULL DEFAULT ”
card_brandTEXTNOT NULL DEFAULT ”
created_atTIMESTAMPTZNOT NULL DEFAULT now()

Indexes:

  • CREATE INDEX idx_card_metadata_created_at ON card_metadata (created_at)
  • CREATE INDEX idx_card_metadata_gateway_token_id ON card_metadata (gateway_token_id) WHERE gateway_token_id IS NOT NULL

PCI Database (Vault)

vaulted_cards

ColumnTypeConstraints
idUUIDPRIMARY KEY DEFAULT uuid()
pan_fingerprintBYTEANOT NULL
encrypted_panBYTEANOT NULL
wrapped_dekBYTEANOT NULL
kms_key_versionTEXTNOT NULL
binVARCHAR(8)NOT NULL
last4VARCHAR(4)NOT NULL
exp_monthSMALLINT
exp_yearSMALLINT
card_brandVARCHAR(20)
created_atTIMESTAMPTZNOT NULL DEFAULT now()

Indexes:

  • CREATE UNIQUE INDEX idx_vaulted_cards_fingerprint ON vaulted_cards(pan_fingerprint)

gateway_tokens

ColumnTypeConstraints
idUUIDPRIMARY KEY DEFAULT uuid()
tokenVARCHAR(40)NOT NULL
vaulted_card_idUUIDNOT NULL REFERENCES vaulted_cards(id)
merchant_idUUIDNOT NULL
merchant_fingerprintBYTEANOT NULL
environmentVARCHAR(10)NOT NULL
created_atTIMESTAMPTZNOT NULL DEFAULT now()

Indexes:

  • CREATE UNIQUE INDEX idx_gateway_tokens_token ON gateway_tokens(token)
  • CREATE UNIQUE INDEX idx_gateway_tokens_merchant_fp ON gateway_tokens(merchant_fingerprint)
  • CREATE INDEX idx_gateway_tokens_merchant ON gateway_tokens(merchant_id)
  • CREATE INDEX idx_gateway_tokens_card ON gateway_tokens(vaulted_card_id)

processor_tokens

ColumnTypeConstraints
idUUIDPRIMARY KEY DEFAULT uuid()
gateway_token_idUUIDNOT NULL REFERENCES gateway_tokens(id)
connector_idVARCHAR(50)NOT NULL
processor_tokenVARCHAR(255)NOT NULL
processor_metadataJSONBDEFAULT ''
created_atTIMESTAMPTZNOT NULL DEFAULT now()

Indexes:

  • CREATE UNIQUE INDEX idx_processor_tokens_gateway_connector ON processor_tokens(gateway_token_id, connector_id)

decrypt_tokens

ColumnTypeConstraints
idUUIDPRIMARY KEY DEFAULT uuid()
gateway_token_idUUIDNOT NULL REFERENCES gateway_tokens(id)
requester_serviceVARCHAR(50)NOT NULL
expires_atTIMESTAMPTZNOT NULL
used_atTIMESTAMPTZ
created_atTIMESTAMPTZNOT NULL DEFAULT now()

Indexes:

  • CREATE INDEX idx_decrypt_tokens_gateway ON decrypt_tokens(gateway_token_id)
  • CREATE INDEX idx_decrypt_tokens_expires ON decrypt_tokens(expires_at) WHERE used_at IS NULL