Skip to main content

API Reference

Drop Backend 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

analysis.Allfile
VersionDateAuthorChanges
0.12026-02-23Platform Architect (AI)CompiledAuto-generated from source code analysis
references
are relative to src/drop-app/src/.

Overview

Drop uses Next.js App Router API routes (app/api/). TheAll applicationresponses usesuse a PSD2consistent pass-throughJSON model — Drop never holds customer money. All funds remain in users' bank accounts; Drop uses AISP to read balances and PISP to initiate payments.envelope:

Base URL

EnvironmentBase URL
Productionhttps://9ef3szvvsb.eu-west-1.awsapprunner.com (future: https://getdrop.no)
Staginghttps://drop-staging.fly.dev
Localhttp://localhost:3000

Response Envelope

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

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

Authentication

Authentication is via httpOnly cookie (drop_token) containing a signed JWT (HS256, 24h expiry).

BankID

Pass-Through OIDCModel: Drop uses a PSD2 pass-through model — it NEVER holds customer money. There is theno solewallet, loginno method.

balance,

Mobileno clientstop-up. useUser Authorization:funds Bearer <token> (7d expiry, storedremain in AsyncStorage).their bank account at all times. Drop uses:

  • AISP (Account Information Service Provider) — reads bank balance via Open Banking
  • PISP (Payment Initiation Service Provider) — initiates transfers directly from user's bank account

The bank_accounts.balance field stores the last AISP-read balance from the user's real bank (cached for display) — NOT a Drop-held balance.


Authentication

RatePOST Limits/api/auth/register

Create a new user account.

Endpoint GroupField LimitSource
BankID initiate/callbackFile 10/min per IPapp/api/auth/register/route.ts
Transaction creation (remittance, qr-payment)10/min per IP
Exchange rates120/min per IP
All other endpointsNo IP-level limit (auth required)

Authentication Endpoints

GET /api/auth/bankid

Initiate BankID OIDC login flow.

PropertyValue
Auth None
Rate Limit 10/min10 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.

PropertyValue
AuthNone (validates state cookie)
Rate Limit10/req/min per IP

QueryRequest params:Body:

userwithkyc_status=approvedonfirstlogin.pid.
FieldTypeRequiredValidation
emailstringYesRFC-like regex, unique
passwordstringYesMin 8 chars, must contain letters + digits
firstNamestringYesvalidateName() — 1-100 chars, at least one letter, no HTML/script
lastNamestringYesSame as firstName
phonestringNoInternational format code, state

Success: Redirects to /dashboard, sets drop_token+XXXXXXXXXXXX cookie.(8-15 Createsdigits)

dateOfBirth string Yes ISO Verifiesdate agestring, must be >= 18 fromyears BankIDold

Success Response (201):

{
  "data": {
    "id": "usr_...",
    "email": "[email protected]",
    "firstName": "...",
    "lastName": "...",
    "dateOfBirth": "...",
    "kycStatus": "pending",
    "createdAt": "2026-..."
  }
}

Error Responses:

StatusCodeCondition
400bad_requestInvalid JSON body
409conflictEmail already registered
422validation_errorField validation failures (returned in details array)
429rate_limitedToo many requests

POST /api/auth/login

Authenticate with email and password.

FieldSource
Fileapp/api/auth/login/route.ts
AuthNone
Rate Limit10 req/min per IP

Request Body:

FieldTypeRequired
emailstringYes
passwordstringYes

Success Response (200):

{
  "data": {
    "id": "usr_...",
    "email": "...",
    "firstName": "...",
    "lastName": "...",
    "kycStatus": "approved"
  }
}

Error Responses:

StatusCodeCondition
400bad_requestMissing email or password
401unauthorizedInvalid credentials
429rate_limitedToo many requests

GET /api/auth/me

Get current authenticated user with linked bank accounts.

PropertyField ValueSource
Fileapp/api/auth/me/route.ts
Auth Required (cookie)

Success Response (200):

{
  "data": {
    "id": "usr_a1b2c3"usr_...",
    "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 and revoke all sessions.

PropertyField ValueSource
Fileapp/api/auth/logout/route.ts
AuthRequired (cookie)

Calls revokeAllSessions() to invalidate all session records, then clears the auth cookie.

Success Response (200):

{ "message": "Logged out" }

POST /api/auth/refresh

Refresh the authentication token (issue new JWT, create new session record).

FieldSource
Fileapp/api/auth/refresh/route.ts
Auth Required (cookie)

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


POST /api/auth/refresh

Refresh JWT token.

PropertyValue
AuthRequired (cookie)

Response (200): 

{
  "data": {
    "userId": "usr_...",
    "email": "...",
    "role": "user"
  }
}


Deprecated Endpoints (410 Gone)

EndpointReplacement
POST /api/auth/loginBankID OIDC
POST /api/auth/registerAuto via BankID
POST /api/auth/verify-otpBankID replaces OTP

Transaction EndpointsTransactions

GET /api/transactions

List useruser's transactions with pagination and filtering.

PropertyField ValueSource
Fileapp/api/transactions/route.ts
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

Success 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 }
}

Note: amount is negated in the response (always shown as outgoing).


GET /api/transactions/[id]

Get single transaction details.details with exchange rate info.

PropertyField ValueSource
Fileapp/api/transactions/[id]/route.ts
Auth Required

Success 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 transaction summary statistics (all-time +and this-monththis statistics.month).

PropertyField ValueSource
Fileapp/api/transactions/summary/route.ts
Auth Required

Success Response (200):

{
  "data": {
    "allTime": {
      totalCount,"totalCount": totalSent,3,
      totalPaid,"totalSent": remittanceCount,5000,
      qrPaymentCount"totalPaid": 129,
      "remittanceCount": 2,
      "qrPaymentCount": 1
    },
    "thisMonth": { "..." }
  }
}


POST /api/transactions/remittance

Create a remittance (international money transfer.transfer).

PropertyField ValueSource
Fileapp/api/transactions/remittance/route.ts
Auth Required
Rate Limit 10/10 req/min per IP
KYC kyc_status mustMust be approved

Request Body:

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

Business logic:Logic:

Fee
    =
  1. Verify recipient belongs to user
  2. Look up exchange rate for recipient's currency
  3. Verify bank account exists and has sufficient balance
  4. Fee: 0.5% of amount.amount
  5. Atomic: debit
  6. Debit bank account +(atomic createtransaction)
  7. Create transaction (status:record with status processing).

Success Response (201):

Full
{
  transaction"data": object{
    with"id": exchange"tx_rem_...",
    rate,"type": fee,"remittance",
    ETA.

"status": "processing", "sendAmount": 2000, "sendCurrency": "NOK", "receiveAmount": 23400, "receiveCurrency": "RSD", "exchangeRate": 11.7, "fee": 10, "feePercent": 0.5, "total": 2010, "recipientName": "...", "recipientCountry": "Serbia", "fromAccount": "DNB", "eta": "1-2 business days", "createdAt": "..." } }

Errors:Error Responses:

Status Code Condition
400 bad_request Missing/invalid fields
400 no_bank_account No linked bank account
402 insufficient_balance BalanceBank account 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 a QR payment to a merchant.

PropertyField ValueSource
Fileapp/api/transactions/qr-payment/route.ts
Auth Required
Rate Limit 10/10 req/min per IP

Request Body:

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

Business logic:Logic:

Fee
    =
  1. Verify merchant exists
  2. Get user's primary bank account
  3. Fee: 1% of amount.amount
  4. Instant
  5. Debit bank account (status:atomic transaction)
  6. Create transaction with status completed (instant)

Success Response (201):

{
  "data": {
    "id": "tx_qr_...",
    "type": "qr_payment",
    "status": "completed",
    "amount": 129,
    "currency": "NOK",
    "fee": 1.29,
    "feePercent": 1,
    "merchantName": "Ahmetov Kebab",
    "merchantId": "mer_1",
    "fromAccount": "DNB",
    "createdAt": "..."
  }
}

Recipients

GET /api/recipients

List user's recipients with pagination.

FieldSource
Fileapp/api/recipients/route.ts
AuthRequired

Query Parameters: page (default 1), limit (default 20, max 50)

Bank account numbers are masked in response (e.g., *****5678).

Supported Countries: RS (Serbia), BA (Bosnia), PL (Poland), PK (Pakistan), TR (Turkey)


POST /api/transactions/disclosurerecipients

GetAdd feea +new exchangerecipient.

ratedisclosure
FieldSource
Fileapp/api/recipients/route.ts
AuthRequired

Request Body:

FieldTypeRequiredValidation
namestringYesvalidateName()
countrystringYesMust be in supported list
currencystringYes-
bankAccountstringYes-
bankNamestringNoSanitized to 200 chars

DELETE /api/recipients/[id]

Delete a recipient.

FieldSource
Fileapp/api/recipients/[id]/route.ts
AuthRequired

Returns 204 No Content on success. Returns 404 if recipient not found or not owned by user.


Cards (FUTURE — feature-flagged, all flags default to false)

Note: The entire Cards section is a FUTURE feature, gated behind feature flags. All card-related feature flags default to false. These endpoints exist in code but return 404 when flags are disabled. Cards require a card issuing partner (e.g., Stripe Issuing) before paymentactivation.

GET /api/cards

List user's cards (Finansavtalelovenexcludes compliance)cancelled).

PropertyField ValueSource
Fileapp/api/cards/route.ts
AuthRequired

POST /api/cards

Create a new card (virtual or physical).

FieldSource
Fileapp/api/cards/route.ts
AuthRequired

Request Body:

FieldTypeRequiredNotes
typestringNovirtual (default) or physical

GET /api/cards/[id]

Get card details. Card number is masked (---- ---- ---- XXXX), CVV is hidden (---).

FieldSource
Fileapp/api/cards/[id]/route.ts
AuthRequired

PCI-DSS compliant: never exposes full card number or CVV.


PATCH /api/cards/[id]

Freeze or unfreeze a card.

FieldSource
Fileapp/api/cards/[id]/route.ts
Auth Required

Request Body: { type,"status": amount,"active" currency?,| recipientId?"frozen" }

Response (200):

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

GETDELETE /api/transactions/cards/[id]/receipt

GetCancel transactiona receipt.

PropertyValue
AuthRequired

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 maskedcard (soft delete — sets status to *****5678cancelled).

PropertyField ValueSource
AuthFile Requiredapp/api/cards/[id]/route.ts

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


POST /api/recipients

Add a recipient.

PropertyValue
AuthRequired

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


DELETE /api/recipients/[id]

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

PropertyValue
Auth Required

POST /api/cards/[id]/physical

Order physical version of a virtual card.

FieldSource
Fileapp/api/cards/[id]/physical/route.ts
AuthRequired
Feature FlagphysicalCards (returns 404 if disabled)

Request Body: { "address": "..." } (min 10 chars)


POST /api/cards/[id]/pin

Set PIN for a card.

FieldSource
Fileapp/api/cards/[id]/pin/route.ts
AuthRequired
Feature FlagcardPin (returns 404 if disabled)

Request Body: { "pin": "1234" } (exactly 4 digits)

PIN is hashed with bcrypt before storage.


GET /api/cards/[id]/limits

Get spending limits for a card.

FieldSource
Fileapp/api/cards/[id]/limits/route.ts
AuthRequired
Feature FlagspendingLimits (returns 404 if disabled)

PUT /api/cards/[id]/limits

Set a spending limit for a card.

FieldSource
Fileapp/api/cards/[id]/limits/route.ts
AuthRequired
Feature FlagspendingLimits (returns 404 if disabled)

Request Body:

FieldTypeRequiredValidation
limitTypestringYesdaily, weekly, monthly, or transaction
amountnumberYesMust be positive

Replaces any existing limit of the same type.


Exchange Rate EndpointsRates

GET /api/rates

Get all NOK exchange rates (public).from NOK.

PropertyField ValueSource
Fileapp/api/rates/route.ts
Auth None
Rate Limit 120/120 req/min per IP

Success 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 a specific currency from NOK. Includes fee: 0.005 (0.5% remittance fee).pair.

PropertyField ValueSource
Fileapp/api/rates/[currency]/route.ts
Auth None
Rate Limit 120/120 req/min per IP

Response includes fee: 0.005 (0.5% remittance fee).


Merchant EndpointsNotifications

POSTGET /api/merchants/registernotifications

RegisterList asall merchantnotifications (upgradesfor role to merchant).

PropertyValue
AuthRequired

Request Body:user.

Field TypeRequiredValidationSource
businessNamestringYesFile validateName()app/api/notifications/route.ts
orgNumberstringYesExactly 9 digits, unique
addressstringNoSanitized to 300 chars
bankAccountstringYesPayout account

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


GET /api/merchants/dashboard

Merchant revenue stats.

PropertyValue
AuthRequired (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.

PropertyValue
AuthRequired (merchant role)

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


GET /api/merchants/transactions

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

PropertyValue
AuthRequired (merchant role)

Notification Endpoints

GET /api/notifications

PropertyValue
Auth Required
Feature Flag notifications (default: enabled)

PATCH /api/notifications

Mark notifications as read. Max 100 IDs per request.

PropertyField ValueSource
Fileapp/api/notifications/route.ts
Auth Required
Feature Flag notifications

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

  • Max 100 IDs per request
  • IDs validated against format ^[a-z]+_[a-f0-9]{16}$

Settings Endpoints

GET /api/settings

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

PropertyField ValueSource
Fileapp/api/settings/route.ts
Auth Required

Defaults: currency=NOK, language=nb, pushEnabled=true, emailEnabled=true


PATCH /api/settings

Update user settings.

PropertyField ValueSource
Fileapp/api/settings/route.ts
Auth Required

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

Currency

whitelist: Languagewhitelist:
FieldTypeValidation
currencystringWhitelist: EUR, USD, GBP, BAM, CHF, PLN, NOK, RSD, TRY, PKR
languagestringWhitelist: nb, en, bs, sq

pushEnabledboolean-
emailEnabledboolean-

GDPR & Compliance EndpointsMerchants

GETPOST /api/user/data-exportmerchants/register

ExportRegister allas usera data (GDPR Art. 20 — right to portability).merchant.

PropertyField ValueSource
AuthFile Requiredapp/api/merchants/register/route.ts

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.

PropertyValue
AuthRequired

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


GET /api/consents

List GDPR consents.

PropertyValue
AuthRequired

POST /api/consents

Grant or withdraw consent.

PropertyValue
Auth Required

Request Body:

towithdraw
Field Type RequiredValidation
consentTypebusinessName string Yesterms, privacy, marketing, cookies_analytics, cookies_marketingvalidateName()
grantedorgNumber booleanstring trueYesExactly 9 digits, unique
addressstringNoSanitized to grant,300 falsechars
bankAccountstringYesPayout account

RecordsUpgrades IPuser addressrole withto consentmerchant. action.Returns a QR code URI (drop://pay/{merchantId}).


GET /api/complaintsmerchants/dashboard

ListGet user'smerchant complaints.dashboard stats.

PropertyField ValueSource
Fileapp/api/merchants/dashboard/route.ts
AuthRequired (merchant role)

Query Parameters: period — today (default), week, month

Returns: revenue, transactionCount, fees, netRevenue, nextPayout, payoutTime.


GET /api/merchants/qr

Get merchant QR code data.

FieldSource
Fileapp/api/merchants/qr/route.ts
AuthRequired (merchant role)

Returns: merchantId, businessName, qrValue (drop://pay/{id}), address.


GET /api/merchants/transactions

List merchant's QR payment transactions with pagination.

FieldSource
Fileapp/api/merchants/transactions/route.ts
AuthRequired (merchant role)

Query Parameters: page, limit

Customer names are partially anonymized (first name + last initial).


GDPR & Compliance

GET /api/user/data-export

Export all user data (GDPR right to data portability).

FieldSource
Fileapp/api/user/data-export/route.ts
AuthRequired

Creates a data_access_request record with type export and status completed.

Success Response (200):

{
  "data": {
    "user": {
      "id": "usr_...",
      "email": "...",
      "first_name": "...",
      "last_name": "...",
      "phone": "+47...",
      "date_of_birth": "1995-03-15",
      "kyc_status": "approved",
      "role": "user",
      "created_at": "..."
    },
    "transactions": [ {...}, {...} ],
    "recipients": [ {...}, {...} ],
    "bankAccounts": [ {...} ],
    "settings": { "currency": "NOK", "language": "nb", ... },
    "consents": [ {...}, {...} ]
  },
  "exportedAt": "2026-02-17T..."
}

DELETE /api/user/account

Request account deletion (GDPR right to erasure).

FieldSource
Fileapp/api/user/account/route.ts
Auth Required

QueryBehavior:

Params:
  • Soft-deletes user (sets deleted_at timestamp)
  • Revokes all active sessions
  • Creates data_access_request with type erasure and status completed
  • Important: Data retained for 5 years per AML/KYC legal requirements (hvitvaskingsloven)

Success Response (200):

page{
  "message": "Account scheduled for deletion",
  limit"retentionNote": "Data retained for 5 years per AML requirements"
}
 (max 100)


POSTGET /api/complaintsconsents

SubmitList auser's complaintGDPR (Finansavtaleloven §3-53 — 15 business day response SLA).consents.

PropertyField ValueSource
Fileapp/api/consents/route.ts
AuthRequired

Success Response (200):

{
  "data": [
    {
      "id": "con_...",
      "user_id": "usr_...",
      "consent_type": "terms",
      "granted": 1,
      "granted_at": "2026-02-17T...",
      "withdrawn_at": null,
      "ip_address": "192.0.2.1"
    }
  ]
}

POST /api/consents

Grant or withdraw a consent.

FieldSource
Fileapp/api/consents/route.ts
Auth Required

Request Body:

Field Type RequiredValidation
categoryconsentType string YesMust be one of: terms, privacy, marketing, cookies_analytics, cookies_marketing
grantedbooleanYestrue to grant, false to withdraw

Behavior:

Success Response (200 for update, 201 for new):

{
  "data": {
    "id": "con_...",
    "consent_type": "marketing",
    "granted": 1,
    "granted_at": "2026-02-17T...",
    "withdrawn_at": null,
    "ip_address": "192.0.2.1"
  }
}

Error Responses:

StatusCodeCondition
400bad_requestInvalid consent type or missing fields

GET /api/complaints

List user's complaints.

FieldSource
Fileapp/api/complaints/route.ts
AuthRequired

Query Parameters:

ParamTypeDefaultNotes
pageint1Pagination page number
limitint10Items per page, max 100

Success Response (200):

{
  "data": [
    {
      "id": "cmp_...",
      "category": "transaction",
      "subject": "Transaction delayed",
      "description": "My remittance to Serbia is delayed...",
      "status": "received",
      "resolution": null,
      "created_at": "2026-02-17T...",
      "resolved_at": null
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 10,
    "total": 3,
    "totalPages": 1
  }
}

POST /api/complaints

Submit a complaint (Finansavtaleloven §3-53 compliance).

FieldSource
Fileapp/api/complaints/route.ts
AuthRequired

Request Body:

FieldTypeRequiredValidation
categorystringYesMust be one of: transaction, service, fees, privacy, technical, other
subject string YesMax 200 charschars, sanitized
description string YesMax 2000 charschars, sanitized

Success

Cards EndpointsResponse (FUTURE201):

{
  Feature-Flagged,"data": All{
    Disabled)

"id":

All"cmp_...", card"category": endpoints"fees", are"subject": behind"High featuretransfer flagsfee", defaulting"description": "...", "status": "received", "created_at": "2026-02-17T..." }, "commitmentNote": "We will review and respond to falseyour complaint within 15 business days per Finansavtaleloven §3-53" } . Requires

Error card issuing partner before activation.Responses:

Flag
EndpointStatus FeatureCode Condition
GET400bad_requestInvalid category or empty fields

POST /api/cardstransactions/disclosure

Get full transaction fee and exchange rate disclosure before initiating payment.

FieldSource
File virtualCardsapp/api/transactions/disclosure/route.ts
POST /api/cardsAuth virtualCards
GET /api/cards/[id]cardDetails
PATCH /api/cards/[id]cardFreeze
DELETE /api/cards/[id]virtualCards
POST /api/cards/[id]/physicalphysicalCards
POST /api/cards/[id]/pincardPin
GET/PUT /api/cards/[id]/limitsspendingLimitsRequired

CardRequest numbersBody:

alwaysmasked
FieldTypeRequiredNotes
typestringYesremittance or qr_payment
amountnumberYesMust be positive
currencystringNoDefaults to NOK
recipientIdstringConditionalRequired for remittance

Success Response (200):

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

Fee Calculation:

  • Remittance: 0.5% of amount
  • QR payment: 1.0% of amount

Delivery Time:

  • QR payment: "Instant"
  • Remittance (EEA): "1-2 business days"
  • Remittance (non-EEA): "2-4 business days"

GET /api/transactions/[id]/receipt

Get transaction receipt with full details.

FieldSource
Fileapp/api/transactions/[id]/receipt/route.ts
AuthRequired

Success Response (200):

{
  "data": {
    "transactionId": "tx_rem_1",
    "date": "2026-02-17T...",
    CVV"type": never"remittance",
    exposed."amount": PCI-DSS2000,
    compliant"currency": masking."NOK",
    "fee": 10,
    "exchangeRate": 10.17,
    "receiveAmount": 20340,
    "receiveCurrency": "RSD",
    "recipient": {
      "name": "Mama Jasmina",
      "country": "RS"
    },
    "reference": "tx_rem_1",
    "status": "completed",
    "estimatedCompletion": null,
    "completedAt": "2026-02-17T..."
  }
}

Error Responses:

StatusCodeCondition
404not_foundTransaction not found or not owned by user

Health Check

GET /api/health

System health check (no auth required.required).

FieldSource
Fileapp/api/health/route.ts
AuthNone

Success Response (200):

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

ResponseReturns (503 — DB unreachable):with {status: "data":error" {if "status":database "down",is "checks": { "db": { "status": "fail" } } } }unreachable.



Approval

RoleNameDateSignature
AuthorPlatform Architect (AI)2026-02-23
Reviewer
ApproverAlem Bašić