Merchant Onboarding Flow

Flow: Merchant Onboarding

Document: LLD-006 Version: 1.0 Date: 2026-02-21 Author: Frontend Architect (AI Agent) Status: Draft Scope: Merchant registration, business verification, QR code generation, merchant dashboard, transaction monitoring, and settlement


1. Overview

Drop supports merchant onboarding for in-store QR payments. Any authenticated user can register as a merchant by providing business details and a valid Norwegian organization number. Upon registration, the user's role is upgraded from user to merchant, granting access to the merchant dashboard with transaction monitoring, daily summaries, and settlement views.

Key facts:


2. Merchant Registration Flow

2.1 Sequence Diagram — Registration to Active Merchant

sequenceDiagram
    actor User
    participant App as Drop App
    participant API as Drop API<br/>(/api/merchants)
    participant Brreg as Brønnøysund<br/>Register (prod)
    participant DB as Database

    User->>App: Navigate to merchant registration
    App->>App: useAuth() — verify authenticated

    User->>App: Fill registration form<br/>(businessName, orgNumber, address, bankAccount)

    App->>App: Client-side validation<br/>(name: validateName, orgNumber: 9 digits)

    App->>API: POST /api/merchants/register<br/>{ businessName, orgNumber, address, bankAccount }

    API->>API: JWT verification
    API->>API: Validate input fields

    alt Production
        API->>Brreg: GET /enhetsregisteret/api/enheter/{orgNumber}
        Brreg-->>API: { organisasjonsnummer, navn, organisasjonsform, ... }
        API->>API: Verify business exists and is active
    else Demo
        API->>API: Format validation only (9 digits, unique)
    end

    API->>DB: Check org_number uniqueness
    API->>DB: INSERT merchant (user_id, business_name, org_number, bank_account, fee_rate=0.01)
    API->>DB: UPDATE users SET role = 'merchant' WHERE id = ?

    API->>API: Generate QR URI: drop://pay/{merchantId}

    API-->>App: 201 { merchant: { id, businessName, orgNumber, qrUri } }

    App->>App: Show success screen<br/>(QR code display, "Vis min QR-kode" button)
    App->>App: Navigate to merchant dashboard

3. Merchant Dashboard Components

3.1 Component Diagram

graph TD
    subgraph "Merchant Dashboard"
        Header["Header<br/>'VELKOMMEN' + business name<br/>+ Settings button"]
        PeriodFilter["PeriodFilter<br/>(I dag / Uke / Maaned)"]
        RevenueCard["RevenueCard<br/>(green gradient)"]
        QRButton["QRButton<br/>'Vis min QR-kode'"]
        TransactionList["TransactionList<br/>'Dagens transaksjoner'"]
        BottomNav["BottomNav"]
    end

    subgraph "Revenue Card"
        TotalRevenue["Total omsetning<br/>(4xl Fraunces font)"]
        StatsGrid["Stats Grid (2 cols)"]
        TxCount["Transaksjoner<br/>(count)"]
        FeesInfo["Gebyrer betalt<br/>(NOK amount)"]
    end

    subgraph "Transaction Item"
        CustomerIcon["CheckCircle2<br/>(green)"]
        CustomerName["Customer Name<br/>(partially anonymized)"]
        TxTime["Timestamp"]
        TxAmount["Amount<br/>(+NOK, green)"]
    end

    RevenueCard --> TotalRevenue
    RevenueCard --> StatsGrid
    StatsGrid --> TxCount
    StatsGrid --> FeesInfo

    TransactionList --> CustomerIcon
    TransactionList --> CustomerName
    TransactionList --> TxTime
    TransactionList --> TxAmount

4. Business Verification Checklist

4.1 Registration Requirements

Requirement Field Validation Demo Production
Business name businessName validateName() — 1-100 chars, at least one letter, no HTML/script Format check only Format check
Organization number orgNumber Exactly 9 digits, unique in DB Format + uniqueness Brønnøysund API lookup
Business address address Optional, sanitized to 300 chars Optional Required for settlement
Payout bank account bankAccount Required, non-empty Format check IBAN/account validation
User authentication JWT Valid BankID session Required Required
KYC status user.kycStatus Must be approved Auto-approved via BankID BankID verification

4.2 Brønnøysundregistrene Verification (Production)

Check API Response Field Pass Criteria
Business exists GET /enhetsregisteret/api/enheter/{orgNr} organisasjonsnummer Matches input
Business is active Same registreringsdatoEnhetsregisteret Not null
Business type Same organisasjonsform.kode AS, ENK, NUF, DA, ANS
Business name match Same navn Approximate match to submitted name

5. Settlement Schedule

5.1 Settlement Schedule Table

Period Settlement Day Payout Time Details
Daily transactions T+1 08:00 CET Next business day after transaction
Weekend transactions Monday 08:00 CET Batched for Monday payout
Holiday transactions Next business day 08:00 CET Following Norwegian business day

5.2 Settlement Calculation

Field Formula Example
Gross revenue Sum of all QR payment amounts 4 350 NOK
Merchant fee Gross x 1% (fee_rate) 43.50 NOK
Net payout Gross - fee 4 306.50 NOK
Payout account merchant.bankAccount IBAN or Norwegian account

5.3 Merchant Dashboard API

Endpoint: GET /api/merchants/dashboard?period={today|week|month}

Response:

{
  "data": {
    "revenue": 4350,
    "transactionCount": 12,
    "fees": 43.5,
    "netRevenue": 4306.5,
    "nextPayout": "2026-02-22T07:00:00.000Z",
    "payoutTime": "Neste virkedag kl. 08:00"
  }
}

6. QR Code Generation

Property Value
Format URI: drop://pay/{merchantId}
Encoding Standard QR code (alphanumeric)
Generation Client-side (from returned qrUri)
Display "Vis min QR-kode" button on merchant dashboard
Printing Merchant can screenshot or print for in-store display

QR endpoint: GET /api/merchants/qr

{
  "data": {
    "merchantId": "mer_a1b2c3d4e5f6g7h8",
    "businessName": "Ahmetov Kebab",
    "qrValue": "drop://pay/mer_a1b2c3d4e5f6g7h8",
    "address": "Gronlandsleiret 44, 0190 Oslo"
  }
}

7. Merchant Transaction Monitoring

7.1 Transaction List

Endpoint: GET /api/merchants/transactions?page=1&limit=20

Field Value Privacy
Customer name First name + last initial Partially anonymized (e.g., "Ola N.")
Amount Positive NOK value Full amount shown
Status "Vellykket" (green) Color-coded
Timestamp HH:MM format Time only for today's transactions

7.2 Period Filtering

Period API Value Dashboard Label Aggregation
Today today I dag Sum of today's transactions
This week week Uke Mon-Sun aggregation
This month month Maaned Calendar month aggregation

8. UI Components (Web)

8.1 Merchant Dashboard Layout

Section Component Description
Header Business name (Fraunces) + Settings icon Welcome greeting + gear icon
Period tabs Button group (I dag, Uke, Maaned) Green active, gray inactive
Revenue card Green gradient card (#0B6E35 to #095a2b) Total omsetning (4xl), stats grid
QR button Full-width green button with QrCode icon "Vis min QR-kode"
Transaction list Card list with CheckCircle2 icons Customer name, time, +amount (green)
Navigation BottomNav (5 tabs) Standard bottom navigation

8.2 Figma Reference

Source of truth: mockups/figma-make-export/src/app/screens/MerchantDashboard.tsx


9. Role Upgrade Flow

Step Before After
1 User has role = 'user' Same
2 User submits merchant registration Same
3 API validates and creates merchant record role = 'merchant'
4 User's JWT still has old role Valid until refresh
5 On next token refresh / re-login New JWT has role = 'merchant'

Authorization gates:


10. Platform Differences

Feature Web Mobile
Merchant registration Full form via web UI Not implemented
Merchant dashboard Dedicated screen with stats Not implemented
QR code display Button to show QR Not implemented
Transaction monitoring List with period filter Not implemented
Settlement view Inline in dashboard stats Not implemented

11. Accessibility Considerations (WCAG 2.1 AA)

Requirement Implementation
Form validation Registration form shows inline error messages
Revenue card Uses both visual (bold text) and semantic (heading) for amounts
Period tabs Active tab indicated by color AND aria-selected
Transaction list Each item has descriptive text (customer, amount, status)
QR code Alt text: "QR-kode for {businessName}"
Color contrast White text on green gradient meets 4.5:1
Settings icon Has aria-label "Innstillinger"

12. Cross-References


Revision #4
Created 2026-02-21 05:58:54 UTC by John
Updated 2026-05-23 10:52:01 UTC by John