mirror of
https://github.com/luxfi/treasury.git
synced 2026-10-30 15:15:00 +00:00
Follow-up to v1.1.9 (which threaded IdempotencyKey through CreatePayment +
CreateFXConversion). Adds:
provider.CreateAccountRequest.IdempotencyKey string
types.Counterparty.IdempotencyKey string
Per-adapter forwarding:
CreateAccount: column, currencycloud, increase, lithic, moderntreasury,
stripe, unit (7 adapters via doRequestIdem or
unique_request_id form field for CC)
CreateCounterparty: column, currencycloud, moderntreasury, wise (4)
Skipped (provider doesn't support the call):
mercury — accounts created dashboard-only
wise — same for CreateAccount
bridge — counterparty not applicable to chain bridge
mpesa, square — out of scope (no counterparty API)
Stubs (marqeta, plaid) unaffected — deregistered in v1.1.9.
Empty key → adapter derives via provider.DeriveIdempotencyKey
(SHA-256 over canonical request fields). Same retry → same key.
294 lines
12 KiB
Go
294 lines
12 KiB
Go
package types
|
|
|
|
import "time"
|
|
|
|
// --- Core Banking Types ---
|
|
|
|
// BankAccount represents an external or virtual bank account.
|
|
type BankAccount struct {
|
|
ID string `json:"id"`
|
|
Provider string `json:"provider"`
|
|
ProviderID string `json:"provider_id"`
|
|
OrgID string `json:"org_id"`
|
|
AccountName string `json:"account_name"`
|
|
AccountNumber string `json:"account_number,omitempty"`
|
|
RoutingNumber string `json:"routing_number,omitempty"`
|
|
IBAN string `json:"iban,omitempty"`
|
|
SwiftBIC string `json:"swift_bic,omitempty"`
|
|
SortCode string `json:"sort_code,omitempty"`
|
|
BankName string `json:"bank_name,omitempty"`
|
|
BankCountry string `json:"bank_country,omitempty"`
|
|
Currency string `json:"currency"`
|
|
AccountType string `json:"account_type"` // checking, savings, virtual
|
|
Status string `json:"status"` // active, pending, closed
|
|
Balance *Balance `json:"balance,omitempty"`
|
|
Meta map[string]string `json:"meta,omitempty"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
}
|
|
|
|
// Balance represents account balance with available/pending breakdown.
|
|
type Balance struct {
|
|
Available string `json:"available"`
|
|
Current string `json:"current"`
|
|
Pending string `json:"pending,omitempty"`
|
|
Currency string `json:"currency"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
}
|
|
|
|
// --- Payment Types ---
|
|
|
|
// Payment represents a fund movement (ACH, wire, SEPA, SWIFT, book transfer).
|
|
type Payment struct {
|
|
ID string `json:"id"`
|
|
Provider string `json:"provider"`
|
|
ProviderID string `json:"provider_id"`
|
|
OrgID string `json:"org_id"`
|
|
Type PaymentType `json:"type"`
|
|
Direction string `json:"direction"` // credit, debit
|
|
Amount string `json:"amount"`
|
|
Currency string `json:"currency"`
|
|
Status PaymentStatus `json:"status"`
|
|
SourceAccountID string `json:"source_account_id,omitempty"`
|
|
DestAccountID string `json:"dest_account_id,omitempty"`
|
|
Counterparty *Counterparty `json:"counterparty,omitempty"`
|
|
Reference string `json:"reference,omitempty"`
|
|
Description string `json:"description,omitempty"`
|
|
FeeAmount string `json:"fee_amount,omitempty"`
|
|
FeeCurrency string `json:"fee_currency,omitempty"`
|
|
ExchangeRate string `json:"exchange_rate,omitempty"`
|
|
SettlementDate string `json:"settlement_date,omitempty"`
|
|
Meta map[string]string `json:"meta,omitempty"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
}
|
|
|
|
type PaymentType string
|
|
|
|
const (
|
|
PaymentACH PaymentType = "ach"
|
|
PaymentWire PaymentType = "wire"
|
|
PaymentSEPA PaymentType = "sepa"
|
|
PaymentSWIFT PaymentType = "swift"
|
|
PaymentBook PaymentType = "book" // internal transfer
|
|
PaymentRTP PaymentType = "rtp" // real-time payments
|
|
PaymentFedNow PaymentType = "fednow"
|
|
PaymentCheck PaymentType = "check"
|
|
PaymentCard PaymentType = "card"
|
|
)
|
|
|
|
type PaymentStatus string
|
|
|
|
const (
|
|
PaymentPending PaymentStatus = "pending"
|
|
PaymentProcessing PaymentStatus = "processing"
|
|
PaymentCompleted PaymentStatus = "completed"
|
|
PaymentFailed PaymentStatus = "failed"
|
|
PaymentCancelled PaymentStatus = "cancelled"
|
|
PaymentReturned PaymentStatus = "returned"
|
|
)
|
|
|
|
// CreatePaymentRequest for initiating payments.
|
|
type CreatePaymentRequest struct {
|
|
Type PaymentType `json:"type"`
|
|
Direction string `json:"direction"`
|
|
Amount string `json:"amount"`
|
|
Currency string `json:"currency"`
|
|
SourceAccountID string `json:"source_account_id"`
|
|
DestAccountID string `json:"dest_account_id,omitempty"`
|
|
Counterparty *Counterparty `json:"counterparty,omitempty"`
|
|
Reference string `json:"reference,omitempty"`
|
|
Description string `json:"description,omitempty"`
|
|
Meta map[string]string `json:"meta,omitempty"`
|
|
// IdempotencyKey is a caller-supplied token forwarded to the upstream
|
|
// provider's idempotency header (e.g. Column "Idempotency-Key", Wise
|
|
// "X-idempotence-uuid", Square body field "idempotency_key"). A retry
|
|
// with the same key MUST be safe at the provider. If empty, adapters
|
|
// fall back to a deterministic SHA-256 of (orgID || endpoint ||
|
|
// canonical request body) via provider.DeriveIdempotencyKey — never a
|
|
// wall-clock-derived value.
|
|
IdempotencyKey string `json:"idempotency_key,omitempty"`
|
|
// OrgID is folded into the deterministic-fallback key so two orgs
|
|
// sending identical bodies do not collide on a single provider key.
|
|
OrgID string `json:"org_id,omitempty"`
|
|
}
|
|
|
|
// Counterparty is the external party in a payment.
|
|
type Counterparty struct {
|
|
ID string `json:"id,omitempty"`
|
|
Name string `json:"name"`
|
|
AccountNumber string `json:"account_number,omitempty"`
|
|
RoutingNumber string `json:"routing_number,omitempty"`
|
|
IBAN string `json:"iban,omitempty"`
|
|
SwiftBIC string `json:"swift_bic,omitempty"`
|
|
BankName string `json:"bank_name,omitempty"`
|
|
BankCountry string `json:"bank_country,omitempty"`
|
|
Email string `json:"email,omitempty"`
|
|
|
|
// IdempotencyKey, if non-empty, is forwarded as the provider's
|
|
// idempotency header / field on counterparty creation. Empty →
|
|
// adapter derives one deterministically via DeriveIdempotencyKey.
|
|
IdempotencyKey string `json:"idempotency_key,omitempty"`
|
|
}
|
|
|
|
// --- FX Types ---
|
|
|
|
// FXQuote is a foreign exchange rate quote.
|
|
type FXQuote struct {
|
|
ID string `json:"id"`
|
|
Provider string `json:"provider"`
|
|
SellCurrency string `json:"sell_currency"`
|
|
BuyCurrency string `json:"buy_currency"`
|
|
SellAmount string `json:"sell_amount,omitempty"`
|
|
BuyAmount string `json:"buy_amount,omitempty"`
|
|
Rate string `json:"rate"`
|
|
InverseRate string `json:"inverse_rate,omitempty"`
|
|
FixedSide string `json:"fixed_side"` // buy or sell
|
|
ExpiresAt time.Time `json:"expires_at"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
// FXConversion is an executed currency conversion.
|
|
type FXConversion struct {
|
|
ID string `json:"id"`
|
|
Provider string `json:"provider"`
|
|
ProviderID string `json:"provider_id"`
|
|
QuoteID string `json:"quote_id,omitempty"`
|
|
SellCurrency string `json:"sell_currency"`
|
|
BuyCurrency string `json:"buy_currency"`
|
|
SellAmount string `json:"sell_amount"`
|
|
BuyAmount string `json:"buy_amount"`
|
|
Rate string `json:"rate"`
|
|
SettlementDate string `json:"settlement_date"`
|
|
Status string `json:"status"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
// CreateFXConversionRequest for currency conversion.
|
|
type CreateFXConversionRequest struct {
|
|
SellCurrency string `json:"sell_currency"`
|
|
BuyCurrency string `json:"buy_currency"`
|
|
Amount string `json:"amount"`
|
|
FixedSide string `json:"fixed_side"` // buy or sell
|
|
QuoteID string `json:"quote_id,omitempty"`
|
|
// IdempotencyKey — see CreatePaymentRequest.IdempotencyKey.
|
|
IdempotencyKey string `json:"idempotency_key,omitempty"`
|
|
// OrgID — see CreatePaymentRequest.OrgID.
|
|
OrgID string `json:"org_id,omitempty"`
|
|
}
|
|
|
|
// --- Multi-Currency Wallet Types ---
|
|
|
|
// Wallet is a multi-currency virtual account/wallet.
|
|
type Wallet struct {
|
|
ID string `json:"id"`
|
|
Provider string `json:"provider"`
|
|
OrgID string `json:"org_id"`
|
|
Name string `json:"name"`
|
|
Balances []Balance `json:"balances"`
|
|
Status string `json:"status"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
// --- Card Types ---
|
|
|
|
// Card represents an issued payment card.
|
|
type Card struct {
|
|
ID string `json:"id"`
|
|
Provider string `json:"provider"`
|
|
ProviderID string `json:"provider_id"`
|
|
OrgID string `json:"org_id"`
|
|
Last4 string `json:"last4"`
|
|
Brand string `json:"brand"` // visa, mastercard
|
|
Type string `json:"type"` // virtual, physical
|
|
Currency string `json:"currency"`
|
|
SpendLimit string `json:"spend_limit,omitempty"`
|
|
SpendInterval string `json:"spend_interval,omitempty"` // per_transaction, daily, monthly
|
|
Status string `json:"status"`
|
|
ExpiresAt string `json:"expires_at"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
// CreateCardRequest for card issuance.
|
|
type CreateCardRequest struct {
|
|
Type string `json:"type"` // virtual, physical
|
|
Currency string `json:"currency"`
|
|
SpendLimit string `json:"spend_limit,omitempty"`
|
|
SpendInterval string `json:"spend_interval,omitempty"`
|
|
CardholderID string `json:"cardholder_id"`
|
|
}
|
|
|
|
// --- Identity/KYC Types ---
|
|
|
|
// IdentityVerification is the result of a KYC/identity check.
|
|
type IdentityVerification struct {
|
|
ID string `json:"id"`
|
|
Provider string `json:"provider"`
|
|
ProviderID string `json:"provider_id"`
|
|
Status string `json:"status"` // pending, verified, failed
|
|
Level string `json:"level"` // basic, enhanced, full
|
|
Checks []KYCCheck `json:"checks"`
|
|
Meta map[string]string `json:"meta,omitempty"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
VerifiedAt *time.Time `json:"verified_at,omitempty"`
|
|
}
|
|
|
|
type KYCCheck struct {
|
|
Type string `json:"type"` // document, address, sanctions, pep
|
|
Status string `json:"status"` // pass, fail, pending, review
|
|
Detail string `json:"detail,omitempty"`
|
|
}
|
|
|
|
// --- Ledger Types ---
|
|
|
|
// LedgerEntry is a double-entry bookkeeping record.
|
|
type LedgerEntry struct {
|
|
ID string `json:"id"`
|
|
LedgerID string `json:"ledger_id"`
|
|
TransactionID string `json:"transaction_id"`
|
|
AccountID string `json:"account_id"`
|
|
Amount string `json:"amount"`
|
|
Currency string `json:"currency"`
|
|
Direction string `json:"direction"` // debit, credit
|
|
Status string `json:"status"` // pending, posted, archived
|
|
Description string `json:"description,omitempty"`
|
|
EffectiveDate string `json:"effective_date"`
|
|
PostedAt time.Time `json:"posted_at"`
|
|
}
|
|
|
|
// LedgerAccount is a bookkeeping account in the ledger.
|
|
type LedgerAccount struct {
|
|
ID string `json:"id"`
|
|
Name string `json:"name"`
|
|
Type string `json:"type"` // asset, liability, equity, revenue, expense
|
|
Currency string `json:"currency"`
|
|
Balance string `json:"balance"`
|
|
Status string `json:"status"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
// --- Webhook Types ---
|
|
|
|
// WebhookEvent is a normalized event from any treasury provider.
|
|
type WebhookEvent struct {
|
|
ID string `json:"id"`
|
|
Provider string `json:"provider"`
|
|
Type string `json:"type"` // payment.completed, payment.failed, fx.settled, etc.
|
|
ResourceID string `json:"resource_id"`
|
|
Data interface{} `json:"data"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
// --- Provider Capability ---
|
|
|
|
// ProviderCapability describes what a treasury provider supports.
|
|
type ProviderCapability struct {
|
|
Name string `json:"name"`
|
|
PaymentTypes []string `json:"payment_types"` // ach, wire, sepa, swift, rtp, fednow
|
|
Currencies []string `json:"currencies"` // USD, EUR, GBP, etc.
|
|
Features []string `json:"features"` // fx, cards, ledger, kyc, wallets
|
|
Countries []string `json:"countries"` // supported countries
|
|
SettlementSpeed string `json:"settlement_speed"` // instant, same_day, t+1, t+2
|
|
Status string `json:"status"`
|
|
}
|