Logo PopinaPopina API

Customer API Overview

REST API for customer, address and balance management operations.

API for managing customer records, addresses, and balance operations. Supports person and company customer types with multiple address configurations per customer and location-based balance tracking.

Key areas

  • Server Health: readiness checks
  • Customers: search, list, create, update and delete customers
  • Addresses: list, create, update, delete addresses
  • Balance:
    • view balance, list movements.
    • perform deposits and withdrawals
    • pay orders with balance

Data Model

Customer Types

Two customer types with different field sets:

Person

type Customer = {
    type: "person"
    id: string // UUID v4
    firstName?: string | null
    lastName?: string | null
    birthDate?: Date | null // Date (ISO 8601)
    // Shared fields
    email?: string | null
    phoneNumber?: string | null // E.164 format
    comment?: string | null
}

Company

type Customer = {
    type: "company"
    id: string // UUID v4
    companyName?: string | null
    siretCode?: string | null // SIRET CODE
    nafCode?: string | null // NAF CODE
    vatCode?: string | null // VAT CODE
    // Shared fields
    email?: string | null
    phoneNumber?: string | null // E.164 format
    comment?: string | null
}

The type field is required when creating or updating customers.

Addresses

Each customer can have one address per type: shipping, billing, or both.

type Address = {
    id: string  // UUID v4
    address1: string; // Primary address line
    address2: string | null | undefined; // Complementary address
    city: string; // City name
    country: string; // Country name
    zipCode: string; // Postal code
    isPrimary: boolean; // Indicates if this is the primary address for the specified type
    type: "shipping" | "billing" | "both"; 
    regionCode: string | null | undefined; // ISO 3166-2 code representing the administrative region (e.g., "US-CA" for California, USA)
}

Address Types

  • shipping - Delivery address for orders and shipments
  • billing - Address for invoicing and payment processing
  • both - Address used for both shipping and billing operations

Database constraint: One primary address per customer per type. The isPrimary field indicates the primary address for that type.

Customer Balance

Customers can have a balance at each location

Tab Entity

A customer's balance account at a specific location:

type Tab = {
  id: string          // UUID
  customerId: string  // Customer UUID
  locationId: string  // Location UUID
  balance: number     // Current balance in cents
  createdAt: string   // Datetime
  updatedAt: string   // Datetime
}

Each customer can have one tab per location (unique constraint on [locationId, customerId]).

Movement Entity

Single source of truth for all customer transactions.

type Movement = {
  id: string                       // UUID
  type: "deposit" | "withdrawal" | "purchase" | "refund"
  amount: number                   // Transaction amount in cents (can be positive or negative)
  description?: string             // Optional note
  totalOrder: number               // Order total at time of movement (0 for non-order movements)
  updatedBalance: number           // Balance snapshot after this movement
  tabId: string                    // Tab UUID
  
  // Order relationship (for purchases/refunds)
  orderId?: string                 // Order UUID (nullable, one-to-one)
  
  // Payment tracking (denormalized)
  paymentId?: string               // Payment method ID
  paymentName?: string             // Payment method name snapshot
  
  // Employee tracking (denormalized)
  employeeId?: string              // Employee who processed the movement
  employeeName?: string            // Employee name snapshot
  
  // Till tracking (denormalized)
  tillId?: string                  // Till/register used
  tillName?: string                // Till name snapshot
  
  // Currency and status
  currencyCode: string             // ISO 4217 currency code (default: "EUR")
  status: "pending" | "finalized"  // Movement status
  
  createdAt: string                // Datetime
  updatedAt: string                // Datetime
}

Movement Types

TypeAmountOrder LinkPayment InfoDescription
depositPositive❌ No✅ YesCustomer adds money (cash, card, transfer)
withdrawalNegative❌ No✅ YesCustomer takes money out
purchaseNegative✅ Yes❌ NoCustomer pays for order from balance
refundPositive✅ Yes❌ NoRefund when order is cancelled

Movement Status Lifecycle

The status field links movements to the order synchronization process for reconciliation and audit trails.

States

  • pending - Awaiting order sync from POS (purchases only)
  • finalized - Order received and reconciled

Status Behavior

Movement TypeInitial StatusFinalized WhenBalance Updated
depositfinalizedImmediately✅ Immediately
withdrawalfinalizedImmediately✅ Immediately
purchasependingWhen orderLive is received with isPaid = true✅ Immediately
refundfinalizedWhen orderLive is received with isCanceled = true and has at least one balance payment✅ Immediately

Balance is always updated immediately when a movement is created, regardless of status. The status field tracks the administrative/reconciliation lifecycle, not the balance state.

Purchase Lifecycle (Two-Phase)

Phase 1 - Payment on POS (Real-time)

  • Customer pays order with balance on POS
  • Movement created with status: "pending" and orderId
  • Balance decremented immediately
  • Order not yet sent to backend

Phase 2 - Order Live Sync (Periodic bulk)

  • POS sends orders to api-order in bulk (every few seconds)
  • api-order receives and saves orders
  • Movements updated to status: "finalized"

POS devices send orders periodically in bulk, not immediately. Purchase movements remain in pending state until their associated order is received by the backend.

Workflow

What Backoffice and POS Device can do

  • Manage customer and address information
  • List customer movements
  • Create a deposit
  • Create a withdrawal

What is handled by System

  • Create Movements of type purchase and refund
  • Set the status of the movement to finalized when the order is received by api-order
Customer balance endpoints structure

Endpoints

Customers

  • GET /v1/customers/ - List customers
  • POST /v1/customers/ - Create customer
  • GET /v1/customers/{id} - Get customer
  • PUT /v1/customers/{id} - Update customer
  • DELETE /v1/customers/{id} - Delete customer

Addresses

  • GET /v1/addresses/ - List addresses
  • POST /v1/addresses/ - Create address
  • GET /v1/addresses/{id} - Get address
  • PUT /v1/addresses/{id} - Update address
  • DELETE /v1/addresses/{id} - Delete address

Balance

  • GET /v1/customers/{customerId}/balance - Get customer balance at current location
  • GET /v1/customers/{customerId}/movements - List customer movements at current location
  • POST /v1/customers/{customerId}/deposit - Create deposit (add money to balance)
  • POST /v1/customers/{customerId}/withdrawal - Create withdrawal (remove money from balance)
  • POST /v1/customers/{customerId}/purchase - Pay order using customer balance (creates pending movement)

Authentication

Two authentication methods are supported:

Backoffice Authentication

authorization-client: serviceKey
backoffice-organization-id: <uuid>
backoffice-location-id: <uuid>  
authorization: Bearer <serviceKey>

The backoffice-location-id header is required for balance-related endpoints (movements, deposit, withdrawal) when using backoffice authentication. For device token, the location is automatically extracted from the device token. The purchase endpoint only supports device authentication.

POS Device Authentication

authorization-client: device
authorization: Bearer <deviceToken>

Error Codes

The API returns structured error responses with specific error codes for different scenarios:

{
  "message": "Error description",
  "code": "ERROR_CODE"
}

Balance Operation Errors

  • INSUFFICIENT_BALANCE (400) - Insufficient balance for the requested operation
  • PAYMENT_METHOD_NOT_FOUND (404) - The specified payment method was not found
  • EMPLOYEE_NOT_FOUND (404) - The specified employee was not found

Customer Errors

  • CUSTOMER_NOT_FOUND (404) - The specified customer was not found

Address Errors

  • ADDRESS_NOT_FOUND (404) - The specified address was not found
  • ADDRESS_ALREADY_EXISTS (409) - An address of this type already exists for the customer

General Errors

  • INVALID_LOCATION_ID (400) - The provided location ID is invalid
  • INVALID_ORGANIZATION_ID (400) - The provided organization ID is invalid
  • LOCATION_NOT_FOUND (404) - The specified location was not found
  • ORGANIZATION_NOT_FOUND (404) - The specified organization was not found
  • API_CUSTOMER_ERROR (500) - An unexpected error occurred in the customer API