Nexus Gateway
EnglishRomână
OpenAPI

Fetch a menu, build a cart from its published identifiers, then send a complete pickup order from your server.

1. Get your tenant key

All production tenants use https://website.api.pionier.ro. Ask your Nexus contact for your tenant’s website key. Ask the restaurant to enable website ordering and publish its menu (Retail Admin → Integrations → POS → Website). Store the key in your server’s secret configuration. The key identifies your tenant; the connection ID selects its point of sale.

export NEXUS_WEBSITE_KEY='your-website-key'
Keep the key on your backend. Browser JavaScript and mobile apps call your own backend, which authenticates to Nexus. Do not expose the key in a public build or URL.

2. Discover enabled points of sale

curl --fail-with-body "https://website.api.pionier.ro/v1/connections" \
  -H "Authorization: Bearer $NEXUS_WEBSITE_KEY"
{
  "connections": [{
    "id": "website-example-connection",
    "location_id": "10",
    "location_name": "Central restaurant",
    "pos_id": "1",
    "pos_name": "Register"
  }]
}

Match the customer’s selected location to a returned connection. Store that connection ID with the cart and order. Refresh this list to discover POS connections enabled later; no new key is required. Never silently select the first item when several connections are available.

export NEXUS_CONNECTION_ID='the-id-returned-by-discovery'

Use the returned id as NEXUS_CONNECTION_ID, not pos_id or location_id. Treat it as an opaque identifier; do not build it yourself.

An empty list means no POS is enabled. A connection ID is required even when only one is returned.

3. Fetch the menu

curl --fail-with-body "https://website.api.pionier.ro/v1/connections/$NEXUS_CONNECTION_ID/menu" \
  -H "Authorization: Bearer $NEXUS_WEBSITE_KEY"
// Run on your server with a runtime that supports fetch.
const response = await fetch(`https://website.api.pionier.ro/v1/connections/${encodeURIComponent(process.env.NEXUS_CONNECTION_ID)}/menu`, {
  headers: { Authorization: `Bearer ${process.env.NEXUS_WEBSITE_KEY}` },
  signal: AbortSignal.timeout(20000)
});
if (!response.ok) throw new Error(`Menu request failed: ${response.status}`);
const menu = await response.json();
// Render menu.products and keep menu.revision with the cart.
<?php
// Server-side PHP with the cURL extension.
$request = curl_init('https://website.api.pionier.ro/v1/connections/' . rawurlencode(getenv('NEXUS_CONNECTION_ID')) . '/menu');
curl_setopt_array($request, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 20,
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('NEXUS_WEBSITE_KEY')]
]);
$body = curl_exec($request);
$status = curl_getinfo($request, CURLINFO_HTTP_CODE);
curl_close($request);
if ($body === false || $status !== 200) {
    throw new RuntimeException('Menu request failed: ' . $status);
}
$menu = json_decode($body, true, 512, JSON_THROW_ON_ERROR);

A 404 menu_not_published means the restaurant needs to publish its menu. A successful menu can still have accepting_orders: false; disable checkout in that case.

Download the sample menu ↓ to explore the schema. Its pizza costs 3,200 bani, packaging 100 bani, and extra cheese 400 bani: 3,700 bani / 37.00 RON.

4. Register your webhook before placing orders

Deploy a public HTTPS receiver that verifies signatures, saves each event once and acknowledges it promptly. Then register its URL with your tenant key. Save the returned signing secret securely; it is separate from your website API key. See the webhook guide for receiver code, retries and secret rotation.

curl --fail-with-body -X PUT "https://website.api.pionier.ro/v1/webhook" \
  -H "Authorization: Bearer $NEXUS_WEBSITE_KEY" \
  -H "Content-Type: application/json" \
  --data '{"url":"https://shop.example.com/nexus/events","enabled":true}'

Replace the example URL with your receiver. Only orders confirmed while the webhook is enabled are watched; existing orders are not backfilled. A 503 webhooks_not_configured requires Nexus to enable signing. Until then, use status polling as a fallback.

5. Persist and submit your order

Save the connection_id, an external_order_id and the complete request in your database before sending it. Each retry must reuse all three unchanged. The following example assumes your payment provider has already confirmed payment.

order-pickup.json
{
  "external_order_id": "shop-1001",
  "menu_revision": "example-menu-1",
  "currency": "RON",
  "fulfillment": "pickup",
  "customer": {
    "name": "Example Customer",
    "phone": "0700000000"
  },
  "payment": {
    "method": "paid_online",
    "reference": "payment-example-1001"
  },
  "items": [
    {
      "product_id": "pizza-margherita",
      "quantity": 1,
      "modifiers": [
        {
          "group_id": "pizza-extras",
          "option_id": "cheese"
        }
      ],
      "notes": "Please slice the pizza"
    }
  ],
  "total": 3700,
  "notes": "Pickup by Alex"
}

Download order-pickup.json ↓. These IDs work only with the sample menu. Adapt the file to the published menu for your selected connection before submitting it.

curl --fail-with-body "https://website.api.pionier.ro/v1/connections/$NEXUS_CONNECTION_ID/orders" \
  -H "Authorization: Bearer $NEXUS_WEBSITE_KEY" \
  -H 'Content-Type: application/json' \
  --data-binary @order-pickup.json
import { readFile } from "node:fs/promises";

// In production, read the exact persisted request from your durable outbox.
const payload = await readFile("order-pickup.json", "utf8");
const response = await fetch(`https://website.api.pionier.ro/v1/connections/${encodeURIComponent(process.env.NEXUS_CONNECTION_ID)}/orders`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.NEXUS_WEBSITE_KEY}`,
    "Content-Type": "application/json"
  },
  body: payload,
  signal: AbortSignal.timeout(20000)
});
if (response.status === 200 || response.status === 201) {
  const receipt = await response.json();
  // Persist confirmation; handle webhooks and reconcile current progress with GET.
} else {
  // Handle the status using the errors guide. Keep the original payload.
  throw new Error(`Submission requires recovery: ${response.status}`);
}
// A network exception also requires recovery; it does not prove rejection.
<?php
// In production, load the original JSON from your durable outbox.
$payload = file_get_contents('order-pickup.json');
$request = curl_init('https://website.api.pionier.ro/v1/connections/' . rawurlencode(getenv('NEXUS_CONNECTION_ID')) . '/orders');
curl_setopt_array($request, [
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => $payload,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 20,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('NEXUS_WEBSITE_KEY'),
        'Content-Type: application/json'
    ]
]);
$body = curl_exec($request);
$status = curl_getinfo($request, CURLINFO_HTTP_CODE);
curl_close($request);
if ($body === false || !in_array($status, [200, 201], true)) {
    // Keep the saved ID/body. Follow the errors guide before retrying.
    throw new RuntimeException('Submission requires recovery: ' . $status);
}
$receipt = json_decode($body, true, 512, JSON_THROW_ON_ERROR);

Successful intake returns 201 Created:

{
  "external_order_id": "shop-1001",
  "status": "pending_acceptance",
  "total": 3700,
  "currency": "RON"
}

6. Read the restaurant’s decision

curl --fail-with-body "https://website.api.pionier.ro/v1/connections/$NEXUS_CONNECTION_ID/orders/shop-1001" \
  -H "Authorization: Bearer $NEXUS_WEBSITE_KEY"

Update your customer’s order page from verified webhook events. Use the GET above to retrieve the current state after downtime or missing updates; polling is the fallback when webhooks are unavailable. Repeated POSTs return the original intake receipt. Read order status and recovery rules before enabling automatic retries.

Nexus GatewayWebsite Ordering API · v1.0.0

Type to search the integration guides.