Subscription ordering and payment webhook – behaviour
Checks and permission grants of the order endpoint, and signature verification, idempotency and state changes of the payment provider notification.
Order (api/subscription/order.order)
POST definition_id, plan_id, months. The code checks no function permission.
- API key → the key owner is the orderer (401 if missing).
getDefinition(): onlystatus=1andenabled=1(otherwise 404);definitionHasPlan(400);planOnStore(403).- Validity: start = the user's registration (
registeredAt), end = start +months(max 120; 0 = open-ended). - Targets: with a home client (
dlbtclient->homeClient) every member of the client (usersOf), otherwise only the orderer. - Per member
dlbtprovision->materialise(uid, definition_id, plan_id, from, to, user_id, 'order', false)— adds, does not replace. - Response:
company_client_id,users,result(created, updated, deleted),valid_from,valid_to,definition.
Prerequisite: dlbtprovision registered (otherwise 409). Tables read: subscription_definition, subscription_definition_plan, subscription_plan, subscription_plan_to_store; written: user_feature (source='order'). No payment check.
Webhook (api/subscription/webhook)
A public endpoint protected by signatures.
- SimplePay (if
dlbtpayment->provider()=simplepay):Signatureheader checked on the raw body (401); JSON (400);event_refrequired (400);claimEvent()unique-key insert, a repeated event only gets a receipt;applySimplepay(): find the transaction, attachprovider_ref,payment.succeeded→ store token andsettlePaid(),payment.failed→settleFailed(); finallymarkEventProcessed()and a signed receipt. - Generic path: HMAC in the
X-Dlbt-Signatureheader with the webhook secret stored in the module settings (a missing secret is also 401);id,type,provider,data; idempotency (duplicate:true);payment.succeeded→settlePaid,payment.failed→settleFailed,subscription.canceled→ statecanceled. On a processing error 500 ("The event was stored but could not be processed."). webhook.back: information only (pending:true), no state change — a browser return is no proof.
The own tables of the dlbtpayment library (event, transaction, subscription) cannot be named from the controller. Charge requests are created by the subscription lifecycle background job.