Layers
┌───────────────┐ ┌───────────────┐ ┌─────────────────────┐
│ Controllers │──▶│ Services │──▶│ Models / MongoDB │
│ (HTTP + DTOs) │ │ (business) │ │ (Mongoose) │
└───────────────┘ └──────┬────────┘ └─────────────────────┘
▲ │
│ ▼
┌───────────────┐ ┌─────────────────────────────────────────┐
│ Guards/Pipes │ │ Providers: Xendit · Midtrans · Mayar.id │
│ JWT/API-Key │ └─────────────────────────────────────────┘
└───────────────┘
Modules
- Applications — register apps, generate API keys, configure webhooks (JWT).
- Payments — payments, payment links, subscriptions and provider integrations (API key).
- Admin — dashboard APIs and the CMS UI.
- Docs — this documentation website.
- Common — guards (
JwtAuthGuard,ApiKeyGuard), decorators and the JWT strategy.
Provider abstraction
Every gateway implements PaymentProvider (and SubscriptionProvider
for recurring billing). PaymentsService.getProvider() maps the request's
provider enum to an implementation, so adding Mayar.id required no change to
the request contract.
enum PaymentProvider {
XENDIT = 'XENDIT',
MIDTRANS = 'MIDTRANS',
MAYAR = 'MAYAR',
}
Payment flow
POST /paymentswith anX-API-Key.ApiKeyGuardresolves the application.PaymentsServiceselects the provider and callscreatePayment.- The provider calls the gateway and returns an
externalId+checkoutUrl. - The payment is stored with status
PENDING. - On callback, the status is reconciled and forwarded to the application's webhook.
Data model
MongoDB collections defined as Mongoose schemas. Every document uses an
ObjectId _id, serialized to the API as id.
| Collection | Key fields |
|---|---|
applications | _id, name, apiKey, webhookUrl, subscriptionWebhookUrl, isActive, createdAt, updatedAt |
payments | _id, applicationId (ref), externalId, amount, status, provider, paymentMethod, checkoutUrl, metadata, processedAt, createdAt, updatedAt |
subscriptions | _id, applicationId (ref), externalSubscriptionId, amount, status, provider, billingCycle, nextBillingDate, createdAt, updatedAt |
Security
- JWT for application management; API keys for payment endpoints.
- Input validation via
class-validatorDTOs. - Provider callbacks verified by token or SHA256 signature.
- Secrets kept in environment variables.