Skip to content

Orders ​

An order is a one-off purchase: digital or physical goods, charged on its own.

Endpoints ​

MethodPath
GET/api/v1/ordersthe user's orders, newest first; filter group
POST/api/v1/orderscreate 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}/checkoutcharge the order (trusted apps; see below)
PUT/api/v1/orders/{id}/revokerevoke 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}/itemsthe 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 ​

shell
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"}
    ]
  }'
php
$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
itemsrequired for third-party apps and with confirm: the items, see below
billing_address_idan address of the user (see Account data)
billing_addressinstead 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_addressfor physical goods, see Shipments
groupyour app's group, e.g. a team ID
metadatayour own data (an object, at most 50 keys), returned as is in the API and the order webhooks
return_urlwhere the user returns after confirming; the origin of one of your redirect URIs (422 otherwise)
withdrawal_waiver_requiredask for the early start
confirmtrusted apps: let the user confirm, see below
checkouttrusted apps: charge right away

Item fields:

Field
typedigital, physical or physical-reduced (the VAT treatment, see VAT)
namerequired, at most 255 characters
descriptionoptional, at most 255 characters
unitpiece or onetime
unitsthe quantity, at least 1
gross_price or priceper unit; gross (VAT included, the user pays exactly this) or net; up to 6 decimals; not negative for third-party apps
image_urloptional; 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

text
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:

php
$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 ​

statusMeaning
draftCreated, not confirmed by the user yet
pendingConfirmed, the payment is still processing (or failed and is retried)
completedPaid
cancelledThe 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:

shell
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}]}'
php
$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:

php
$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);
  • confirm needs items and can't be combined with checkout or a transaction (422).
  • The draft expires after 24 hours (expires_at): it is cancelled, confirmation_url becomes null and checkout answers 409 confirmation_expired.
  • Follow the order through its webhooks: order.created, then order.completed once paid (order.payment_failed for a declined charge, retried automatically) or order.cancelled when the user declines or it expires.

Without confirm, trusted apps' drafts don't expire and checkout: true charges right away.

Errors ​

Statuserror / meaning
202checkout: the payment is not completed yet; the order is in data, follow it through its webhooks
402the payment failed (direct checkout)
403confirmation_required (third-party checkout of a draft; with confirmation_url)
409confirmation_expired; or the order can't be checked out or revoked in its current state
422validation, e.g. a return_url that isn't one of your origins

Anikeen ID developer documentation