Orders
An order is a one-off purchase: digital or physical goods, charged on its own.
Endpoints
| Method | Path | |
|---|---|---|
GET | /api/v1/orders | the user's orders, newest first; filter group |
POST | /api/v1/orders | create an order |
GET | /api/v1/orders/{id} | one order |
PUT | /api/v1/orders/{id} | change group or metadata of a draft |
PUT | /api/v1/orders/{id}/checkout | charge the order (trusted apps; see below) |
PUT | /api/v1/orders/{id}/revoke | revoke a paid order (a withdrawal: refunded with a credit note); not for monthly bills |
DELETE | /api/v1/orders/{id} | delete a draft |
GET | /api/v1/orders/{id}/items | the order's items |
User token; scopes orders (or orders:read to read). Third-party apps can only change, revoke or delete orders they created.
Creating an order
curl -X POST https://id.anikeen.com/api/v1/orders \
-H 'Authorization: Bearer USER_TOKEN' \
-H 'Accept: application/json' -H 'Content-Type: application/json' \
-d '{
"billing_address_id": "01JADDRESS…",
"return_url": "https://shop.example.com/orders/1/return",
"metadata": {"shop_order": "1"},
"items": [
{"type": "digital", "name": "Sticker pack", "unit": "piece", "units": 1, "gross_price": "9.99"}
]
}'$order = $user->orders()->create([
'billing_address_id' => $user->getUserData()->billing_address_id,
'items' => [
['type' => 'digital', 'name' => 'Sticker pack', 'unit' => 'piece', 'units' => 1, 'gross_price' => '9.99'],
],
]);
return redirect()->away($order->confirmationUrl(route('orders.return', $shopOrder)));
// later: https://shop.example.com/orders/1/return?status=completed&order=01J…Fields
| Field | |
|---|---|
items | required for third-party apps and with confirm: the items, see below |
billing_address_id | an address of the user (see Account data) |
billing_address | instead of the ID, when the user has no billing address yet: at least country_iso; also first_name, last_name, company_name, address, address_2, house_number, postal_code, city, state, phone_number, email. The user completes it on the confirmation page |
shipping_address_id / shipping_address | for physical goods, see Shipments |
group | your app's group, e.g. a team ID |
metadata | your own data (an object, at most 50 keys), returned as is in the API and the order webhooks |
return_url | where the user returns after confirming; the origin of one of your redirect URIs (422 otherwise) |
withdrawal_waiver_required | ask for the early start |
confirm | trusted apps: let the user confirm, see below |
checkout | trusted apps: charge right away |
Item fields:
| Field | |
|---|---|
type | digital, physical or physical-reduced (the VAT treatment, see VAT) |
name | required, at most 255 characters |
description | optional, at most 255 characters |
unit | piece or onetime |
units | the quantity, at least 1 |
gross_price or price | per unit; gross (VAT included, the user pays exactly this) or net; up to 6 decimals; not negative for third-party apps |
image_url | optional; copied to Anikeen ID and shown on the confirmation page, order and invoice |
Pictures are copied when the order is created: JPEG, PNG, GIF, WebP or AVIF up to 5 MB from a public host, no SVG. They stay visible when your app removes the original.
Confirmation
Orders of third-party apps are created as drafts with a confirmation_url. Send the user there (the SDK's confirmationUrl($returnUrl) appends your return_url). On the confirmation page the user sees the items with VAT, can change the billing and shipping address in place, adds a payment method if needed (or pays once with another method) and pays. 3-D Secure is handled there too. Afterwards the user returns to
https://shop.example.com/orders/1/return?status=completed&order=01J…status is completed, pending or cancelled – only a hint. Read the order to know its state:
$order = auth()->user()->orders()->find($shopOrder->anikeen_id);
$shopOrder->update(['status' => $order->status]);A draft that isn't confirmed within 24 hours is cancelled. Calling checkout on a draft of a third-party app answers 403 confirmation_required with the confirmation_url (the SDK throws a ConfirmationRequiredException).
Status
status | Meaning |
|---|---|
draft | Created, not confirmed by the user yet |
pending | Confirmed, the payment is still processing (or failed and is retried) |
completed | Paid |
cancelled | The user cancelled, or it wasn't confirmed within 24 hours |
Failed payments are retried automatically; the user gets an email and can pay on their order page after updating their payment method.
Previewing totals
To show a total with VAT before the user confirms, ask for a preview. Nothing is stored and no token is needed:
curl -X POST https://id.anikeen.com/api/v1/orders/preview \
-H 'Accept: application/json' -H 'Content-Type: application/json' \
-d '{"billing_address": {"country_iso": "DE"},
"items": [{"type": "physical", "name": "T-shirt", "gross_price": "24.90", "unit": "piece", "units": 1}]}'$preview = app(\Anikeen\Id\AnikeenId::class)->createOrderPreview([
'country_iso' => 'DE',
'items' => [['type' => 'physical', 'name' => 'T-shirt', 'gross_price' => '24.90', 'unit' => 'piece', 'units' => 1]],
])->shift();
$preview->gross_total;Refunds
When money is given back for an order (a refund or a partial cancellation, with a credit note), Anikeen ID sends order.refunded. The order then carries refunded_total and refunds. A full refund also cancels the order (order.cancelled).
Confirmable orders (trusted apps)
Trusted apps can charge one-off orders right away ("checkout": true). With "confirm": true the user confirms and pays the order on Anikeen ID instead, like for a third-party app – e.g. a top-up the user starts in your app. Use the app token on POST /api/v1/admin/orders with user_id, or the user's token on POST /api/v1/orders:
$order = app(\Anikeen\Id\AnikeenId::class)->createOrderForUser($team->owner->anikeen_id, [
'group' => $team->id,
'confirm' => true,
'return_url' => route('billing.topup.done'),
'metadata' => ['topup' => $topup->id],
'items' => [['type' => 'digital', 'name' => 'Credit', 'unit' => 'onetime', 'units' => 1, 'gross_price' => '10.00']],
])->data;
return redirect()->away($order->confirmation_url);confirmneedsitemsand can't be combined withcheckoutor a transaction (422).- The draft expires after 24 hours (
expires_at): it is cancelled,confirmation_urlbecomesnullandcheckoutanswers409 confirmation_expired. - Follow the order through its webhooks:
order.created, thenorder.completedonce paid (order.payment_failedfor a declined charge, retried automatically) ororder.cancelledwhen the user declines or it expires.
Without confirm, trusted apps' drafts don't expire and checkout: true charges right away.
Errors
| Status | error / meaning |
|---|---|
| 202 | checkout: the payment is not completed yet; the order is in data, follow it through its webhooks |
| 402 | the payment failed (direct checkout) |
| 403 | confirmation_required (third-party checkout of a draft; with confirmation_url) |
| 409 | confirmation_expired; or the order can't be checked out or revoked in its current state |
| 422 | validation, e.g. a return_url that isn't one of your origins |