📚 API Documentation | GitHub Repository
Centralized invoice management and payment processing system for Estonian Internet Services infrastructure. Provides invoice generation, payment processing, and integration with external payment systems for Registry, Auction, and EEID services.
- System Overview
- Technology Stack
- Architecture
- Requirements
- Installation and Setup
- Configuration
- Integrations
- API Documentation
- Invoice Types
- Deployment
- Testing
- Development
EIS Billing System is the central component for billing management in the Estonian Internet Services infrastructure. The system processes requests from three main services:
- Registry - domain management system
- Auction - domain auction system
- EEID - unified identity system
- Invoice and payment link generation
- Payment processing via EveryPay
- Refunds for auction deposits
- Bulk payments for auction
- Integration with Directo accounting system
- E-invoice delivery via Omniva
- Automatic transaction detection via LHV Connect
- Web interface for administrators
- Ruby 3.4.5
- Rails 7.2.2.0
- PostgreSQL (primary database)
- Redis (caching and background jobs)
- Hotwire (Turbo + Stimulus)
- Importmap (JS dependency management)
- Sprockets (asset pipeline)
- Puma - application server
- Sidekiq/ActiveJob - background jobs
- PDFKit + wkhtmltopdf - PDF generation
- PgSearch - full-text search
- Pagy - pagination
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Registry │────▶│ │◀────│ Auction │
└─────────────┘ │ │ └─────────────┘
│ EIS Billing │
┌─────────────┐ │ System │ ┌─────────────┐
│ EEID │────▶│ │────▶│ EveryPay │
└─────────────┘ └──────┬───────┘ └─────────────┘
│
┌──────┴──────┐
│ │
┌───▼───┐ ┌────▼────┐ ┌───────────┐
│Directo│ │ Omniva │ │LHV Connect│
└───────┘ └─────────┘ └───────────┘
- REST API - all service-to-service interactions
- Webhooks - callbacks from EveryPay for payment status updates
- Background Jobs - asynchronous processing for integrations
- Ruby 3.4.5
- PostgreSQL 12+
- Redis 5+
- Docker & Docker Compose (for development)
- wkhtmltopdf
- Clone the repository:
git clone <repository-url>
cd eis_billing_system- Copy configuration examples:
cp config/application.yml.sample config/application.yml- Start the application via Docker:
docker-compose up- Create the database:
docker-compose exec app rails db:create db:migrate- Install dependencies:
bundle install- Setup the database:
rails db:create
rails db:migrate
rails db:seed- Start the server:
rails serverbase_registry: "http://registry:3000"
base_auction: "http://auction_center:3000"
base_eeid: "http://eeid:3000"
# Callback URLs for payment status updates
registry_update_payment_url: "http://registry:3000/eis_billing/payment_status"
auction_update_payment_url: "http://auction_center:3000/eis_billing/payment_status"
eeid_update_payment_url: "http://eeid:3000/eis_billing/payment_status"everypay_key: "your_api_key"
everypay_base: "https://igw-demo.every-pay.com/api/v4"
linkpay_prefix: "https://igw-demo.every-pay.com/lp"
linkpay_token: "your_linkpay_token"
api_username: "your_username"
account_name: "your_account"directo_invoice_url: "https://your-directo-instance.com/api/invoice.asp"lhv_keystore: "./eestiInternetiSa/eestiInternetiSa.p12"
lhv_keystore_password: "your_password"
lhv_keystore_alias: "your_alias"
lhv_ca_file: "path/to/ca/file" # development only
lhv_dev_mode: "true" # for developmente_invoice_provider_test_mode: "true" # for testingdevelopment:
allowed_base_urls: "https://registry.test, https://auction_center.test, https://eeid.test"
tara_redirect_uri: "https://eis_billing_system.test/auth/tara/callback"
tara_identifier: "your_client_id"
tara_secret: "your_client_secret"deposit_min_num: "10001"
deposit_max_num: "14001"smtp_address: "smtp.example.com"
smtp_port: "587"
smtp_user_name: "your_username"
smtp_password: "your_password"
smtp_domain: "example.com"
smtp_authentication: "plain"
action_mailer_default_from: "no-reply@example.com"Purpose: Online payment processing
Functionality:
- Linkpay - payment link generation for embedding in PDF/Email
- One-off payments - single payments for account top-ups and invoice payments
- Refunds - refund processing for auction deposits
- Webhooks - payment status update notifications
Endpoints:
POST /api/v1/invoice_generator/invoice_generator- create linkpay linkPOST /api/v1/invoice_generator/oneoff- create one-off paymentGET /api/v1/callback_handler/callback- webhook for EveryPay updates
Webhook Events (event_name):
status_updated- payment status updatedrefunded- refund completedvoided- payment cancelledchargebacked- chargeback initiatedabandoned- payment failed
Purpose: Accounting system integration
Functionality:
- Invoice forwarding to accounting
- Payment data synchronization
- Background processing via
DirectoInvoiceForwardJob
Endpoints:
POST /api/v1/directo/directo- forward invoice to Directo
Data Schema:
Invoices contain in_directo (boolean) and directo_data (jsonb) fields for synchronization status tracking.
Purpose: Electronic invoice delivery
Functionality:
- E-invoice delivery via Omniva operator
- Background processing via
SendEInvoiceJobandEInvoiceResponseSenderJob - Delivery time tracking in
sent_at_omnivafield
Endpoints:
POST /api/v1/e_invoice/e_invoice- send e-invoice
Purpose: Automatic bank transaction detection
Functionality:
- Automatic matching of incoming payments with invoices
- Processing via
PaymentLhvConnectJob - Certificate-based secure connection
Technical Details:
- Keystore: PKCS12 format (.p12)
- CA certificate support for validation
- Dev mode for testing without real transactions
Purpose: Administrator authentication
Functionality:
- OAuth2 authentication via EEID (wrapper over TARA)
- User session management
- White-list access codes
Endpoints:
GET /auth/tara/callback- OAuth callbackDELETE /logout- session termination
Models:
User- system administratorsAppSession- active sessionsWhiteCode- access codes
📚 View API Documentation on GitHub Pages
The complete API documentation is automatically generated and published to GitHub Pages on every push to the main branch.
The system uses Apipie for interactive API documentation generation.
Local Access: http://localhost:3000/apipie (when running the application)
Authentication (for local documentation viewing):
apipie_login: test
apipie_password: testTo generate static HTML documentation locally:
bundle exec rake apipie:staticGenerated files will be available in public/apipie/
POST /api/v1/invoice_generator/invoice_generator
Create linkpay link for payment
{
"transaction_amount": "100.00",
"reference_number": "RF123456",
"order_reference": "Account #12345",
"customer_name": "John Doe",
"customer_email": "john@example.com",
"custom_field_1": "Domain renewal",
"custom_field2": "registry",
"linkpay_token": "generated_token",
"invoice_number": "INV-2025-001"
}Response:
{
"message": "Link created",
"everypay_link": "https://pay.every-pay.eu/..."
}POST /api/v1/invoice_generator/oneoff
Create a one-off payment
{
"transaction_amount": "50.00",
"customer_url": "https://registry.test/payment/callback",
"description": "Account top-up",
"custom_field2": "registry"
}POST /api/v1/invoice_generator/bulk_payment
{
"transaction_amount": "500.00",
"customer_url": "https://auction.test/payment/callback",
"description": "Multiple domain deposits",
"custom_field2": "auction"
}POST /api/v1/refund/auction
{
"params": {
"invoice_number": "INV-2025-001"
}
}POST /api/v1/invoice_generator/invoice_status
Get invoice status by number
POST /api/v1/import_data/invoice_data
Import invoice data from external systems
POST /api/v1/import_data/reference_data
Import reference data (reference numbers)
PATCH /api/v1/invoice/invoice_synchronize
Synchronize invoice status with external system
Purpose: Standard payments
Usage:
- Account top-ups
- Invoice payments
- Typically used with one-off payment
Characteristics:
affiliation: :regular- Does not support refunds
- Used by all services (Registry, Auction, EEID)
Purpose: Auction participation deposits
Usage:
- Fund blocking for auction participation
- Refunds for unsuccessful bidders
Characteristics:
affiliation: :auction_deposit- Supports refunds via EveryPay
- Used only by Auction service
- Special invoice number range (10001-14001)
Refund process:
# Check if refund is possible
invoice.auction_deposit_prepayment? # => true
# API for refund
POST /api/v1/refund/auction
{
"params": {
"invoice_number": "10523"
}
}Purpose: Embeddable payment links
Usage:
- Links for PDF invoices
- Links in email notifications
- Payment via link with payment method selection
Characteristics:
affiliation: :linkpay- Stores additional information in
linkpay_info(jsonb) - Used by all services
Additional data:
{
"linkpay_info": {
"link": "https://pay.every-pay.eu/...",
"token": "...",
"created_at": "2025-01-01T12:00:00Z"
}
}docker-compose updocker-compose -f docker-compose.staging.yml upSystem is deployed on AWS using Docker.
Deployment process:
- Capistrano - deployment automation
- GitHub Actions - CI/CD pipeline
- rbenv - Ruby version management
- Passenger - application server in production
Running deployment:
# Staging
cap staging deploy
# Production
cap production deployThe system supports three environments:
- development - local development (Docker)
- staging - testing environment (AWS + Docker)
- production - production environment (AWS + Docker)
Ensure these are configured in each environment:
- Database (DATABASE_URL)
- Redis (REDIS_URL)
- Secret keys (SECRET_KEY_BASE)
- External service API keys
- SMTP settings
# All tests
bundle exec rspec
# Specific file
bundle exec rspec spec/models/invoice_spec.rb
# Specific test
bundle exec rspec spec/models/invoice_spec.rb:15Project uses SimpleCov for test coverage measurement.
# Run tests with coverage report
COVERAGE=true bundle exec rspec
# Report available in coverage/index.html
open coverage/index.html- RSpec - testing framework
- FactoryBot - test data factories
- Faker - test data generation
- WebMock - HTTP request mocking
- Selenium/Webdriver - integration tests
- DatabaseCleaner - database cleanup between tests
# RuboCop - code style
bundle exec rubocop
# Brakeman - security scanning
bundle exec brakeman
# Bundle Audit - dependency vulnerabilities
bundle exec bundle-audit check --updateapp/
├── controllers/
│ ├── api/v1/ # API endpoints
│ │ ├── invoice_generator/
│ │ ├── callback_handler/
│ │ ├── e_invoice/
│ │ ├── directo/
│ │ └── refund/
│ ├── dashboards/ # Admin UI
│ └── invoice_details/ # Invoice details
├── models/
│ ├── invoice.rb # Main invoice model
│ ├── reference.rb # Reference numbers
│ ├── user.rb # Administrators
│ └── white_code.rb # Access codes
├── jobs/
│ ├── directo_invoice_forward_job.rb
│ ├── send_e_invoice_job.rb
│ ├── payment_lhv_connect_job.rb
│ └── save_invoice_data_job.rb
├── contracts/ # Parameter validation (dry-validation)
├── mailers/ # Email notifications
└── services/ # Business logic
Invoices (main table):
invoice_number- unique invoice numberinitiator- source (registry/auction/eeid/billing_system)payment_reference- EveryPay referencetransaction_amount- payment amountstatus- status (unpaid/paid/cancelled/failed/refunded/overdue)affiliation- type (regular/auction_deposit/linkpay)everypay_response- EveryPay response (jsonb)directo_data- Directo data (jsonb)linkpay_info- linkpay data (jsonb)in_directo- sent to Directo flagtransaction_time- transaction timestampsent_at_omniva- Omniva delivery timestamp
References:
reference_number- payment referenceinitiator- sourceowner- owneremail- owner email
All integrations with external services are processed asynchronously:
# Directo
DirectoInvoiceForwardJob.perform_later(invoice_id)
# E-Invoice
SendEInvoiceJob.perform_later(invoice_id)
# LHV Connect
PaymentLhvConnectJob.perform_later
# Data saving
SaveInvoiceDataJob.perform_later(invoice_data)
SaveReferenceDataJob.perform_later(reference_data)# Rails console
rails console
# Database console
rails dbconsole
# Routes
rails routes | grep invoice
# Clear logs
rails log:clear
# Migration status
rails db:migrate:statusLogs are available in:
log/development.loglog/staging.loglog/production.log
# Use byebug in code
def some_method
byebug # debugger will stop here
# your code
endGitHub Actions are configured for:
- Automated test runs
- Code style checks (RuboCop)
- Security scanning (Brakeman)
- Dependency checks (Bundle Audit)
Automated dependency updates are configured via Renovate (see renovate.json)