Skip to content

API Standards, Versioning & Contracts ​


1. REST Architecture & Resource Modeling ​

Debelu's backend REST API follows strict resource-oriented design principles to ensure predictable integration for web, mobile, and third-party partners.

1.1 URI & Naming Conventions ​

  • Resource Collections: Plural nouns in kebab-case (/api/campus-orders, /api/flash-sales, /api/vendor-applications).
  • Sub-Resources: Nested strictly by natural ownership:
    • /api/orders/:id/items
    • /api/vendors/:id/reviews
    • /api/campuses/:id/hubs
  • Non-CRUD Actions: Expressed as explicit terminal sub-verbs:
    • POST /api/orders/:id/verify-delivery
    • POST /api/orders/:id/cancel
    • POST /api/payouts/dispatch

1.2 HTTP Verbs & Semantics ​

MethodIdempotentSafeTypical StatusUsage
GETYesYes200 OKResource or collection retrieval. Never mutates server state.
POSTNoNo201 Created / 200 OKNon-idempotent resource creation or state machine transition.
PUTYesNo200 OKComplete resource replacement.
PATCHNoNo200 OKPartial update of resource attributes.
DELETEYesNo200 OK / 204 No ContentSoft or hard deletion of an entity.

2. Standard Envelopes & Error Contracts (RFC 7807) ​

2.1 Standard Success Envelope ​

All successful responses return JSON wrapped in a predictable meta-envelope:

json
{
  "success": true,
  "data": {
    "id": "10000000-0000-4000-8000-000000000801",
    "status": "Processing",
    "total": 15000.00
  },
  "meta": {
    "timestamp": "2026-10-05T09:30:00.000Z",
    "version": "1.0",
    "requestId": "req_a1b2c3d4e5"
  }
}

2.2 RFC 7807 Problem Details Specification ​

When an error occurs, the API returns a structured Problem Details payload in compliance with RFC 7807:

json
{
  "type": "https://debelu.com/errors/insufficient-escrow-balance",
  "title": "Insufficient Escrow Balance",
  "status": 409,
  "detail": "Order balance cannot be released because ₦5,000 remains unverified.",
  "instance": "/api/orders/10000000-0000-4000-8000-000000000801/release",
  "code": "ESCROW_BALANCE_DEFICIT",
  "invalid_params": [
    {
      "name": "amountMinor",
      "reason": "Requested amount exceeds locked escrow liability"
    }
  ]
}

2.3 Master Error Code Catalog ​

Error CodeHTTP StatusDomain CategoryDescription
AUTH_UNAUTHORIZED401AuthenticationMissing or malformed Bearer token.
AUTH_TOKEN_EXPIRED401AuthenticationSupabase JWT has expired; refresh required.
AUTH_FORBIDDEN403AuthorizationInsufficient staff role or missing specific permission.
AUTH_AAL2_REQUIRED403AuthenticationOperation requires step-up Two-Factor Authentication (AAL2).
VALIDATION_FAILED422Input ValidationZod schema validation failed on request body or parameters.
RESOURCE_NOT_FOUND404DataTargeted entity does not exist or is invisible under current RLS scope.
CONCURRENCY_CONFLICT409State ManagementPostgreSQL error 40001 (Serialization Failure); stale revision supplied.
ESCROW_LOCKED423EscrowFunds are locked in active escrow and cannot be withdrawn.
DELIVERY_PIN_INVALID400FulfillmentIncorrect 4-digit Delivery PIN submitted.
RATE_LIMIT_EXCEEDED429Traffic ControlRequest quota exceeded; wait for Retry-After seconds.
INTERNAL_ERROR500ServerUnhandled server exception; correlation ID logged to Sentry.

3. Idempotency Standard (Idempotency-Key) ​

To eliminate duplicate charges and double-order submissions over unstable mobile networks:

3.1 Mandatory Endpoints ​

The Idempotency-Key: <UUIDv4> header is mandatory on:

  • POST /api/payments/intent
  • POST /api/orders/checkout
  • POST /api/orders/:id/verify-delivery
  • POST /api/payouts/dispatch
mermaid
sequenceDiagram
    autonumber
    actor Client
    participant MW as Idempotency Middleware
    participant Redis as Redis Cache
    participant Route as Route Handler

    Client->>MW: POST /api/orders/checkout (Idempotency-Key: k_123)
    MW->>Redis: SETNX lock:idemp:k_123 (TTL: 120s)
    alt Lock Acquired (First Time)
        MW->>Route: Execute Checkout Handler
        Route-->>MW: Return HTTP 201 Created (Order Payload)
        MW->>Redis: SET response:idemp:k_123 (TTL: 24h, status, body)
        MW->>Redis: DEL lock:idemp:k_123
        MW-->>Client: HTTP 201 Created
    else Lock Held by Concurrent Request
        MW-->>Client: HTTP 409 Conflict ("Operation already in progress")
    else Cached Response Found
        MW->>Redis: GET response:idemp:k_123
        MW-->>Client: HTTP 201 Created (Cached Replay with X-Cache-Lookup: HIT)
    end

4. Pagination & Querying Standards ​

4.1 Cursor-Based Pagination (Real-Time Feeds) ​

Mandatory for dynamic, high-velocity feeds (product browse, chat streams, notification lists):

  • Request: GET /api/products?cursor=ZXlKMGVYQWlPaUo...&limit=20
  • Response Meta:
    json
    "meta": {
      "next_cursor": "ZXlKMGVYQWlPaUo...",
      "has_more": true,
      "limit": 20
    }

4.2 Offset/Limit Pagination (Structured Admin/Audit) ​

Used strictly for deterministic, sortable tabular data:

  • Request: GET /api/payouts?page=2&limit=50&sort=created_at&order=desc
  • Response Meta:
    json
    "meta": {
      "page": 2,
      "limit": 50,
      "total": 1240,
      "total_pages": 25
    }

5. Rate Limiting Tiers & Header Standards ​

Debelu enforces dynamic rate limits via Redis sliding window counters:

TierRequest QuotaScopeTarget Endpoints
Tier 1: Anonymous Public$60\text{ req/min}$Per IP AddressCatalog browsing, public marketing endpoints.
Tier 2: Authenticated Buyer$300\text{ req/min}$Per User IDCart operations, order lookups, support tickets.
Tier 3: Authenticated Merchant$600\text{ req/min}$Per User IDInventory management, product uploads, order tracking.
Tier 4: Sensitive Financial / Auth$10\text{ req/min}$Per IP / UserLogin, OTP generation, payment initialization, withdrawal.
Tier 5: Nduzi AI Assistant$20\text{ req/min}$Per User ID/api/gemini/stream (AI conversation).

Standard Response Headers ​

Every API response transmits rate limit context:

http
RateLimit-Limit: 300
RateLimit-Remaining: 284
RateLimit-Reset: 1728114000

When exceeded (HTTP 429):

http
Retry-After: 35

6. API Versioning, Deprecation & Sunset Policy ​

6.1 Versioning Conventions ​

  • Structural breaking changes (schema removals, renamed fields) require an explicit URI version increment (/api/v1/ $\to$ /api/v2/).
  • Non-breaking additive changes (adding optional fields, new endpoints) deploy continuously without version increments.

6.2 Formal Sunset Header Protocol ​

When an endpoint is marked for deprecation:

http
Deprecation: @1735689600
Sunset: Wed, 01 Apr 2026 00:00:00 GMT
Link: <https://debelu.com/docs/migration/v2>; rel="sunset"

The platform guarantees a minimum 6-month support window between formal deprecation notice and physical endpoint decommission.

Released under Proprietary Enterprise License.