Appearance
Orders
php
$orders = $console->orders($team); // a Team or its idPlacing an order
php
$order = $console->orders($team)->create([
['family' => 'container', 'product_id' => $planId, 'attributes' => [
'location_id' => 'bon1',
'container_template_id' => $templateId,
'vlan_id' => $vlanId,
'ssh_key' => $sshKeyId, // optional
'name' => 'game-1', // optional hostname
]],
], ['tos_accepted' => true]); // required: only once your user accepted the terms
return redirect($order->checkout_url); // the user confirms (and pays) on Anikeen ID$items: 1–10 items, each withfamilyandproduct_idfrom the catalog andattributesper family - see Order attributes.$options:tos_accepted(required,true- send it only once your user accepted the terms of service),withdrawal_waiver,coupon_code,return_url.
php
$order = $orders->create($items, [
'tos_accepted' => true,
'withdrawal_waiver' => true,
'coupon_code' => 'SPRING',
]);The order of your app team is open with a checkout_url: redirect the user there to confirm and pay on Anikeen ID. Nothing is charged before.
Containers with LXC options
Containers that run their own containers inside (e.g. rootless Podman) need LXC options. They are allow-listed: features fuse and keyctl, devices tun; nesting is always on, anything else answers 422.
php
use Anikeen\Console\Resources\Container;
$console->orders($team)->create([
['family' => 'container', 'product_id' => $gpuPlanId, 'attributes' => [
'location_id' => 'bon1',
'container_template_id' => $templateId,
'vlan_id' => $vlanId,
'options' => [
'features' => [Container::FEATURE_FUSE, Container::FEATURE_KEYCTL],
'devices' => [Container::DEVICE_TUN],
],
]],
], ['tos_accepted' => true]);The catalog lists the allowed values in $catalog->options('container')->options. See LXC options.
Back to your app (return_url)
Send the user back to your app after the checkout (app tokens only; https, plain http only for localhost). The Console redirects there with the order id and its status appended:
php
$order = $console->orders($team)->create($items, [
'tos_accepted' => true,
'return_url' => route('ordered'), // → https://your.app/ordered?console_order=01JE…&status=completed
]);
// routes/web.php
Route::get('/ordered', function (Request $request) {
$console = AnikeenConsole::forUser($request->user());
$team = $console->appTeam();
// never trust the query: read the order (completed once Anikeen ID confirmed it)
$order = $console->orders($team)->find($request->query('console_order'));
return view('ordered', ['order' => $order]);
})->name('ordered');Idempotency
Every create() sends an Idempotency-Key - a new UUID per call - and keeps it for the retry after a token refresh, so an order is never placed twice. The key that was sent is on the order:
php
$order->idempotencyKey;Use your own key, e.g. the id of your own order, so that a retry after a crash returns the first order:
php
$order = $orders
->withIdempotencyKey("myapp-order-{$localOrder->id}")
->create($items, ['tos_accepted' => true]);Keys live 24 hours per team; the same key with another body is refused (ValidationFailedException, error idempotency_key_reused). At most 10 orders per minute and team (RateLimitException). See Idempotency.
Reading orders
php
$order = $orders->find($orderId); // an open order is checked with Anikeen ID first
$order = $order->refresh(); // GET …/orders/{order} again
$order->status; // pending, open, completed, cancelled, expired, failed
$order->isOpen();
$order->isCompleted();
$order->isFinal(); // completed, cancelled, expired or failed
$order->products(); // [{type: "container", id: "01JD…"}, …] once provisioned
foreach ($orders->list(['status' => 'open']) as $order) { … } // newest first; also per_page, page| Property | |
|---|---|
id, team_id | |
status | pending, open, completed, cancelled, expired, failed |
mode | session or direct |
source | api or console |
checkout_url | shown only to the user who ordered, while open |
expires_at, error, created_at, completed_at | |
items | {id, family, product_id, product_name, unit, list_price, price, status, product, provisioned_at} |
Rather than polling, listen for the OrderCompleted and ProductReady webhook events.