Skip to main content

Integrations

Six external partners, all wrapped in a reliability layer. Every integration goes through a CircuitBreaker. Every webhook is idempotent. Every external call has a defined fallback.

Integration map

Xendit, payments ✅

Purpose: Process all buyer payments, QRIS, BCA Virtual Account, bank transfer.

Outbound calls:

  • POST /v2/invoices, create payment invoice
  • GET /v2/invoices/:id, check invoice status
  • POST /payouts, disburse to seller

Inbound webhooks:

  • invoice.paid, payment confirmed
  • invoice.expired, payment timeout
  • payout.completed, disbursement done

Reliability:

  • HMAC signature verification (timing-safe compare)
  • Idempotency keys on all outbound calls
  • Amount mismatch detection on webhooks
  • 12-hour payment window enforced

Critical guards:

  • Amount mismatch never auto-progresses → PAYMENT_REVIEW
  • Failed HMAC → reject + log to webhook_events
  • Duplicate webhook → idempotency check returns existing outcome

Files:

  • backend/src/infrastructure/adapters/XenditAdapter.ts
  • backend/src/modules/payments/ (invoice + payout webhook controllers)
  • env: XENDIT_API_KEY, XENDIT_WEBHOOK_VERIFICATION_TOKEN

Biteship, shipping ✅

Purpose: Aggregated shipping across all major Indonesian couriers, JNE, J&T, GoSend, AnterAja, Lion Parcel, etc.

Outbound calls:

  • POST /v1/rates/couriers, get shipping rate quote
  • POST /v1/orders, create shipment + generate label
  • GET /v1/trackings/:id, fetch tracking status

Inbound webhooks:

  • order.delivered, package delivered
  • order.returned, return shipment received
  • order.failed, delivery failed

Reliability:

  • Server-side rate quote (prevents client tampering)
  • IDR 2,000 markup added in adapter, not exposed to client
  • Rate cache for 60 seconds in shipping_rates_cache

Status: ✅ Forward shipping live · 🔵 Reverse label for returns planned for v1

Files:

  • backend/src/infrastructure/adapters/BiteshipAdapter.ts
  • backend/src/modules/shipping/ (rates, areas, tracking, label, webhook controllers)
  • env: BITESHIP_API_KEY

Resend, email ✅

Purpose: Transactional email, order confirmations, KTP status updates, payout notifications, password reset, marketing broadcasts.

Outbound calls:

  • POST /emails, send single email
  • POST /emails/batch, send batch

Templates: Stored in email_templates table. Edited via ops portal Email Templates module.

Reliability:

  • Outbox pattern, email creation is async via outbox_events
  • Failed sends retry every 15 minutes
  • Bounce tracking (planned)

Files:

  • backend/src/infrastructure/adapters/ResendAdapter.ts
  • env: RESEND_API_KEY

OpenAI, AI capabilities ✅

Purpose: Three use cases:

  1. KTP OCR, extract identity data from photo
  2. Help center AI bot, customer queries
  3. Ops AI bot, staff SOP guidance

Model: gpt-4o-mini (cost-optimized for high volume)

Reliability:

  • PII redaction layer scrubs sensitive data before API call
  • Rate limiting per user
  • Cost monitoring with daily budget alerts
  • Fallback to keyword matching when API down

KTP OCR pipeline:

Files:

  • backend/src/infrastructure/adapters/OpenAIAdapter.ts
  • backend/src/infrastructure/adapters/KtpOcrAdapter.ts
  • env: OPENAI_API_KEY

Xero, accounting 🟡

Purpose (intended): Sync every order, fee, expense, and disbursement to Xero for accounting and tax compliance.

Current state: Placeholder only. The xero_synced boolean is flipped to true, but no actual Xero API call happens.

What's needed:

  • OAuth 2.0 authentication flow
  • Map orders to Xero invoices
  • Map disbursements to Xero bills
  • Map expenses to Xero expense entries
  • Bidirectional sync for reconciliation

Roadmap: Build before launch (June 2026). Required for proper Indonesian tax compliance.

Files:

  • infrastructure/adapters/XeroAdapter.ts (stub)
  • env: XERO_CLIENT_ID, XERO_CLIENT_SECRET (not yet wired)

Meta Pixel, analytics ✅

Purpose: Track marketing funnel events for Meta ads optimization.

Events fired:

  • PageView, every page load
  • ViewContent, listing detail view
  • Search, filter use
  • AddToWishlist, listing like
  • InitiateCheckout, checkout started
  • AddPaymentInfo, payment method selected
  • Purchase, order confirmed

Privacy: Hashed user IDs only. No PII sent to Meta.

Files:

  • src/app/lib/analytics/meta.ts
  • env: VITE_META_PIXEL_ID

Reliability layer

Three patterns wrap every external integration:

IdempotencyGuard

Prevents duplicate processing on retried operations.

const result = await idempotencyGuard.execute(
`order-create-${orderId}`,
() => xendit.createInvoice(order)
);

If the key has been seen before, returns the original result without re-executing.

Used on: Order creation, all webhooks, all outbound payment calls.

OutboxProcessor

Transactional outbox pattern — writes side effects to outbox_events table within the same transaction as business logic, then a 15-minute in-process cron processes pending events. The cron runs via @nestjs/schedule inside the NestJS backend — not an external or Vercel cron.

Why it matters: If the DB commit succeeds but the email send fails, the email will retry. No lost notifications.

Used for: Notifications, fin_audit_log entries, downstream events.

CircuitBreaker

Wraps every external API call. Opens after N consecutive failures, fails fast for cooldown period, retries.

const breaker = new CircuitBreaker('xendit', {
failureThreshold: 5,
cooldownMs: 30000
});
const result = await breaker.execute(() => xendit.api.call());

Used on: Xendit, Biteship, Resend, OpenAI, Xero adapters.

Why it matters: When Biteship is down, we fail fast with a clear error instead of cascading timeouts.

Webhook security

All inbound webhooks pass through a security pipeline:

Stored in webhook_events table for full audit trail.

Observability

Sentry is live for error tracking across all three runtimes: web (VITE_SENTRY_DSN), NestJS backend (SENTRY_DSN_SERVER), and mobile (sentry_flutter). See Observability for how to read logs and use it for debugging.

Future integrations (planned)

IntegrationPurposePriority
Mixpanel or AmplitudeProduct analytics beyond MetaMedium
AlgoliaSearch infrastructureMedium
TwilioSMS for KTP verificationLow
WhatsApp Business APINative chat integrationLow

Where to look in the codebase

What you wantWhere it lives
Adapter interfacesbackend/src/domain/ports/
Adapter implementationsbackend/src/infrastructure/adapters/
Reliability layerbackend/src/infrastructure/reliability/
Webhook controllersbackend/src/modules/payments/, backend/src/modules/shipping/, backend/src/modules/notifications/
Environment variables.env.example

Next: Automation Roadmap →