.. This file is part of GNU TALER. Copyright (C) 2024 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation; either version 2.1, or (at your option) any later version. TALER is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with TALER; see the file COPYING. If not, see .. target audience: developer, core developer .. _terminal-api: ============ Terminal API ============ .. contents:: Table of Contents :local: Introduction ------------ Terminals are devices where users can withdraw digital cash. This API is offered by a payment service backend and is used by such terminals. It enables imposing limits on withdrawals per unique user ID (and communicating such limits to the terminals) as well as setting up and triggering withdrawal operations. Implementations of this API typically interact with a terminal-specific payment service (or a bank) to realize the service. Authentication -------------- Terminals must authenticate against all terminal API using basic auth according to `HTTP basic auth `_. Config ------ .. http:get:: /config Return the protocol version and configuration information about the bank. This specification corresponds to ``current`` protocol being version **0**. **Response:** :http:statuscode:`200 OK`: Response is a `TerminalConfig`. **Details:** .. ts:def:: TerminalConfig interface TerminalConfig { // Name of the API. name: "taler-terminal"; // libtool-style representation of the Bank protocol version, see // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning // The format is "current:revision:age". version: string; // Terminal provider display name to be used in user interfaces. provider_name: string; // The currency supported by this Terminal-API // must be the same as the currency specified // in the currency field of the wire gateway config currency: string; // Wire transfer type supported by the terminal. // FIXME: needed? wire_type: string; } .. http:get:: /quotas/$UUID Obtain the current transaction limit for the given $UUID. The UUID should be an encoding of a unique identifier of the user. **Response:** :http:statuscode:`200 OK`: Response is a `WithdrawLimit`. **Details:** .. ts:def:: WithdrawLimit interface WithdrawLimit { // Maximum amount that can be withdrawn now. limit: Amount; // Time when the limit may increase. expiration: Timestamp; } .. http:post:: /quotas/$UUID/lock This endpoint allows a terminal to reserve a given amount from the user's quota, ensuring that a subsequent operation will not fail due to a quota violation. **Request:** The request should be a `WithdrawLimitLock`. **Response:** :http:statuscode:`204 No content`: The change was accepted. :http:statuscode:`409 Conflict`: The proposed lock would push the user above the limit. **Details:** .. ts:def:: WithdrawLimitLock interface WithdrawLimitLock { // Amount that should be reserved from the quota. limit: Amount; // ID for the lock. FIXME: could also be 32-byte nonce? lock: string; // How long should the lock be held? expiration: Timestamp; } .. http:delete:: /quotas/$UUID/lock/$LOCK This endpoint allows the terminal to clear a lock it may have previously created. **Response:** :http:statuscode:`204 No content`: The lock was cleared. :http:statuscode:`404 Not found`: The lock is unknown. :http:statuscode:`409 Conflict`: The lock was already used in a withdrawal operation. .. http:post:: /withdrawals This endpoint allows the terminal to set up a new withdrawal operation. **Request:** The request should be a `TerminalWithdrawalSetup`. **Response:** :http:statuscode:`200 Ok`: The operation was created. The response will be a `TerminalWithdrawalSetupResponse`. :http:statuscode:`404 Not found`: A lock was specified but the lock is not known for the given user. :http:statuscode:`409 Conflict`: A conflicting withdrawal operation already exists or the amount would violate the quota for the specified user. **Details:** .. ts:def:: TerminalWithdrawalSetup interface TerminalWithdrawalSetup { // Amount to withdraw. If given, the wallet // cannot change the amount! amount?: Amount; // Suggested amount to withdraw. If given, the wallet can // still change the suggestion. suggested_amount?: Amount; // A provider-specific transaction identifier. // This identifier may be used to attest the // payment at the provider's backend. Optional, // as we may not know it at this time. provider_transaction_id?: string; // The non-Taler fees the customer will have // to pay to the service provider // they are using to make this withdrawal. // If the fees cannot be precalculated, // they can be specified in the /withdrawals/$WITHDRAWAL_ID/check // request after the transaction was executed. terminal_fees?: Amount; // Unique request ID to make retried requests idempotent. request_uid: string; // Unique user ID of the user. Optional // in case a user Id is not (yet) known. user_uuid?: string; // ID identifying a lock on the quota that the client // may wish to use in this operation. May only be // present if ``user_uuid`` is also given. lock?: string; } .. ts:def:: TerminalWithdrawalSetupResponse interface TerminalWithdrawalSetupResponse { // ID identifying the withdrawal operation being created. withdrawal_id: string; } .. http:post:: /withdrawals/$WITHDRAWAL_ID/check Endpoint for providers to notify the terminal backend about a payment having happened. This will cause the bank to validate the transaction and allow the withdrawal to proceed. The API is idempotent, meaning sending a payment notification for the same ``WITHDRAWAL_ID`` return successfuly but not change anything. This endpoint is always *optional*: the bank, exchange and wallet should all eventually notice the wire transfer with or without this endpoint being called. However, by calling this endpoint checks that might otherwise only happen periodically can be triggered immediately. The endpoint may also be used to associate a user ID at a very late stage with the withdrawal --- and still get an immediate failure if we are above the quota. .. note:: The backend shall **never** just accept this claim that the payment was confirmed, but instead needs to internally attest that the payment was successful using provider-specific transaction validation logic! The point of this endpoint is merely to trigger this validation **now**. **Request:** The body of the request must be a `TerminalWithdrawalConfirmationRequest`. **Response:** :http:statuscode:`204 No content`: The payment notification was processed successfully. :http:statuscode:`404 Not found`: The withdrawal operation was not found. :http:statuscode:`409 Conflict`: The withdrawal operation has been previously aborted and cannot be confirmed anymore. :http:statuscode:`451 Unavailable for Legal Reasons`: The withdrawal operation cannot be confirmed because it would put the user above the legal limit. The payment service will eventually bounce the transfer (if it were to become effective), but the user should already be shown an error. **Details:** .. ts:def:: TerminalWithdrawalConfirmationRequest interface TerminalWithdrawalConfirmationRequest { // A provider-specific transaction identifier. // This identifier may be used to facilitate the // backend to check that the credit was confirmed. provider_transaction_id?: string; // The fees which the customer had to pay to the // provider terminal_fees?: Amount; // A user-specific identifier for quota checks. user_uuid?: string; // ID identifying a lock on the quota that the client // may wish to use in this operation. May only be // present if ``user_uuid`` is also given. lock?: string; } .. http:get:: /withdrawals/$WITHDRAWAL_ID Query information about a withdrawal, identified by the ``WITHDRAWAL_ID``. **Request:** :query long_poll_ms: *Optional.* If specified, the bank will wait up to ``long_poll_ms`` milliseconds for operationt state to be different from ``old_state`` before sending the HTTP response. A client must never rely on this behavior, as the bank may return a response immediately. :query old_state: *Optional.* Default to "pending". **Response:** :http:statuscode:`200 OK`: The withdrawal operation is known to the bank, and details are given in the `BankWithdrawalOperationStatus` response body. :http:statuscode:`404 Not found`: The operation was not found. .. http:delete:: /withdrawals/$WITHDRAWAL_ID/abort Aborts ``WITHDRAWAL_ID`` operation. Has no effect on an already aborted operation. This endpoint can be used by the terminal if the terminal aborts the transaction, ensuring that the operation is also aborted at the bank. **Request:** The request body is empty. **Response:** :http:statuscode:`204 No content`: The withdrawal operation has been aborted. :http:statuscode:`404 Not found`: The withdrawal operation was not found. :http:statuscode:`409 Conflict`: The withdrawal operation has been confirmed previously and can't be aborted. Endpoints for Integrated Sub-APIs --------------------------------- .. http:any:: /taler-integration/* All endpoints under this prefix are specified by the. :doc:`GNU Taler bank integration API `. This API handles the communication with Taler wallets. .. http:any:: /taler-wire-gateway/* All endpoints under this prefix are specified by the :doc:`GNU Taler wire gateway API `. The endpoints are only available for accounts configured with ``is_taler_exchange=true``.