taler-docs

Documentation for GNU Taler components, APIs and protocols
Log | Files | Refs | README | LICENSE

commit 31771451cedb9784cce621d0af5028897546bebf
parent 1a7dff6c8ddf0a143797f8790887858cf900ee2e
Author: Hernâni Marques <hernani+clementine@vecirex.net>
Date:   Sat,  5 Sep 2026 03:20:47 +0200

10989/docs: stage e2e onboarding (API access) + regio notes

Diffstat:
Mdeployments/tops-stage-devtesting.rst | 233++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 225 insertions(+), 8 deletions(-)

diff --git a/deployments/tops-stage-devtesting.rst b/deployments/tops-stage-devtesting.rst @@ -1,15 +1,105 @@ +Testing in the TOPS Staging Environment +======================================= + +This document contains a detailled, step-by-step instructions for testing +with the staging environment for the Taler Operations deployment. + +The staging environment (on host ``rusty``) is almost equivalent to the production +environment. It is, however, not connected to a real bank account. + +Prerequisites +------------- + +An administrator needs to enable your SSH key for testing +in the staging environment. + + +Withdrawals: Basic Withdrawal +----------------------------- + +1. Scan the following QR code to start a withdrawal from the `stage exchange <https://exchange.stage.taler-ops.ch/>`_: + + .. image:: ./qr-withdraw-tops-stage.png + + ``taler://withdraw-exchange/exchange.stage.taler-ops.ch/`` + +2. Confirm the withdrawal in the wallet. + +3. Run the following command to fake a wire transfer, using a randomly + generated creditor IBAN. The ``$AMOUNT`` and ``$SUBJECT`` should be + taken from the wire transfer instructions in the wallet UI. + + .. code:: none + + ssh -T devtesting@rusty.taler-ops.ch "fake-incoming --amount $AMOUNT --subject '$SUBJECT'" + +4. Check that the withdrawal succeeded in the wallet. + + +Deposits: Basic Deposit +----------------------- + +1. Do a basic withdrawal. +2. Initiate a deposit in the wallet UI, using the receiver account known to the wallet from the withdrawal. +3. The deposit transaction should now ask for KYC information. Fill out the corresponding form(s). +4. The deposit transaction should finish. + +Deposits: Deposit with KYC Auth +------------------------------- + +1. Do a basic withdrawal. + +2. Generate an IBAN via: + + .. code:: none + + ssh -T devtesting@rusty.taler-ops.ch geniban + +3. Initiate a deposit in the wallet UI to the randomly generated IBAN. + +4. The deposit transaction should now ask for a KYC auth transfer. Satisfy the auth transfer by running: + + .. code:: none + + ssh -T devtesting@rusty.taler-ops.ch "fake-incoming --amount $AMOUNT --subject '$SUBJECT' --debit-payto '$DEBIT_PAYTO'" + + with the information shown in the wallet UI, where the ``$DEBIT_PAYTO`` must contain the IBAN generated in step (2). + + +5. The deposit transaction should now ask for KYC information. Fill out the corresponding form(s). + +6. The deposit transaction should finish. + Merchant: End-to-end onboarding (staging) ----------------------------------------- Stage-specific glue for the merchant path already described elsewhere: -:ref:`taler-merchant-backend-operator-manual` (SPA) and *Merchant: -Onboarding* in :doc:`tops` (bank account → KYC auth → accept exchange -terms of service → accept payments). Wire faking reuses ``geniban`` / -``fake-incoming`` from *Deposits: Deposit with KYC Auth* above. +:ref:`taler-merchant-backend-operator-manual` (SPA and HTTP API) and +*Merchant: Onboarding* in :doc:`tops` (bank account → KYC auth → accept +exchange terms of service → accept payments). Authentication is +documented under :ref:`merchant-api-authentication`. Wire faking +reuses ``geniban`` / ``fake-incoming`` from *Deposits: Deposit with KYC +Auth* above. + +Two variants: **SPA (mostly manual)** below, then **API** (curl / +scripted self-provision, login tokens, and orders). -This section is the **mostly manual** path (merchant portal / SPA). +This page is written for **TOPS stage** (``$BASE`` below). Deployments +like **regional currencies** — overview at +`https://regio.taler.net/ <https://regio.taler.net/>`_, setup via +``taler-deployment.git`` ``regional-currency/`` (see the :doc:`automated +setup<../regional/regional-automated-manual>` and :doc:`custom +setup<../regional/regional-custom-manual>` manuals) — can differ. +Look at the merchant ``/config``: if ``mandatory_tan_channels`` is +empty, MFA for self-provisioning is effectively off and +``POST /instances`` often returns **204** (instance exists immediately, +no ``/challenge/…`` round-trip) — typical for many **regio** setups. +Creating orders still needs at least one active bank account (otherwise +the backend rejects with a missing-account error). Wire faking via +``rusty`` / ``taler-devtesting`` is TOPS-stage specific (not the usual +regional-bank funding path). Variables used below (set your own values): @@ -18,8 +108,15 @@ Variables used below (set your own values): BASE=https://stage.my.taler-ops.ch INSTANCE=my-shop # instance id (slug) INSTANCE_PASSWORD=… # password chosen at signup + EMAIL=you@example.com # inbox that can receive stage TAN mail + PHONE=+41 7x xxx xx xx # real CH mobile; must match phone_regex + # from $BASE/config *and* be accepted by + # the SMS helper (dummy numbers fail with + # TALER_EC 2132 on /challenge/$ID) IBAN=… # from geniban DEBIT_PAYTO=payto://iban/$IBAN + TOKEN=… # access_token from /private/token + ORDER_ID=… # from PostOrderResponse ``$BASE/`` redirects to ``$BASE/webui/``. Use the `stage exchange <https://exchange.stage.taler-ops.ch/>`_ for payments. @@ -36,9 +133,20 @@ Shared bank / KYC steps IBAN=$(ssh -T devtesting@rusty.taler-ops.ch geniban) DEBIT_PAYTO="payto://iban/$IBAN" -2. Register that IBAN in the portal under **Bank account** - (:ref:`instance-account-setup`). Skip revenue-API credentials - unless an administrator provided stage ones. +2. Register that IBAN on the instance (:ref:`instance-account-setup`) — + in the portal under **Bank account**, or via API after you have a + ``$TOKEN``: + + .. code:: none + + curl -sS \ + -H "Authorization: Bearer $TOKEN" \ + -H 'Content-Type: application/json' \ + -d "{\"payto_uri\":\"$DEBIT_PAYTO\"}" \ + "$BASE/instances/$INSTANCE/private/accounts" + + Skip revenue-API credentials unless an administrator provided stage + ones. 3. When the exchange requires the KYC auth transfer (*Merchant: Onboarding* in :doc:`tops`), satisfy it like *Deposits: Deposit with @@ -75,3 +183,112 @@ Normal interactive path (:ref:`Instance-setup`, *Self-provisioning*, 4. Pay from the wallet (shared step 5) and confirm paid status in the SPA. + +API (self-provision → password → login token → Bearer) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Same backend via HTTP +(:http:post:`/instances`, :ref:`merchant-api-authentication`, +:http:post:`[/instances/$INSTANCE]/private/token`, +:http:post:`[/instances/$INSTANCE]/private/orders`). +Private endpoints need +``Authorization: Bearer secret-token:…`` (RFC 8959). + +On this stage backend, expect the MFA path below (``mandatory_tan_channels`` +is ``email`` and ``sms``). Where that list is empty, skip to step 3 after a +**204** create. + +1. Self-provision (:http:post:`/instances`). Example body + (`InstanceConfigurationRequest`; ``auth.method`` = ``token``): + + .. code:: none + + curl -sS -H 'Content-Type: application/json' \ + -d "{ + \"id\": \"$INSTANCE\", + \"name\": \"Example Shop\", + \"email\": \"$EMAIL\", + \"phone_number\": \"$PHONE\", + \"auth\": {\"method\": \"token\", \"password\": \"$INSTANCE_PASSWORD\"}, + \"address\": {\"country\": \"CH\"}, + \"jurisdiction\": {\"country\": \"CH\"}, + \"use_stefan\": true + }" \ + "$BASE/instances" + + Typical response before MFA: **HTTP 202** `ChallengeResponse` with + ``combi_and: true`` and one challenge per TAN channel, e.g.: + + .. code:: none + + { + "combi_and": true, + "challenges": [ + {"tan_channel": "email", "tan_info": "…", "challenge_id": "$CHALLENGE_EMAIL"}, + {"tan_channel": "sms", "tan_info": "…", "challenge_id": "$CHALLENGE_SMS"} + ] + } + + Until both TANs are solved, ``$INSTANCE`` does **not** exist + (``/instances/$INSTANCE/private/…`` → **404**). + +2. Request and confirm each TAN on the **unprefixed** challenge URLs + (instance path segment optional; before create, only this form + works — see *Solving challenges* in the merchant API): + + .. code:: none + + curl -sS -H 'Content-Type: application/json' -d '{}' \ + "$BASE/challenge/$CHALLENGE_ID" + curl -sS -H 'Content-Type: application/json' \ + -d "{\"tan\":\"$TAN\"}" \ + "$BASE/challenge/$CHALLENGE_ID/confirm" + + Repeat for every ``challenge_id``. A successful request returns + **200**; a rejected SMS/e-mail address returns **400** with code + **2132** (fix ``$PHONE`` / ``$EMAIL``). Wrong ``$TAN`` on confirm + returns **409**. + + Retry the **same** ``POST $BASE/instances`` body with: + + .. code:: none + + -H "Taler-Challenge-Ids: $CHALLENGE_EMAIL,$CHALLENGE_SMS" + + Expect **200** / **204** when the instance is created. With + unsolved challenges the retry stays at **202**. + +3. Password → login token (Basic: user ``$INSTANCE``, password + ``$INSTANCE_PASSWORD``; `LoginTokenRequest`): + + .. code:: none + + curl -sS -u "$INSTANCE:$INSTANCE_PASSWORD" \ + -H 'Content-Type: application/json' \ + -d '{"scope":"order-simple"}' \ + "$BASE/instances/$INSTANCE/private/token" + + From `LoginTokenSuccessResponse`, set ``TOKEN`` to ``access_token`` + (already includes the ``secret-token:`` prefix). Scopes such as + ``spa`` or ``all`` work the same way if you need broader rights. + +4. Create an order with the Bearer token: + + .. code:: none + + curl -sS \ + -H "Authorization: Bearer $TOKEN" \ + -H 'Content-Type: application/json' \ + -d '{"order":{"summary":"stage test","amount":"CHF:1"}}' \ + "$BASE/instances/$INSTANCE/private/orders" + +5. Read ``order_id`` from `PostOrderResponse`. Fetch ``taler_pay_uri`` + via :http:get:`[/instances/$INSTANCE]/private/orders/$ORDER_ID` + (or the public order status URL). Finish *Shared bank / KYC steps* + if needed, then pay from the wallet. + +.. note:: + + Prefer login tokens from ``/private/token``. Long-lived + ``Authorization: Bearer secret-token:$INSTANCE_PASSWORD`` is the + deprecated ``token`` method and will be phased out.