Interaction with merchant websites¶
The payment process¶
By design, the Taler payment process ensures the following properties:
- The user must see and accept a contract in a secure context before the payment happens. That contract accounts for all the items which are supposed to be bought.
- The payment process must be idempotent, that is at any later time the customer must be able to replay the payment and retrieve the resource he paid for. In case where a physical item was bought, this online resource is the merchant’s order status page, which may contain tracking information for the customer. Note that by replaying the payment we mean reusing the same coins used to pay for the product the first time to get the same product the user got the first time. So the replay does NOT subtract further credit from the user’s total budget.
- Purchases are shareable: any purchase is given a URL that allows other users to buy the same item(s).
The merchant must also have a fulfillment URL, that addresses points 2 and 3 above. In particular, fulfillment URL is responsible for:
- Deliver the final product to the user after the payment
- Instruct the wallet to send the payment to the pay URL
- Redirect the user to the offer URL in case they hit a shared fulfillment URL.
taler-wallet-lib. See https://git.taler.net/web-common.git/tree/taler-wallet-lib.ts
For example, suppose Alice wants to pay for a movie. She will first select the movie from the catalog, which directs her to the offer URL https://merchant/offer?x=8ru42. This URL generates a “402 Payment Required” response, and will instruct the wallet about the contract’s URL. Then the wallet downloads the contract that states that Alice is about to buy a movie. The contract includes a fresh transaction ID, say 62. Alice’s browser detects the response code and displays the contract for Alice.
Alice then confirms that she wants to buy the movie. Her wallet associates her confirmation with the details and a hash of the contract. After Alice confirms, the wallet redirects her to the fulfillment URL, say https://merchant/fulfillment?x=8ru42&tid=62 that is specified in the contract.
The first time Alice visits this URL, the merchant will again generate a “402 Payment Required” response, this time not including the full contract but merely the hash of the contract (which includes Alice’s transaction ID 62), as well as the offer URL (which Alice will ignore) and the pay URL. Alice’s wallet will detect that Alice already confirmed that she wants to execute this particular contract. The wallet will then transmit the payment to the pay URL, obtain a response from the merchant confirming that the payment was successful, and then reload the fulfillment URL.
This time (and every time in the future where Alice visits the fulfillment URL), she receives the movie. If the browser has lost the session state, the merchant will again ask her to pay (as it happened the very first time she visited the fulfillment URL), and she will authenticate by replaying the payment.
If Alice decides to share the fulfillment URL with Bob and he visits it, his browser will not have the right session state and furthermore his wallet will not be able to replay the payment. Instead, his wallet will automatically redirect Bob to the offer URL and allow him to purchase the movie himself.
Making an offer¶
When a user visits a offer URL, the merchant returns a page that can interact
This page’s main objective is to inform the wallet on where it should get the
taler-wallet-lib. This function will download the contract from
<CONTRACT-URL> and hand it to the wallet.
In case of HTTP headers-based protocol, the merchant needs to set the header X-Taler-contract-url to the contract URL. Once this information reaches the browser, the wallet will takes action by reading that header and downloading the contract.
Either way, the contract gets to the wallet which then renders it to the user.
Fulfillment interaction details¶
A payment process is triggered whenever the user visits a fulfillment URL and he has no rights in the session state to get the items accounted in the fulfillment URL. Note that after the user accepts a contract, the wallet will automatically point the browser to the fulfillment URL.
Becasue fulfillment URLs implements replayable and shareable payments (see points 2,3 above), fulfillment URL parameter must encompass all the details necessary to reconstruct a contract.
That saves the merchant from writing contracts to disk upon every contract generation, and defer this operation until customers actually pay.
HTTP headers based¶
Once the fulfillment URL gets visited, deliver the final product if the user has paid, otherwise: the merchant will reconstruct the contract and re-hash it, sending back to the client a “402 Payment required” status code and some HTTP headers which will help the wallet to manage the payment. Namely:
The wallet then looks at X-taler-contract-hash, and can face two situations:
- This hashcode is already present in the wallet’s database (meaning that the user did accept the related contract), so the wallet can send the payment to X-taler-pay-URL. During this operation, the wallet associates the coins it sent to X-taler-pay-URL with this hashcode, so that it can replay payments whenever it gets this hashcode again.
- This hashcode is unknown to the wallet (meaning that the user visited a shared fulfillment URL). The wallet then points the browser to X-taler-offer-URL, which is in charge of generating a contract referring to the same items accounted in the fulfillment URL. Of course, the user is then able to accept or not the contract.
Once the fulfillment URL gets visited, deliver the final product if the user has paid, otherwise:
needs to include a call to
taler.executeContract(..). See the following example:
The logic which will take place is the same as in the HTTP header based protocol.
executePayment(..) gets executed in the browser, it will hand its three
parameters to the wallet, which will:
- Send the payment to <PAY-URL> if <CONTRACT-HASH> is found in its database (meaning that the user accepted it).
- Redirect the browser to <OFFER-URL>, if <CONTRACT-HASH> is NOT found in its database, meaning that the user visited a shared fulfillment URL.