Skip to main content

API Reference

API Reference

Project: Drop Version: 0.1.0 Date: 2026-02-23 Author: Platform Architect (AI) Status: In Review Reviewers: Alem Bašić (CEO)

Document History

Version Date Author Changes
0.1 2026-02-23 Platform Architect (AI) Compiled from source code analysis

Overview

Drop uses Next.js App Router API routes (app/api/). The application uses a PSD2 pass-through model — Drop never holds customer money. All funds remain in users' bank accounts; Drop uses AISP to read balances and PISP to initiate payments.

Base URL

Environment Base URL
Production https://9ef3szvvsb.eu-west-1.awsapprunner.com (future: https://getdrop.no)
Staging https://drop-staging.fly.dev
Local http://localhost:3000

Response Envelope

// Success
{ "data": { ... } }

// Success (list)
{ "data": [...], "pagination": { "page": 1, "limit": 20, "total": 100 } }

// Error
{ "error": "error_code", "message": "Human-readable message", "details": [...] }

Authentication

Authentication is via httpOnly cookie (drop_token) containing a signed JWT (HS256, 24h expiry). BankID OIDC is the sole login method.

Mobile clients use Authorization: Bearer <token> (7d expiry, stored in AsyncStorage).

Rate Limits

Endpoint Group Limit
BankID initiate/callback 10/min per IP
Transaction creation (remittance, qr-payment) 10/min per IP
Exchange rates 120/min per IP
All other endpoints No IP-level limit (auth required)

Authentication Endpoints

GET /api/auth/bankid

Initiate BankID OIDC login flow.

Property Value
Auth None
Rate Limit 10/min per IP

Sets bankid_state httpOnly cookie. Returns { "redirectUrl": "https://bankid.no/authorize?..." }.


GET /api/auth/bankid/callback

BankID OIDC callback — creates/finds user, issues session cookie.

Property Value
Auth None (validates state cookie)
Rate Limit 10/min per IP

Query params: code, state

Success: Redirects to /dashboard, sets drop_token cookie. Creates user with kyc_status=approved on first login. Verifies age >= 18 from BankID pid.


GET /api/auth/me

Get current authenticated user with linked bank accounts.

Property Value
Auth Required (cookie)

Response (200):

{
  "data": {
    "id": "usr_a1b2c3",
    "email": "[email protected]",
    "firstName": "Amir",
    "lastName": "Bašić",
    "totalBalance": 58030.0,
    "bankAccounts": [
      { "id": "ba_1", "bankName": "DNB", "accountNumber": "1234.56.78901",
        "balance": 45230.0, "currency": "NOK", "isPrimary": true }
    ],
    "kycStatus": "approved",
    "createdAt": "2026-01-01T00:00:00.000Z"
  }
}

Note: balance values are AISP-read from user's real bank — NOT Drop-held funds.


POST /api/auth/logout

Logout — revoke all sessions.

Property Value
Auth Required (cookie)

Response (200): { "message": "Logged out" }


POST /api/auth/refresh

Refresh JWT token.

Property Value
Auth Required (cookie)

Response (200): { "data": { "userId": "usr_...", "email": "...", "role": "user" } }


Deprecated Endpoints (410 Gone)

Endpoint Replacement
POST /api/auth/login BankID OIDC
POST /api/auth/register Auto via BankID
POST /api/auth/verify-otp BankID replaces OTP

Transaction Endpoints

GET /api/transactions

List user transactions with pagination and filtering.

Property Value
Auth Required

Query Parameters:

Param Type Default Notes
page int 1 Min 1
limit int 20 Min 1, Max 50
type string remittance or qr_payment
status string processing, completed, or failed

Response (200):

{
  "data": [
    { "id": "tx_rem_1", "type": "remittance", "status": "completed",
      "amount": -2000, "currency": "NOK", "recipientName": "Mama Jasmina", "createdAt": "..." }
  ],
  "pagination": { "page": 1, "limit": 20, "total": 3 }
}

GET /api/transactions/[id]

Get single transaction details.

Property Value
Auth Required

Response (200):

{
  "data": {
    "id": "tx_rem_1", "type": "remittance", "status": "completed",
    "sendAmount": 2000, "sendCurrency": "NOK",
    "receiveAmount": 23400, "receiveCurrency": "RSD",
    "exchangeRate": 11.7, "fee": 10, "total": 2010,
    "recipientName": "Mama Jasmina", "recipientCountry": "Serbia",
    "createdAt": "...", "completedAt": "..."
  }
}

GET /api/transactions/summary

Get all-time + this-month statistics.

Property Value
Auth Required

Response (200): { "data": { "allTime": { totalCount, totalSent, totalPaid, remittanceCount, qrPaymentCount }, "thisMonth": { ... } } }


POST /api/transactions/remittance

Create international money transfer.

Property Value
Auth Required
Rate Limit 10/min per IP
KYC kyc_status must be approved

Request Body:

Field Type Required Validation
recipientId string Yes Must belong to current user
amount number Yes 100–50,000 NOK, max 2 decimal places
currency string No Defaults to NOK
bankAccountId string No Defaults to primary bank account

Business logic: Fee = 0.5% of amount. Atomic: debit bank account + create transaction (status: processing).

Response (201): Full transaction object with exchange rate, fee, ETA.

Errors:

Status Code Condition
400 bad_request Missing/invalid fields
400 no_bank_account No linked bank account
402 insufficient_balance Balance too low
403 kyc_required KYC not approved
404 not_found Recipient not found
422 validation_error Unsupported currency corridor

POST /api/transactions/qr-payment

Create QR payment to a merchant.

Property Value
Auth Required
Rate Limit 10/min per IP

Request Body:

Field Type Required Validation
merchantId string Yes Must exist
amount number Yes 1–100,000 NOK, max 2 decimal places

Business logic: Fee = 1% of amount. Instant (status: completed).


POST /api/transactions/disclosure

Get fee + exchange rate disclosure before payment (Finansavtaleloven compliance).

Property Value
Auth Required

Request Body: { type, amount, currency?, recipientId? }

Response (200):

{
  "amount": 2000, "fee": 10, "feePercentage": 0.5,
  "exchangeRate": 10.17, "receiveAmount": 20340, "receiveCurrency": "RSD",
  "estimatedDelivery": "1-2 business days", "totalCost": 2010
}

GET /api/transactions/[id]/receipt

Get transaction receipt.

Property Value
Auth Required

Returns full receipt with amounts, fees, exchange rate, recipient info. 404 if not owned by user.


Recipient Endpoints

GET /api/recipients

List saved recipients. Bank account numbers masked (*****5678).

Property Value
Auth Required

Query Params: page, limit (max 50). Supported countries: RS, BA, PL, PK, TR.


POST /api/recipients

Add a recipient.

Property Value
Auth Required

Request Body: { name, country, currency, bankAccount, bankName? }


DELETE /api/recipients/[id]

Delete a recipient. Response (204). 404 if not found/owned.

Property Value
Auth Required

Exchange Rate Endpoints

GET /api/rates

Get all NOK exchange rates (public).

Property Value
Auth None
Rate Limit 120/min per IP

Response (200):

{
  "data": {
    "baseCurrency": "NOK",
    "rates": { "RSD": 11.7, "BAM": 1.04, "PLN": 0.41, "PKR": 26.8, "TRY": 3.45, "EUR": 0.089 },
    "updatedAt": "..."
  }
}

GET /api/rates/[currency]

Get rate for specific currency from NOK. Includes fee: 0.005 (0.5% remittance fee).

Property Value
Auth None
Rate Limit 120/min per IP

Merchant Endpoints

POST /api/merchants/register

Register as merchant (upgrades role to merchant).

Property Value
Auth Required

Request Body:

Field Type Required Validation
businessName string Yes validateName()
orgNumber string Yes Exactly 9 digits, unique
address string No Sanitized to 300 chars
bankAccount string Yes Payout account

Returns QR code URI: drop://pay/{merchantId}


GET /api/merchants/dashboard

Merchant revenue stats.

Property Value
Auth Required (merchant role)

Query Params: period = today (default) / week / month

Returns: { revenue, transactionCount, fees, netRevenue, nextPayout, payoutTime }


GET /api/merchants/qr

Get merchant QR code data.

Property Value
Auth Required (merchant role)

Returns: { merchantId, businessName, qrValue: "drop://pay/{id}", address }


GET /api/merchants/transactions

List merchant's QR payment transactions. Customer names partially anonymized.

Property Value
Auth Required (merchant role)

Notification Endpoints

GET /api/notifications

Property Value
Auth Required
Feature Flag notifications (default: enabled)

PATCH /api/notifications

Mark notifications as read. Max 100 IDs per request.

Property Value
Auth Required
Feature Flag notifications

Request Body: { "notificationIds": ["noti_..."] }


Settings Endpoints

GET /api/settings

Get user settings (auto-creates defaults: currency=NOK, language=nb).

Property Value
Auth Required

PATCH /api/settings

Update user settings.

Property Value
Auth Required

Request Body (all optional): { currency?, language?, pushEnabled?, emailEnabled? }

Currency whitelist: EUR, USD, GBP, BAM, CHF, PLN, NOK, RSD, TRY, PKR Language whitelist: nb, en, bs, sq


GDPR & Compliance Endpoints

GET /api/user/data-export

Export all user data (GDPR Art. 20 — right to portability).

Property Value
Auth Required

Returns full export: user profile, transactions, recipients, bank accounts, settings, consents.


DELETE /api/user/account

Request account deletion (GDPR Art. 17 — right to erasure). Data retained 5 years per hvitvaskingsloven.

Property Value
Auth Required

Response (200): { "message": "Account scheduled for deletion", "retentionNote": "Data retained for 5 years per AML requirements" }


GET /api/consents

List GDPR consents.

Property Value
Auth Required

POST /api/consents

Grant or withdraw consent.

Property Value
Auth Required

Request Body:

Field Type Validation
consentType string terms, privacy, marketing, cookies_analytics, cookies_marketing
granted boolean true to grant, false to withdraw

Records IP address with consent action.


GET /api/complaints

List user's complaints.

Property Value
Auth Required

Query Params: page, limit (max 100)


POST /api/complaints

Submit a complaint (Finansavtaleloven §3-53 — 15 business day response SLA).

Property Value
Auth Required

Request Body:

Field Type Validation
category string transaction, service, fees, privacy, technical, other
subject string Max 200 chars
description string Max 2000 chars

Cards Endpoints (FUTURE — Feature-Flagged, All Disabled)

All card endpoints are behind feature flags defaulting to false. Requires card issuing partner before activation.

Endpoint Feature Flag
GET /api/cards virtualCards
POST /api/cards virtualCards
GET /api/cards/[id] cardDetails
PATCH /api/cards/[id] cardFreeze
DELETE /api/cards/[id] virtualCards
POST /api/cards/[id]/physical physicalCards
POST /api/cards/[id]/pin cardPin
GET/PUT /api/cards/[id]/limits spendingLimits

Card numbers always masked (---- ---- ---- XXXX). CVV never exposed. PCI-DSS compliant masking.


Health Check

GET /api/health

System health — no auth required.

Response (200):

{
  "data": {
    "status": "ok",
    "version": "0.1.0",
    "uptime": 3600,
    "checks": {
      "db": { "status": "pass", "latencyMs": 2, "driver": "pg" },
      "services": { "mode": "production" }
    },
    "timestamp": "2026-02-23T12:00:00.000Z"
  }
}

Response (503 — DB unreachable): { "data": { "status": "down", "checks": { "db": { "status": "fail" } } } }



Approval

Role Name Date Signature
Author Platform Architect (AI) 2026-02-23
Reviewer
Approver Alem Bašić