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'
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.
{
"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.jsonimport { 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.