Multi-Provider Payment Gateway Backend
PayLink is a production-grade payment orchestration service that provides a unified API for creating payment checkouts across multiple payment providers. Built with Go for high performance and reliability.
- Overview
- Features
- Architecture
- Getting Started
- Configuration
- API Reference
- Development
- Testing
- Deployment
- Security
- Contributing
- License
PayLink abstracts the complexity of integrating multiple payment providers into a single, consistent API. Whether you are processing payments through Midtrans, Xendit, or Stripe, PayLink handles the provider-specific logic, webhook verification, and transaction management.
| Benefit | Description |
|---|---|
| Provider Agnostic | Single API interface for all payment providers |
| Webhook Management | Automatic signature verification and idempotent processing |
| Horizontal Scaling | Stateless design supports multiple instances |
| Observable | Structured logging and metrics-ready architecture |
| Secure | Constant-time signature verification, no secrets in code |
- Unified Checkout API - Create payment sessions with any supported provider
- Webhook Processing - Secure, idempotent webhook handling with async job processing
- Transaction Management - Query transaction status across providers
- Background Workers - Asynchronous job processing for webhooks and reconciliation
| Provider | Status | Documentation |
|---|---|---|
| Midtrans | Supported | Midtrans Docs |
| Xendit | Supported | Xendit Docs |
| Stripe | Planned | Stripe Docs |
Client Request
|
v
+-------------------------------------------------------------------------+
| PayLink API Server |
| |
| +-------------+ +-------------+ +-------------+ |
| | Routes | -> | Middleware | -> | Handlers | |
| +-------------+ +-------------+ +-------------+ |
| | |
| v |
| +-------------------------------------------------------------+ |
| | Adapter Layer | |
| | +-----------+ +-----------+ +-----------+ | |
| | | Midtrans | | Xendit | | Stripe | | |
| | +-----------+ +-----------+ +-----------+ | |
| +-------------------------------------------------------------+ |
+-------------------------------------------------------------------------+
| | |
v v v
+-----------+ +-----------+ +-------------------+
| PostgreSQL| | Redis | | Payment Providers |
+-----------+ +-----------+ +-------------------+
| Component | Purpose |
|---|---|
| API Server | HTTP request handling and routing |
| Adapters | Provider-specific payment logic |
| Worker | Async webhook and reconciliation processing |
| PostgreSQL | Transaction and webhook storage |
| Redis | Job queue and idempotency keys |
For detailed architecture information, see docs/architecture.md.
- Docker and Docker Compose
- Git
- Clone the repository
git clone https://github.com/vibeswithkk/Paylink.git
cd Paylink- Configure environment
cp .env.example .env
# Edit .env with your provider credentials- Start services
docker compose -f infra/docker-compose.yml up --build- Verify installation
curl http://localhost:8080/health
# Expected: {"status":"ok"}PayLink is configured via environment variables. Copy .env.example to .env and update the values.
| Variable | Description | Default |
|---|---|---|
PORT |
HTTP server port | 8080 |
DB_HOST |
PostgreSQL host | localhost |
DB_PORT |
PostgreSQL port | 5432 |
DB_USER |
PostgreSQL user | paylink |
DB_PASSWORD |
PostgreSQL password | secret |
DB_NAME |
PostgreSQL database | paylink |
REDIS_HOST |
Redis host | localhost |
REDIS_PORT |
Redis port | 6379 |
MIDTRANS_SERVER_KEY |
Midtrans server key | - |
XENDIT_API_KEY |
Xendit API key | - |
STRIPE_SECRET_KEY |
Stripe secret key | - |
STRIPE_WEBHOOK_SECRET |
Stripe webhook secret | - |
Creates a new payment checkout session.
POST /v1/checkout
Content-Type: application/json
Request Body
{
"merchant_id": "550e8400-e29b-41d4-a716-446655440000",
"amount": 150000,
"currency": "IDR",
"order_id": "ORDER-123",
"provider_preference": "midtrans"
}Response
{
"checkout_url": "https://app.sandbox.midtrans.com/snap/v3/redirection/...",
"provider_tx_id": "snap_ORDER-123_150000"
}Receives and processes webhooks from payment providers.
POST /v1/webhook/{provider}
Retrieves transaction status.
GET /v1/tx/{id}
Returns service health status.
GET /health
For complete API documentation, see docs/api.yaml.
paylink/
├── cmd/
│ ├── server/ # API server entry point
│ └── worker/ # Background worker entry point
├── internal/
│ ├── api/ # HTTP handlers
│ ├── adapters/ # Provider implementations
│ ├── config/ # Configuration
│ ├── crypto/ # Cryptographic utilities
│ ├── db/ # Database layer
│ ├── jobs/ # Job queue
│ ├── models/ # Data models
│ └── util/ # Utilities
├── crypto_cpp/ # C++ crypto module (optional)
├── infra/ # Docker and infrastructure
├── migrations/ # Database migrations
└── docs/ # Documentation
# Build API server
go build -o bin/server ./cmd/server
# Build worker
go build -o bin/worker ./cmd/worker- Create adapter directory:
internal/adapters/{provider}/ - Implement
ProviderAdapterinterface - Register provider in
internal/adapters/registry.go
# Using Docker (recommended)
docker build -f infra/Dockerfile.test -t paylink-test .
docker run --rm paylink-test
# Using Go directly
go test -v ./...go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.outIntegration tests require running services:
# Start services
docker compose -f infra/docker-compose.yml up -d db redis
# Run integration tests
go test -v -tags=integration ./...
# Cleanup
docker compose -f infra/docker-compose.yml down- Start PayLink locally
- Expose local server via ngrok:
ngrok http 8080 - Configure webhook URL in provider sandbox dashboard
- Trigger test payment in sandbox
- Verify webhook received in PayLink logs
PayLink exposes Prometheus-compatible metrics at /metrics:
curl http://localhost:8080/metricsAvailable Metrics:
| Metric | Type | Description |
|---|---|---|
paylink_uptime_seconds |
Gauge | Time since server start |
paylink_requests_total |
Counter | Total requests by status |
paylink_checkouts_total |
Counter | Total checkouts created |
paylink_checkouts_by_provider |
Counter | Checkouts by provider |
paylink_webhooks_total |
Counter | Webhooks by status |
paylink_latency_avg_ms |
Gauge | Average request latency |
Add to prometheus.yml:
scrape_configs:
- job_name: 'paylink'
static_configs:
- targets: ['paylink:8080']PayLink uses structured JSON logging:
{
"time": "2024-12-06T10:00:00Z",
"level": "INFO",
"msg": "Checkout created",
"provider": "midtrans",
"order_id": "ORDER-123",
"amount": 150000
}Log Levels:
INFO- Normal operationsWARN- Recoverable issues (invalid signatures, validation failures)ERROR- Failures requiring attention
# Liveness probe
curl http://localhost:8080/health
# Expected response
{"status":"ok"}See docs/error_handling.md for:
- Retry logic configuration
- Fallback behavior
- Dead letter queue handling
See docs/security.md for:
- Webhook signature verification
- Input validation
- OWASP compliance
docker compose -f infra/docker-compose.yml up --builddocker compose -f infra/docker-compose.yml up -dHelm charts and Kubernetes manifests are planned for future releases.
All incoming webhooks are verified using provider-specific signature algorithms:
| Provider | Algorithm |
|---|---|
| Midtrans | SHA512(order_id + status_code + gross_amount + ServerKey) |
| Xendit | x-callback-token header verification |
| Stripe | HMAC-SHA256 with webhook secret |
- Store credentials in environment variables or secret managers
- Use HTTPS for all external communications
- Enable rate limiting in production
- Rotate API keys periodically
- Review audit logs regularly
- Fork the repository
- Create a feature branch
- Make changes with tests
- Submit a pull request
MIT License. See LICENSE for details.
For issues and feature requests, please open a GitHub issue.
PayLink is maintained by the development team.