Skip to main content

Prerequisites

  • The web app is reachable locally.
  • You have a target workspace id.
  • ENABLE_SEPAY_INTEGRATION=true is set in workspace_secrets.
  • The web runtime is configured with:
    • SEPAY_OAUTH_CLIENT_ID
    • SEPAY_OAUTH_CLIENT_SECRET
    • SEPAY_OAUTH_TOKEN_ENCRYPTION_SECRET
    • SEPAY_WEBHOOK_API_KEY or SEPAY_WEBHOOK_SECRET
    • WEB_APP_URL or NEXT_PUBLIC_WEB_APP_URL or NEXT_PUBLIC_APP_URL
  • Optional overrides:
    • SEPAY_OAUTH_AUTHORIZE_URL
    • SEPAY_OAUTH_BASE_URL
    • SEPAY_API_BASE_URL

Enable The Workspace Flag

Validate OAuth

  1. Start OAuth from the same browser session that will receive the callback.
  2. Call:
  1. Open the returned authorizeUrl.
  2. Complete SePay consent.
  3. Confirm the callback succeeds and the workspace receives a SePay connection.

Validate Provisioning

Expected:
  • At least one active endpoint.
  • token_prefix is present.
  • sepay_webhook_id is present after provisioning.
Database checks:

Validate Webhook Ingestion

Expected:
  • The API returns success, or duplicate-safe success on replay.
  • A sepay_webhook_events row exists for evt_test_001.
  • A wallet_transactions row exists and is linked through created_transaction_id.
  • transactionDate should always include an explicit timezone such as +07:00. Bare YYYY-MM-DD HH:mm:ss strings are interpreted as Vietnam time (UTC+7) for SePay compatibility; omitting the timezone in test payloads is a fixture bug, not a supported operator shortcut.
Verification query:

Idempotency

Resend the exact same payload with the same id. Expected:
  • No duplicate transaction is inserted.
  • The event is treated as a duplicate/no-op.

Expense Direction

Send a payload with transferType: "out" and a positive transferAmount. Expected:
  • wallet_transactions.amount is stored as a negative value.
  • The transaction resolves against an expense category.

Endpoint Lifecycle

  1. Create an endpoint.
  2. Rotate the endpoint.
  3. Delete the endpoint.
Expected:
  • Deleted endpoints have active = false.
  • Deleted endpoints have deleted_at is not null.
  • Listing routes exclude deleted endpoints.
  • Token resolution ignores deleted endpoints.

Disconnect

Expected:
  • sepay_connections.status = 'revoked'
  • Active endpoints are marked inactive and soft-deleted.

Failure Paths

  • Invalid webhook auth header is rejected.
  • Invalid webhook JSON body returns a validation error.
  • Unknown endpoint token is rejected.
  • Disabled feature flag blocks SePay workspace APIs.

Troubleshooting

  • OAuth start failures usually mean missing OAuth env vars or app-origin config.
  • OAuth callback state failures usually mean the callback did not reuse the browser session or cookie jar that started OAuth.
  • Provisioning failures usually mean SePay has no usable bank account or the webhook scopes were not granted.
  • Missing transactions should be debugged from sepay_webhook_events.failure_reason first.