Ordeliya Docs

Getting Started

Make your first authenticated API call to the Ordeliya API in under 5 minutes.

Quick Start

This guide takes you from zero to a working API integration. By the end, you will have authenticated, listed your products, and created your first order programmatically.

Prerequisites

  • An Ordeliya account at app.ordeliya.com
  • A store with at least one product in the menu
  • A terminal with curl installed (or any HTTP client)

Step 1: Get Your API Key

The fastest way to authenticate is with an API Key. API Keys are long-lived and don't require token refresh.

  1. Log in to your dashboard at app.ordeliya.com
  2. Go to Settings → API Keys
  3. Click Create API Key
  4. Give it a name (e.g., "My Integration") and select scopes
  5. Copy the key — it starts with ord_live_sk_

API Keys are shown only once. Store them securely. If you lose a key, revoke it and create a new one.


Step 2: Verify Connectivity

Test that your key works with the health endpoint (no auth required) and then an authenticated call:

# Public health check (no auth required)
curl https://api.ordeliya.com/health
{
  "success": true,
  "data": {
    "status": "ok",
    "db": true,
    "redis": true,
    "responseTime": 4
  }
}

Now test with your API key:

# Authenticated request — list your products
curl https://api.ordeliya.com/products \
  -H "Authorization: Bearer ord_live_sk_7f3a9b2c1d4e5f6a7b8c9d0e1f2a3b4c"
{
  "success": true,
  "data": [
    {
      "id": "prod_8kx2m4n7",
      "name": "Margherita Pizza",
      "slug": "margherita-pizza",
      "basePrice": 8900,
      "status": "ACTIVE",
      "isAvailable": true,
      "imageUrl": "https://cdn.ordeliya.com/stores/store_r4k7/products/margherita.webp",
      "categories": [
        { "id": "cat_p1z2a3", "name": "Pizzas" }
      ]
    },
    {
      "id": "prod_3jn8v5q2",
      "name": "Garlic Bread",
      "slug": "garlic-bread",
      "basePrice": 3900,
      "status": "ACTIVE",
      "isAvailable": true,
      "imageUrl": null,
      "categories": [
        { "id": "cat_s1d2e3", "name": "Sides" }
      ]
    }
  ],
  "meta": {
    "total": 2,
    "page": 1,
    "limit": 20,
    "totalPages": 1,
    "requestId": "req_a1b2c3d4e5f6"
  }
}

If you see your products, you're connected.


Step 3: Get an Access Token (Alternative)

If you prefer short-lived JWTs over API Keys (e.g., for browser-based apps):

curl -X POST https://api.ordeliya.com/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "owner@myrestaurant.dk",
    "password": "your-secure-password"
  }'
{
  "success": true,
  "data": {
    "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c3JfNGs3bTJuOHYiLCJlbWFpbCI6Im93bmVyQG15cmVzdGF1cmFudC5kayIsInN0b3JlSWQiOiJzdG9yZV9yNGs3IiwiYXVkIjoidGVuYW50IiwiaWF0IjoxNzEwNTEwMTgwLCJleHAiOjE3MTA1MTEwODB9.abc123",
    "user": {
      "id": "usr_4k7m2n8v",
      "email": "owner@myrestaurant.dk",
      "name": "Anders Jensen"
    },
    "stores": [
      {
        "storeId": "store_r4k7",
        "storeName": "Pizza Roma — Copenhagen",
        "websiteId": "web_m3x9",
        "role": "OWNER"
      },
      {
        "storeId": "store_h8n2",
        "storeName": "Pizza Roma — Aarhus",
        "websiteId": "web_m3x9",
        "role": "OWNER"
      }
    ]
  }
}

The access token expires in 15 minutes. A refreshToken is set as an httpOnly cookie automatically.

Use the token in subsequent requests:

curl https://api.ordeliya.com/orders \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."

Step 4: Create Your First Order

Create a manual order using the POST /orders endpoint. Include X-Idempotency-Key to prevent duplicates:

curl -X POST https://api.ordeliya.com/orders \
  -H "Authorization: Bearer ord_live_sk_7f3a9b2c1d4e5f6a7b8c9d0e1f2a3b4c" \
  -H "Content-Type: application/json" \
  -H "X-Idempotency-Key: my-first-order-001" \
  -d '{
    "fulfillmentType": "PICKUP",
    "source": "PHONE",
    "customerName": "Maria Nielsen",
    "customerPhone": "+4520123456",
    "customerEmail": "maria@example.dk",
    "items": [
      {
        "productId": "prod_8kx2m4n7",
        "quantity": 2,
        "notes": "Extra crispy"
      },
      {
        "productId": "prod_3jn8v5q2",
        "quantity": 1
      }
    ],
    "notes": "Ring doorbell on arrival",
    "scheduledAt": null
  }'
{
  "success": true,
  "data": {
    "id": "ord_v7k3m9n2",
    "orderId": "2026-0147",
    "status": "RECEIVED",
    "fulfillmentType": "PICKUP",
    "source": "PHONE",
    "customer": {
      "name": "Maria Nielsen",
      "phone": "+4520123456",
      "email": "maria@example.dk"
    },
    "items": [
      {
        "id": "oi_x1y2z3",
        "productId": "prod_8kx2m4n7",
        "productName": "Margherita Pizza",
        "quantity": 2,
        "unitPriceMinor": 8900,
        "totalMinor": 17800,
        "notes": "Extra crispy"
      },
      {
        "id": "oi_a4b5c6",
        "productId": "prod_3jn8v5q2",
        "productName": "Garlic Bread",
        "quantity": 1,
        "unitPriceMinor": 3900,
        "totalMinor": 3900,
        "notes": null
      }
    ],
    "subtotalMinor": 21700,
    "taxMinor": 5425,
    "deliveryFeeMinor": 0,
    "discountMinor": 0,
    "totalMinor": 21700,
    "currency": "DKK",
    "paymentStatus": "PENDING",
    "notes": "Ring doorbell on arrival",
    "createdAt": "2026-03-15T14:22:31.000Z"
  }
}

The order appears immediately in your dashboard under Orders.


Pagination

All list endpoints support cursor-based pagination:

ParameterTypeDefaultDescription
pageinteger1Page number
limitinteger20Items per page (max: 100)
sortstringcreatedAtSort field
orderstringdescSort direction (asc or desc)
# Get page 3, 50 items per page, oldest first
curl "https://api.ordeliya.com/orders?page=3&limit=50&order=asc" \
  -H "Authorization: Bearer ord_live_sk_..."

The response meta includes pagination info:

{
  "meta": {
    "total": 1247,
    "page": 3,
    "limit": 50,
    "totalPages": 25
  }
}

Idempotency

For any POST request that creates a resource, include X-Idempotency-Key:

curl -X POST https://api.ordeliya.com/orders \
  -H "Authorization: Bearer ord_live_sk_..." \
  -H "X-Idempotency-Key: checkout_session_abc123" \
  -H "Content-Type: application/json" \
  -d '{ ... }'

How it works:

  1. First request with key checkout_session_abc123 → creates the order, returns 201
  2. Second request with the same key → returns the original response without creating a duplicate
  3. Keys expire after 24 hours

Key format recommendations:

PatternExample
Session-basedcheckout_{sessionId}_{timestamp}
Client-generatedord_{uuid}
POS transactionpos_{deviceId}_{transactionId}

Error Handling

The API uses standard HTTP status codes:

CodeMeaningWhen
200OKSuccessful GET, PATCH
201CreatedSuccessful POST
204No ContentSuccessful DELETE
400Bad RequestInvalid JSON, missing required fields
401UnauthorizedMissing, expired, or invalid token
403ForbiddenValid token but insufficient role/permissions
404Not FoundResource doesn't exist or belongs to another store
409ConflictDuplicate resource (e.g., duplicate email)
422Unprocessable EntityValidation errors (correct format, invalid values)
429Too Many RequestsRate limited — check Retry-After header
500Server ErrorUnexpected error — include requestId in bug report

Error responses always include a requestId for debugging:

{
  "success": false,
  "error": {
    "statusCode": 422,
    "message": "Validation failed",
    "errors": [
      { "field": "items", "message": "At least one item is required" },
      { "field": "fulfillmentType", "message": "Must be DELIVERY, PICKUP, or CURBSIDE" }
    ]
  },
  "meta": {
    "requestId": "req_x9y8z7w6v5u4"
  }
}

Next Steps

You've made your first API call and created an order. Here's what to explore next:

  • Authentication — JWT realms, API Key scopes, roles & permissions
  • Orders API — Full order lifecycle, status transitions, timeline
  • Webhooks — Real-time event subscriptions with HMAC verification