Payment Admin
The Payment Admin API mutates orders after checkout: deliver (capture), cancel, credit (refund), and modify rows. Mutating operations are asynchronous (HTTP 202) — they return a task reference URL you can poll.
Source of truth
The full reference with every example lives in the README — Admin.
Order operations
$req = Svea::admin()->order('12345678');
$req->get(); // AdminOrderResponse
$req->deliver(); // DeliverResponse — all rows
$req->deliver(rows: [101, 102]); // partial
$req->cancel();
$req->cancelAmount(50000);
$req->cancelRow(rowId: 101);
$req->withIdempotencyKey('key')->deliver();Delivery operations (credit / refund)
$delivery = Svea::admin()->order('12345678')->delivery(456);
$delivery->credit()->rows([101, 102])->send();
$delivery->credit()->newRow(fn ($row) => $row->name('Return fee')->unitPrice(5000)->quantity(100)->vatPercent(2500))->send();
$delivery->creditAmount(9900);Modify order rows
All three row-mutation methods take fluent callbacks that build an AdminOrderRow:
// Add a new row — returns ['order_row_id' => int, 'task_reference' => string]
$result = Svea::admin()->order('12345678')->addOrderRow(function (AdminOrderRow $row) {
$row->name('Extra item')
->sku('EXTRA-1')
->unitPrice(5000)
->quantity(100)
->vatPercent(2500)
->unit('st');
});
// Update one row by ID
Svea::admin()->order('12345678')->updateOrderRow(rowId: 101, callback: function (AdminOrderRow $row) {
$row->unitPrice(4500)->name('Updated name');
});
// Replace ALL rows — pass one callback per replacement row
Svea::admin()->order('12345678')->replaceOrderRows(
fn (AdminOrderRow $row) => $row->name('Widget')->sku('WGT-1')->unitPrice(9900)->quantity(100)->vatPercent(2500),
fn (AdminOrderRow $row) => $row->name('Shipping')->sku('SHIP')->unitPrice(4900)->quantity(100)->vatPercent(2500),
);AdminOrderRow does not apply the SDK-level minor-unit conversion that Checkout's OrderRow does — pass already-scaled values (100 = 1 unit, 2500 = 25%).
Conditional builders — when() / unless()
AdminOrderRequest and AdminOrderRow both use the Conditionable trait. Inline branching without breaking the chain:
Svea::admin()
->order($externalOrderId)
->withIdempotencyKey('capture-' . $payment->id)
->when(
! empty($partialRows),
fn ($req) => $req->deliver(rows: $partialRows),
fn ($req) => $req->deliver(), // optional else branch
);
// Inside row callbacks too
Svea::admin()->order('12345678')->addOrderRow(fn (AdminOrderRow $row) => $row
->name($item->name)
->unitPrice($item->price)
->quantity(100)
->vatPercent(2500)
->when($item->is_discounted, fn ($r) => $r->discountPercent(1000))
->unless($item->is_taxable, fn ($r) => $r->vatPercent(0))
);when($condition, $then, $else = null) calls $then($builder) if truthy, otherwise the optional $else($builder). unless() is the inverse. Both return the builder.
Polling tasks
$deliver = Svea::admin()->order('12345678')->deliver();
$taskUrl = $deliver->taskReference();
do {
sleep(1);
$task = Svea::admin()->task($taskUrl);
} while ($task->pending());
$task->completed(); // bool
$task->failed(); // bool
$task->resource; // string|null — URL to the resulting resourceIn production run the poll loop inside a queued job with retries rather than blocking an HTTP request.
AdminOrderResponse helpers
$adminOrder = Svea::admin()->order('12345678')->get();
$adminOrder->status(); // SveaOrderStatus enum
$adminOrder->actions(); // string[]
$adminOrder->canDeliver();
$adminOrder->canCredit();
$adminOrder->canCancel();
$adminOrder->deliveries(); // array
$adminOrder->delivery(456);
$adminOrder->deliveryRowIds(456);
$adminOrder->hasAction('CanDeliverOrder');
$adminOrder->hasStatus('Open');