Skip to content

API Reference

Complete REST API documentation for Promenade Platform with authentication, endpoints, request/response examples, and error codes.


Base URL

Development: http://localhost:8081/api/v1
Production:  https://api.promenade.com/api/v1

Authentication

All protected endpoints require JWT token in Authorization header:

bash
Authorization: Bearer <access_token>

Obtain Token

Endpoint: POST /identity/users/login

Request:

json
{
  "email": "user@example.com",
  "password": "SecurePass123"
}

Response (200 OK):

json
{
  "status": "success",
  "data": {
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "expires_at": "2025-12-29T10:30:00Z",
    "token_type": "Bearer",
    "user": {
      "id": "01JGABC123",
      "email": "user@example.com",
      "name": "John Doe",
      "status": "active"
    }
  }
}

Refresh Token

Endpoint: POST /identity/auth/refresh

Request:

json
{
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Response (200 OK):

json
{
  "status": "success",
  "data": {
    "access_token": "new_access_token",
    "refresh_token": "new_refresh_token",
    "expires_at": "2025-12-29T10:45:00Z",
    "token_type": "Bearer"
  }
}

Identity Context

User Management

Register User

POST /identity/users/register

Public endpoint (no authentication required)

Request:

json
{
  "email": "newuser@example.com",
  "name": "Jane Smith",
  "password": "SecurePass456"
}

Response (201 Created):

json
{
  "status": "success",
  "data": {
    "id": "01JGDEF456",
    "email": "newuser@example.com",
    "name": "Jane Smith",
    "status": "active",
    "created_at": "2025-12-29T10:00:00Z"
  }
}

Get Current User Profile

GET /identity/users/me

Authentication: Required

Response (200 OK):

json
{
  "status": "success",
  "data": {
    "id": "01JGABC123",
    "email": "user@example.com",
    "name": "John Doe",
    "status": "active",
    "is_locked": false,
    "failed_login_attempts": 0,
    "last_login_at": "2025-12-29T09:00:00Z",
    "created_at": "2025-01-15T08:00:00Z"
  }
}

List Users

GET /identity/users?page=1&page_size=20&status=active

Authentication: Required (Admin role)

Query Parameters:

  • page (int): Page number (default: 1)
  • page_size (int): Items per page (default: 20, max: 100)
  • status (string): Filter by status (active/suspended/banned)
  • search (string): Search by email or name

Response (200 OK):

json
{
  "status": "success",
  "data": [
    {
      "id": "01JGABC123",
      "email": "user1@example.com",
      "name": "John Doe",
      "status": "active"
    },
    {
      "id": "01JGDEF456",
      "email": "user2@example.com",
      "name": "Jane Smith",
      "status": "active"
    }
  ],
  "pagination": {
    "page": 1,
    "page_size": 20,
    "total": 150,
    "total_pages": 8
  }
}

Update User Status

PATCH /identity/users/:id/status

Authentication: Required (Admin role)

Request:

json
{
  "status": "suspended",
  "reason": "Policy violation"
}

Response (200 OK):

json
{
  "status": "success",
  "data": {
    "message": "User status updated successfully"
  }
}

Contact Management

Create Email Contact

POST /identity/contacts

Authentication: Required

Request:

json
{
  "type": "email",
  "email": "john.doe@work.com",
  "label": "Work",
  "is_primary": true
}

Response (201 Created):

json
{
  "status": "success",
  "data": {
    "id": "01JGHIJ789",
    "user_id": "01JGABC123",
    "type": "email",
    "email": "john.doe@work.com",
    "label": "Work",
    "is_primary": true,
    "is_verified": false,
    "is_public": false,
    "created_at": "2025-12-29T10:15:00Z"
  }
}

List User Contacts

GET /identity/contacts?type=email

Authentication: Required

Query Parameters:

  • type (string): Filter by type (email/phone/address)
  • is_primary (bool): Filter primary contacts

Response (200 OK):

json
{
  "status": "success",
  "data": [
    {
      "id": "01JGHIJ789",
      "type": "email",
      "email": "john.doe@work.com",
      "label": "Work",
      "is_primary": true,
      "is_verified": true
    },
    {
      "id": "01JGKLM012",
      "type": "phone",
      "phone": "+380501234567",
      "label": "Mobile",
      "is_primary": true,
      "is_verified": false
    }
  ]
}

Verify Contact

POST /identity/contacts/:id/verify

Authentication: Required

Request:

json
{
  "verification_code": "123456"
}

Response (200 OK):

json
{
  "status": "success",
  "data": {
    "message": "Contact verified successfully"
  }
}

Profile Management

Create Profile

POST /identity/profiles

Authentication: Required

Request:

json
{
  "display_name": "John Doe",
  "first_name": "John",
  "last_name": "Doe",
  "bio": "Software engineer passionate about clean code",
  "timezone": "Europe/Kyiv",
  "language": "uk",
  "country": "UA"
}

Response (201 Created):

json
{
  "status": "success",
  "data": {
    "id": "01JGNOP345",
    "user_id": "01JGABC123",
    "display_name": "John Doe",
    "first_name": "John",
    "last_name": "Doe",
    "bio": "Software engineer passionate about clean code",
    "timezone": "Europe/Kyiv",
    "language": "uk",
    "country": "UA",
    "is_public": false,
    "is_active": true,
    "created_at": "2025-12-29T10:20:00Z"
  }
}

Get Profile

GET /identity/profiles/:id

Authentication: Required (own profile or public profiles)

Response (200 OK):

json
{
  "status": "success",
  "data": {
    "id": "01JGNOP345",
    "display_name": "John Doe",
    "bio": "Software engineer passionate about clean code",
    "avatar_url": "https://cdn.promenade.com/avatars/01JGNOP345.jpg",
    "timezone": "Europe/Kyiv",
    "language": "uk",
    "country": "UA",
    "website": "https://johndoe.com",
    "linkedin": "https://linkedin.com/in/johndoe",
    "github": "https://github.com/johndoe"
  }
}

Role & Permission Management (RBAC)

List Roles

GET /identity/roles

Authentication: Required (Admin role)

Response (200 OK):

json
{
  "status": "success",
  "data": [
    {
      "id": "01JGQRS678",
      "name": "admin",
      "display_name": "Administrator",
      "description": "Full system access",
      "is_system": true,
      "permissions_count": 29
    },
    {
      "id": "01JGTUV901",
      "name": "user",
      "display_name": "Regular User",
      "description": "Standard user access",
      "is_system": true,
      "permissions_count": 8
    }
  ]
}

Assign Role to User

POST /identity/users/:user_id/roles

Authentication: Required (Admin role)

Request:

json
{
  "role_id": "01JGQRS678"
}

Response (200 OK):

json
{
  "status": "success",
  "data": {
    "message": "Role assigned successfully"
  }
}

Shared Context (Reference Data)

Countries

List Countries

GET /shared/countries?is_active=true

Public endpoint

Query Parameters:

  • is_active (bool): Filter by status
  • region (string): Filter by region (Europe, Asia, etc.)
  • search (string): Search by name or code

Response (200 OK):

json
{
  "status": "success",
  "data": [
    {
      "id": "01JGWXY234",
      "code": "UA",
      "name": "Ukraine",
      "local_name": "Україна",
      "region": "Europe",
      "calling_code": "+380",
      "currency_code": "UAH",
      "language_code": "uk",
      "is_active": true
    },
    {
      "id": "01JGZAB567",
      "code": "US",
      "name": "United States",
      "region": "North America",
      "calling_code": "+1",
      "currency_code": "USD",
      "language_code": "en",
      "is_active": true
    }
  ]
}

Currencies

List Currencies

GET /shared/currencies?is_active=true

Public endpoint

Response (200 OK):

json
{
  "status": "success",
  "data": [
    {
      "id": "01JGCDE890",
      "code": "USD",
      "name": "US Dollar",
      "symbol": "$",
      "decimal_places": 2,
      "is_active": true
    },
    {
      "id": "01JGFGH123",
      "code": "EUR",
      "name": "Euro",
      "symbol": "€",
      "decimal_places": 2,
      "is_active": true
    }
  ]
}

Customer Management Context

Customer Management

Create Customer

POST /customer-mgmt/customers

Authentication: Required

Request:

json
{
  "name": "Acme Corporation",
  "type": "company",
  "status": "lead",
  "tier": "enterprise",
  "email": "contact@acme.com",
  "phone": "+1-555-0100",
  "website": "https://acme.com",
  "tags": ["enterprise", "saas", "priority"],
  "assigned_to": "01JGABC123"
}

Response (201 Created):

json
{
  "status": "success",
  "data": {
    "id": "01JGIJK456",
    "name": "Acme Corporation",
    "type": "company",
    "status": "lead",
    "tier": "enterprise",
    "email": "contact@acme.com",
    "phone": "+1-555-0100",
    "website": "https://acme.com",
    "tags": ["enterprise", "saas", "priority"],
    "assigned_to": "01JGABC123",
    "created_at": "2025-12-29T11:00:00Z"
  }
}

List Customers

GET /customer-mgmt/customers?status=lead&tier=enterprise&page=1&page_size=20

Authentication: Required

Query Parameters:

  • status (string): lead/prospect/customer/churned
  • tier (string): free/basic/pro/enterprise
  • type (string): individual/company
  • assigned_to (uuid): Filter by sales rep
  • search (string): Search by name, email, phone
  • tags (string): Filter by tags (comma-separated)
  • page, page_size: Pagination

Response (200 OK):

json
{
  "status": "success",
  "data": [
    {
      "id": "01JGIJK456",
      "name": "Acme Corporation",
      "type": "company",
      "status": "lead",
      "tier": "enterprise",
      "email": "contact@acme.com",
      "created_at": "2025-12-29T11:00:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "page_size": 20,
    "total": 45
  }
}

Get Customer by ID

GET /customer-mgmt/customers/:id

Authentication: Required

Response (200 OK):

json
{
  "status": "success",
  "data": {
    "id": "01JGIJK456",
    "name": "Acme Corporation",
    "type": "company",
    "status": "customer",
    "tier": "enterprise",
    "email": "contact@acme.com",
    "phone": "+1-555-0100",
    "website": "https://acme.com",
    "tags": ["enterprise", "saas", "priority"],
    "assigned_to": "01JGABC123",
    "source": "referral",
    "notes": [
      {
        "id": "01JGLMN789",
        "content": "Initial contact made, interested in enterprise plan",
        "created_at": "2025-12-29T11:15:00Z",
        "created_by": "01JGABC123"
      }
    ],
    "created_at": "2025-12-29T11:00:00Z",
    "updated_at": "2025-12-29T11:15:00Z"
  }
}

Update Customer Status

PATCH /customer-mgmt/customers/:id/status

Authentication: Required

Request:

json
{
  "status": "customer",
  "reason": "Contract signed"
}

Response (200 OK):

json
{
  "status": "success",
  "data": {
    "message": "Customer status updated to customer"
  }
}

Delete Customer

DELETE /customer-mgmt/customers/:id

Authentication: Required (Admin role)

Response (200 OK):

json
{
  "status": "success",
  "data": {
    "message": "Customer deleted successfully"
  }
}

Deal Management

Create Deal

POST /customer-mgmt/deals

Authentication: Required

Request:

json
{
  "title": "Enterprise Plan - Acme Corp",
  "customer_id": "01JGIJK456",
  "value_cents": 5000000,
  "currency": "USD",
  "stage": "lead",
  "expected_close_date": "2026-01-31",
  "assigned_to": "01JGABC123"
}

Response (201 Created):

json
{
  "status": "success",
  "data": {
    "id": "01JGOPQ012",
    "title": "Enterprise Plan - Acme Corp",
    "customer_id": "01JGIJK456",
    "value": {
      "amount": "50000.00",
      "currency": "USD"
    },
    "stage": "lead",
    "probability": 10,
    "expected_close_date": "2026-01-31",
    "assigned_to": "01JGABC123",
    "status": "open",
    "created_at": "2025-12-29T11:30:00Z"
  }
}

Move Deal to Next Stage

POST /customer-mgmt/deals/:id/move-stage

Authentication: Required

Request:

json
{
  "stage": "qualified",
  "notes": "Budget confirmed, decision maker identified"
}

Response (200 OK):

json
{
  "status": "success",
  "data": {
    "id": "01JGOPQ012",
    "stage": "qualified",
    "probability": 25,
    "updated_at": "2025-12-29T12:00:00Z"
  }
}

Mark Deal as Won

POST /customer-mgmt/deals/:id/win

Authentication: Required

Request:

json
{
  "actual_value_cents": 4500000,
  "notes": "Contract signed with 10% discount"
}

Response (200 OK):

json
{
  "status": "success",
  "data": {
    "id": "01JGOPQ012",
    "stage": "closed_won",
    "status": "won",
    "actual_value": {
      "amount": "45000.00",
      "currency": "USD"
    },
    "actual_close_date": "2025-12-29",
    "won_at": "2025-12-29T12:30:00Z"
  }
}

Get Pipeline Statistics

GET /customer-mgmt/deals/stats/pipeline

Authentication: Required

Response (200 OK):

json
{
  "status": "success",
  "data": {
    "by_stage": [
      {
        "stage": "lead",
        "count": 15,
        "total_value": "750000.00",
        "probability": 10
      },
      {
        "stage": "qualified",
        "count": 8,
        "total_value": "400000.00",
        "probability": 25
      },
      {
        "stage": "proposal",
        "count": 5,
        "total_value": "350000.00",
        "probability": 50
      }
    ],
    "total_deals": 28,
    "total_value": "1500000.00",
    "weighted_value": "525000.00"
  }
}

Order Management Context

Order Management

Create Order

POST /order-mgmt/orders

Authentication: Required

Request:

json
{
  "customer_id": "01JGIJK456",
  "currency": "USD",
  "items": [
    {
      "description": "Enterprise Plan - Annual",
      "quantity": 1,
      "unit_price_cents": 1200000
    },
    {
      "description": "Premium Support",
      "quantity": 1,
      "unit_price_cents": 300000
    }
  ]
}

Response (201 Created):

json
{
  "status": "success",
  "data": {
    "id": "01JGRST345",
    "order_number": "ORD-2025-000042",
    "customer_id": "01JGIJK456",
    "status": "pending",
    "total": {
      "amount": "15000.00",
      "currency": "USD"
    },
    "items": [
      {
        "id": "01JGUVW678",
        "description": "Enterprise Plan - Annual",
        "quantity": 1,
        "unit_price": "12000.00",
        "total": "12000.00"
      },
      {
        "id": "01JGXYZ901",
        "description": "Premium Support",
        "quantity": 1,
        "unit_price": "3000.00",
        "total": "3000.00"
      }
    ],
    "created_at": "2025-12-29T13:00:00Z"
  }
}

List Orders

GET /order-mgmt/orders?status=pending&customer_id=01JGIJK456

Authentication: Required

Query Parameters:

  • status (string): pending/confirmed/processing/fulfilled/cancelled
  • customer_id (uuid): Filter by customer
  • date_from, date_to (string): Filter by date range
  • page, page_size: Pagination

Response (200 OK):

json
{
  "status": "success",
  "data": [
    {
      "id": "01JGRST345",
      "order_number": "ORD-2025-000042",
      "customer_id": "01JGIJK456",
      "status": "pending",
      "total": "15000.00",
      "currency": "USD",
      "created_at": "2025-12-29T13:00:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "page_size": 20,
    "total": 1
  }
}

Get Order by ID

GET /order-mggt/orders/:id

Authentication: Required

Response (200 OK):

json
{
  "status": "success",
  "data": {
    "id": "01JGRST345",
    "order_number": "ORD-2025-000042",
    "customer_id": "01JGIJK456",
    "status": "confirmed",
    "total": {
      "amount": "15000.00",
      "currency": "USD"
    },
    "items": [
      {
        "id": "01JGUVW678",
        "description": "Enterprise Plan - Annual",
        "quantity": 1,
        "unit_price": "12000.00",
        "total": "12000.00"
      }
    ],
    "confirmed_at": "2025-12-29T13:15:00Z",
    "created_at": "2025-12-29T13:00:00Z",
    "updated_at": "2025-12-29T13:15:00Z"
  }
}

Confirm Order

POST /order-mgmt/orders/:id/confirm

Authentication: Required

Response (200 OK):

json
{
  "status": "success",
  "data": {
    "id": "01JGRST345",
    "status": "confirmed",
    "confirmed_at": "2025-12-29T13:15:00Z"
  }
}

Start Processing Order

POST /order-mgmt/orders/:id/process

Authentication: Required

Response (200 OK):

json
{
  "status": "success",
  "data": {
    "id": "01JGRST345",
    "status": "processing",
    "processing_started_at": "2025-12-29T13:30:00Z"
  }
}

Mark Order as Fulfilled

POST /order-mgmt/orders/:id/fulfill

Authentication: Required

Response (200 OK):

json
{
  "status": "success",
  "data": {
    "id": "01JGRST345",
    "status": "fulfilled",
    "fulfilled_at": "2025-12-29T14:00:00Z"
  }
}

Cancel Order

POST /order-mgmt/orders/:id/cancel

Authentication: Required

Request:

json
{
  "reason": "Customer requested cancellation"
}

Response (200 OK):

json
{
  "status": "success",
  "data": {
    "id": "01JGRST345",
    "status": "cancelled",
    "cancelled_at": "2025-12-29T13:45:00Z"
  }
}

Health Checks

System Health

GET /health

Public endpoint

Response (200 OK - Healthy):

json
{
  "status": "healthy",
  "version": "1.0.0",
  "dependencies": {
    "database": "healthy",
    "redis": "healthy",
    "event_bus": "healthy"
  },
  "timestamp": "2025-12-29T15:00:00Z"
}

Response (503 Service Unavailable - Unhealthy):

json
{
  "status": "unhealthy",
  "version": "1.0.0",
  "dependencies": {
    "database": "unhealthy",
    "redis": "degraded",
    "event_bus": "healthy"
  },
  "timestamp": "2025-12-29T15:00:00Z"
}

Database Health

GET /health/db

Response (200 OK):

json
{
  "status": "healthy",
  "ping_ms": 5,
  "connections": {
    "active": 12,
    "idle": 8,
    "max": 50
  }
}

Redis Health

GET /health/redis

Response (200 OK):

json
{
  "status": "healthy",
  "ping_ms": 2,
  "memory_used_mb": 45,
  "connected_clients": 8
}

Event Bus Health

GET /health/bus

Response (200 OK):

json
{
  "status": "healthy",
  "adapter": "redis",
  "published_total": 15234,
  "failed_total": 3
}

Error Responses

Standard Error Format

All error responses follow this structure:

json
{
  "status": "error",
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable error message",
    "details": {}
  }
}

HTTP Status Codes

CodeMeaningDescription
200OKRequest successful
201CreatedResource created successfully
400Bad RequestInvalid request data
401UnauthorizedMissing or invalid authentication
403ForbiddenInsufficient permissions
404Not FoundResource not found
409ConflictResource already exists
422UnprocessableValidation failed
429Too Many RequestsRate limit exceeded
500Internal ErrorServer error
503Service UnavailableService temporarily unavailable

Common Error Codes

Authentication Errors:

  • UNAUTHORIZED: Missing or invalid token
  • TOKEN_EXPIRED: JWT token expired
  • INVALID_CREDENTIALS: Invalid email/password
  • ACCOUNT_LOCKED: Too many failed login attempts

Validation Errors:

  • VALIDATION_ERROR: Request validation failed
  • INVALID_EMAIL: Invalid email format
  • INVALID_PHONE: Invalid phone format
  • INVALID_UUID: Invalid UUID format

Resource Errors:

  • NOT_FOUND: Resource not found
  • ALREADY_EXISTS: Resource already exists (duplicate)
  • FORBIDDEN: Insufficient permissions

Business Logic Errors:

  • INVALID_STATUS_TRANSITION: Cannot change status (e.g., pending → fulfilled without processing)
  • INSUFFICIENT_BALANCE: Not enough funds
  • LIMIT_EXCEEDED: Operation limit exceeded

Rate Limiting Errors:

  • RATE_LIMIT_EXCEEDED: Too many requests (X-RateLimit-Reset header shows when to retry)

Error Response Examples

401 Unauthorized:

json
{
  "status": "error",
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Missing or invalid authentication token"
  }
}

400 Validation Error:

json
{
  "status": "error",
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Validation failed",
    "details": {
      "email": "invalid email format",
      "password": "must be at least 8 characters"
    }
  }
}

404 Not Found:

json
{
  "status": "error",
  "error": {
    "code": "NOT_FOUND",
    "message": "Customer with ID 01JGIJK456 not found"
  }
}

429 Rate Limit:

json
{
  "status": "error",
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Too many login attempts, try again in 60 seconds"
  }
}

Rate Limiting

Rate Limits by Endpoint

EndpointLimitWindow
POST /identity/users/login5 requests1 min
POST /identity/users/register3 requests1 min
POST /identity/auth/refresh10 requests1 min
Other authenticated endpoints100 requests1 min
Public endpoints1000 requests1 hour

Rate Limit Headers

Every response includes rate limit information:

X-RateLimit-Limit: 5
X-RateLimit-Remaining: 3
X-RateLimit-Reset: 1735481400  (Unix timestamp)

See: Rate Limiting Guide for complete documentation


Pagination

Query Parameters

?page=1&page_size=20
  • page (int): Page number (1-indexed, default: 1)
  • page_size (int): Items per page (default: 20, max: 100)

Response Format

json
{
  "status": "success",
  "data": [...],
  "pagination": {
    "page": 1,
    "page_size": 20,
    "total": 150,
    "total_pages": 8
  }
}

Filtering & Sorting

Filtering

Use query parameters:

GET /customer-mgmt/customers?status=lead&tier=enterprise&tags=priority

Sorting

Use sort parameter:

GET /customer-mgmt/customers?sort=-created_at,name
  • Prefix with - for descending order
  • Comma-separated for multiple fields

Versioning

API version is included in URL:

/api/v1/...

Breaking changes will increment major version:

/api/v2/...  (future)

CORS

Allowed Origins (Production):

  • https://app.promenade.com
  • https://promenade.com

Allowed Methods:

  • GET, POST, PUT, PATCH, DELETE, OPTIONS

Allowed Headers:

  • Authorization, Content-Type, X-Request-ID

Webhooks (Future)

Subscribe to events:

json
{
  "url": "https://your-app.com/webhooks/promenade",
  "events": ["customer.created", "order.confirmed", "deal.won"],
  "secret": "webhook_secret_key"
}

Event payload:

json
{
  "event": "customer.created",
  "data": {...},
  "timestamp": "2025-12-29T15:30:00Z"
}

See: Webhooks Guide (coming Q2 2026)



Questions? Open a discussion

Found a bug in API? Report an issue

Built with Domain-Driven Design and Go