package models import ( "encoding/json" "time" "github.com/google/uuid" ) // APIError is the standard error envelope across FlatRender services. type APIError struct { Code string `json:"code"` Message string `json:"message"` } // ── Client apps (tenants of the broker — each site that pays through it) ─────── type ClientApp struct { ID uuid.UUID `json:"id"` TenantID *uuid.UUID `json:"tenant_id,omitempty"` Name string `json:"name"` Slug string `json:"slug"` APIKey string `json:"api_key"` Secret string `json:"secret,omitempty"` // returned only on create / rotate ZarinPalMerchantID *string `json:"zarinpal_merchant_id,omitempty"` ZarinPalSandbox *bool `json:"zarinpal_sandbox,omitempty"` AllowedReturnOrigins []string `json:"allowed_return_origins"` WebhookURL *string `json:"webhook_url,omitempty"` IsActive bool `json:"is_active"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } // ── Transactions ────────────────────────────────────────────────────────────── type Transaction struct { ID uuid.UUID `json:"id"` ClientAppID uuid.UUID `json:"client_app_id"` ClientSlug string `json:"client_slug,omitempty"` // joined for admin views Status string `json:"status"` Gateway string `json:"gateway"` AmountRial int64 `json:"amount_rial"` Currency string `json:"currency"` Description *string `json:"description,omitempty"` ClientRef *string `json:"client_ref,omitempty"` ReturnURL string `json:"return_url"` Metadata json.RawMessage `json:"metadata,omitempty"` PayerMobile *string `json:"payer_mobile,omitempty"` PayerEmail *string `json:"payer_email,omitempty"` Authority *string `json:"authority,omitempty"` RefID *string `json:"ref_id,omitempty"` CardPan *string `json:"card_pan,omitempty"` FeeRial *int64 `json:"fee_rial,omitempty"` GatewayResponse json.RawMessage `json:"gateway_response,omitempty"` FailureReason *string `json:"failure_reason,omitempty"` PaidAt *time.Time `json:"paid_at,omitempty"` FailedAt *time.Time `json:"failed_at,omitempty"` ExpiresAt *time.Time `json:"expires_at,omitempty"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } // Transaction status values (kept as plain text — no PG enum, for flexibility). const ( StatusCreated = "Created" StatusPending = "Pending" StatusPaid = "Paid" StatusFailed = "Failed" StatusCancelled = "Cancelled" StatusExpired = "Expired" ) // ── Client-facing request/response shapes ───────────────────────────────────── // PayRequest is the body a client site POSTs to /v1/pay/request. type PayRequest struct { Amount int64 `json:"amount"` // in `currency` units Currency string `json:"currency,omitempty"` // "IRR" (Rial, default) or "IRT" (Toman) Description string `json:"description,omitempty"` ClientRef string `json:"client_ref,omitempty"` ReturnURL string `json:"return_url"` Mobile string `json:"mobile,omitempty"` Email string `json:"email,omitempty"` Metadata json.RawMessage `json:"metadata,omitempty"` } // PayResponse is returned from /v1/pay/request. type PayResponse struct { ID uuid.UUID `json:"id"` Status string `json:"status"` PaymentURL string `json:"payment_url"` Authority string `json:"authority"` AmountRial int64 `json:"amount_rial"` } // WebhookPayload is the signed body POSTed to a client's webhook_url. type WebhookPayload struct { Event string `json:"event"` // payment.paid | payment.failed ID uuid.UUID `json:"id"` Status string `json:"status"` AmountRial int64 `json:"amount_rial"` Currency string `json:"currency"` ClientRef string `json:"client_ref,omitempty"` RefID string `json:"ref_id,omitempty"` Authority string `json:"authority,omitempty"` CardPan string `json:"card_pan,omitempty"` Metadata json.RawMessage `json:"metadata,omitempty"` PaidAt *time.Time `json:"paid_at,omitempty"` CreatedAtTs int64 `json:"ts"` }