summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2021-06-22 19:34:47 +0200
committerChristian Grothoff <christian@grothoff.org>2021-06-22 19:34:47 +0200
commit555a18f735324a0d7829262529124b029098340d (patch)
treeaeaa5d6aef29c280209dea44d3141e7bce54c3d6 /core
parent1c356f81ea3051aa443e61e951aace709e90d25d (diff)
parentf47314fe9460324d5bf331d0dc71d5358c6d8e08 (diff)
downloaddocs-555a18f735324a0d7829262529124b029098340d.tar.gz
docs-555a18f735324a0d7829262529124b029098340d.tar.bz2
docs-555a18f735324a0d7829262529124b029098340d.zip
Merge branch 'dd13'
Diffstat (limited to 'core')
-rw-r--r--core/api-bank-merchant.rst122
-rw-r--r--core/api-common.rst454
-rw-r--r--core/api-exchange.rst1603
-rw-r--r--core/api-merchant.rst55
-rw-r--r--core/api-wire.rst41
-rw-r--r--core/index.rst5
6 files changed, 2131 insertions, 149 deletions
diff --git a/core/api-bank-merchant.rst b/core/api-bank-merchant.rst
new file mode 100644
index 00000000..790d3f74
--- /dev/null
+++ b/core/api-bank-merchant.rst
@@ -0,0 +1,122 @@
+..
+ This file is part of GNU TALER.
+ Copyright (C) 2021 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+
+============================
+Taler Bank Merchant HTTP API
+============================
+
+This section describes an API offered by the Taler wire gateway. The API is
+used by the merchant to query for incoming transactions.
+
+This API is TO BE implemented by the Taler Demo Bank, as well as by
+LibEuFin (work in progress).
+
+
+--------------
+Authentication
+--------------
+
+The bank library authenticates requests to the bank merchant API using
+`HTTP basic auth <https://tools.ietf.org/html/rfc7617>`_.
+
+--------------------------------
+Querying the transaction history
+--------------------------------
+
+
+.. http:get:: ${BASE_URL}/history
+
+ Return a list of transactions made from an exchange to the merchant.
+
+ Incoming transactions must contain a valid wire transfer identifier and
+ exchange base URL. If a bank transaction does not conform to the right
+ syntax, the wire gateway must not report it to the merchant via this
+ endpoint.
+
+ The bank account of the merchant is determined via the base URL and/or the
+ user name in the ``Authorization`` header. In fact, the transaction history
+ might come from a "virtual" account, where multiple real bank accounts are
+ merged into one history.
+
+ Transactions are identified by an opaque numeric identifier, referred to here
+ as *row ID*. The semantics of the row ID (including its sorting order) are
+ determined by the bank server and completely opaque to the client.
+
+ The list of returned transactions is determined by a row ID *starting point*
+ and a signed non-zero integer *delta*:
+
+ * If *delta* is positive, return a list of up to *delta* transactions (all matching
+ the filter criteria) strictly **after** the starting point. The transactions are sorted
+ in **ascending** order of the row ID.
+ * If *delta* is negative, return a list of up to *-delta* transactions (all matching
+ the filter criteria) strictly **before** the starting point. The transactions are sorted
+ in **descending** order of the row ID.
+
+ If *starting point* is not explicitly given, it defaults to:
+
+ * A value that is **smaller** than all other row IDs if *delta* is **positive**.
+ * A value that is **larger** than all other row IDs if *delta* is **negative**.
+
+ **Request**
+
+ :query start: *Optional.*
+ Row identifier to explicitly set the *starting point* of the query.
+ :query delta:
+ The *delta* value that determines the range of the query.
+ :query long_poll_ms: *Optional.* If this parameter is specified and the
+ result of the query would be empty, the bank will wait up to ``long_poll_ms``
+ milliseconds for new transactions that match the query to arrive and only
+ then send the HTTP response. A client must never rely on this behavior, as
+ the bank may return a response immediately or after waiting only a fraction
+ of ``long_poll_ms``.
+
+ **Response**
+
+ :http:statuscode:`200 OK`: JSON object of type `MerchantIncomingHistory`.
+ :http:statuscode:`400 Bad request`: Request malformed. The bank replies with an `ErrorDetail` object.
+ :http:statuscode:`401 Unauthorized`: Authentication failed, likely the credentials are wrong.
+ :http:statuscode:`404 Not found`: The endpoint is wrong or the user name is unknown. The bank replies with an `ErrorDetail` object.
+
+ .. ts:def:: MerchantIncomingHistory
+
+ interface MerchantIncomingHistory {
+
+ // Array of incoming transactions.
+ incoming_transactions : MerchantIncomingBankTransaction[];
+
+ }
+
+ .. ts:def:: MerchantIncomingBankTransaction
+
+ interface MerchantIncomingBankTransaction {
+
+ // Opaque identifier of the returned record.
+ row_id: SafeUint64;
+
+ // Date of the transaction.
+ date: Timestamp;
+
+ // Amount transferred.
+ amount: Amount;
+
+ // Payto URI to identify the sender of funds.
+ debit_account: string;
+
+ // Base URL of the exchange where the transfer originated form.
+ exchange_url: string;
+
+ // The wire transfer identifier.
+ wtid: WireTransferIdentifierRawP;
+ }
diff --git a/core/api-common.rst b/core/api-common.rst
index 19f6bf55..9c23b905 100644
--- a/core/api-common.rst
+++ b/core/api-common.rst
@@ -64,6 +64,8 @@ handle the error as if an internal error (500) had been returned.
changed, the client MUST follow the link to the new location. If possible,
the client SHOULD remember the new URL for the reserve for future
requests.
+ :http:statuscode:`400 Bad request`:
+ One of the arguments to the request is missing or malformed.
:http:statuscode:`500 Internal server error`:
This always indicates some serious internal operational error of the exchange,
such as a program bug, database problems, etc., and must not be used for
@@ -75,10 +77,7 @@ handle the error as if an internal error (500) had been returned.
although the auditor API for this is not yet specified. However, as internal
server errors are always reported to the exchange operator, a good operator
should naturally be able to address them in a timely fashion, especially
- within 24h. When generating an internal server error, the exchange responds with
- a JSON object containing the following fields: FIXME: What are the fields?
- :http:statuscode:`400 Bad request`:
- One of the arguments to the request is missing or malformed.
+ within 24h.
Unless specified otherwise, all error status codes (4xx and 5xx) have a message
body with an `ErrorDetail` JSON object.
@@ -500,6 +499,13 @@ uses 512-bit hash codes (64 bytes).
uint8_t hash[64]; // usually SHA-512
};
+.. _TALER_EcdhEphemeralPublicKeyP:
+.. sourcecode:: c
+
+ struct TALER_EcdhEphemeralPublicKeyP {
+ uint8_t ecdh_pub[32];
+ };
+
.. _reserve-pub:
.. sourcecode:: c
@@ -584,6 +590,13 @@ uses 512-bit hash codes (64 bytes).
uint32_t value[4];
};
+.. _WadId:
+.. sourcecode:: c
+
+ struct TALER_WadId wad_id {
+ uint32_t value[6];
+ };
+
.. _eddsa-coin-pub:
.. sourcecode:: c
@@ -706,11 +719,6 @@ within the
struct TALER_MerchantPublicKeyP merchant;
};
-.. _TALER_RefreshCommitmentP:
-.. sourcecode:: c
-
- // FIXME: put definition here
-
.. _TALER_RefreshMeltCoinAffirmationPS:
.. sourcecode:: c
@@ -753,6 +761,9 @@ within the
struct TALER_ExchangePublicKeyP signkey_pub;
};
+.. _TALER_ExchangeKeySetPS:
+.. sourcecode:: c
+
struct TALER_ExchangeKeySetPS {
/**
* purpose.purpose = TALER_SIGNATURE_EXCHANGE_KEY_SET
@@ -793,7 +804,6 @@ within the
struct GNUNET_HashCode h_wire_details;
};
-
.. _TALER_MasterWireFeePS:
.. sourcecode:: c
@@ -814,7 +824,7 @@ within the
struct TALER_DepositTrackPS {
/**
- * purpose.purpose = TALER_SIGNATURE_MASTER_SEPA_DETAILS || TALER_SIGNATURE_MASTER_TEST_DETAILS
+ * purpose.purpose = TALER_SIGNATURE_MERCHANT_TRACK_TRANSACTION
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
struct GNUNET_HashCode h_contract_terms;
@@ -834,7 +844,6 @@ within the
struct TALER_AmountNBO deposit_fee;
};
-
.. _TALER_WireDepositDataPS:
.. _TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT:
.. sourcecode:: c
@@ -917,12 +926,31 @@ within the
.. _TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND:
.. sourcecode:: c
- // FIXME: put definition here
+ struct TALER_RefundConfirmationPS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND.
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct GNUNET_HashCode h_contract_terms;
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+ struct TALER_MerchantPublicKeyP merchant;
+ uint64_t rtransaction_id;
+ struct TALER_AmountNBO refund_amount;
+ };
.. _TALER_SIGNATURE_MERCHANT_TRACK_TRANSACTION:
.. sourcecode:: c
- // FIXME: put definition here
+ struct TALER_DepositTrackPS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_MERCHANT_TRACK_TRANSACTION.
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct GNUNET_HashCode h_contract_terms;
+ struct GNUNET_HashCode h_wire;
+ struct TALER_MerchantPublicKeyP merchant;
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+ };
.. _TALER_RefundRequestPS:
.. sourcecode:: c
@@ -940,6 +968,9 @@ within the
struct TALER_AmountNBO refund_fee;
};
+.. _TALER_MerchantRefundConfirmationPS:
+.. sourcecode:: c
+
struct TALER_MerchantRefundConfirmationPS {
/**
* purpose.purpose = TALER_SIGNATURE_MERCHANT_REFUND_OK
@@ -969,7 +1000,6 @@ within the
.. sourcecode:: c
struct TALER_RecoupRefreshConfirmationPS {
-
/**
* purpose.purpose = TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP_REFRESH
*/
@@ -985,7 +1015,7 @@ within the
struct TALER_RecoupConfirmationPS {
/**
- * purpose.purpose = TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP
+ * purpose.purpose = TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
struct GNUNET_TIME_AbsoluteNBO timestamp;
@@ -995,6 +1025,33 @@ within the
};
+.. _TALER_DenominationUnknownAffirmationPS:
+.. sourcecode:: c
+
+ struct TALER_DenominationUnknownAffirmationPS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_UNKNOWN
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct GNUNET_TIME_AbsoluteNBO timestamp;
+ struct GNUNET_HashCode h_denom_pub;
+ };
+
+
+.. _TALER_DenominationExpiredAffirmationPS:
+.. sourcecode:: c
+
+ struct TALER_DenominationExpiredAffirmationPS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_EXCHANGE_GENERIC_DENOMINATIN_EXPIRED
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct GNUNET_TIME_AbsoluteNBO timestamp;
+ char operation[8];
+ struct GNUNET_HashCode h_denom_pub;
+ };
+
+
.. _TALER_ReserveCloseConfirmationPS:
.. sourcecode:: c
@@ -1022,3 +1079,368 @@ within the
struct TALER_TransferPublicKeyP transfer_pub;
struct GNUNET_HashCode coin_envelope_hash;
};
+
+
+
+
+.. _TALER_ReserveStatusRequestSignaturePS:
+.. sourcecode:: c
+
+ struct TALER_ReserveStatusRequestSignaturePS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_RESERVE_STATUS_REQUEST
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct GNUNET_TIME_AbsoluteNBO request_timestamp;
+ };
+
+
+.. _TALER_ReserveHistoryRequestSignaturePS:
+.. sourcecode:: c
+
+ struct TALER_ReserveHistoryRequestSignaturePS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_RESERVE_HISTORY_REQUEST
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct TALER_AmountNBO history_fee;
+ struct GNUNET_TIME_AbsoluteNBO request_timestamp;
+ };
+
+
+.. _TALER_PurseStatusRequestSignaturePS:
+.. sourcecode:: c
+
+ struct TALER_PurseStatusRequestSignaturePS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_PURSE_STATUS_REQUEST
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ };
+
+
+.. _TALER_PurseStatusResponseSignaturePS:
+.. sourcecode:: c
+
+ struct TALER_PurseStatusResponseSignaturePS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_PURSE_STATUS_RESPONSE
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct TALER_AmountNBO total_purse_amount;
+ struct TALER_AmountNBO total_deposit_amount;
+ struct TALER_AmountNBO max_deposit_fees;
+ struct GNUNET_TIME_AbsoluteNBO purse_expiration;
+ struct GNUNET_TIME_AbsoluteNBO status_timestamp;
+ struct GNUNET_HashCode h_contract_terms;
+ };
+
+
+.. _TALER_ReserveCloseRequestSignaturePS:
+.. sourcecode:: c
+
+ struct TALER_ReserveCloseRequestSignaturePS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_RESERVE_CLOSE
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ };
+
+.. _TALER_RefreshCommitmentP:
+.. sourcecode:: c
+
+ struct TALER_RefreshCommitmentP {
+ struct GNUNET_HashCode session_hash;
+ };
+
+
+.. _TALER_PurseRequestSignaturePS:
+.. sourcecode:: c
+
+ struct TALER_PurseRequestSignaturePS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_PURSE_REQUEST
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct GNUNET_TIME_AbsoluteNBO purse_expiration;
+ struct TALER_AmountNBO merge_value_after_fees;
+ struct GNUNET_HashCode h_contract_terms;
+ };
+
+
+.. _TALER_PurseDepositSignaturePS:
+.. sourcecode:: c
+
+ struct TALER_PurseDepositSignaturePS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_PURSE_DEPOSIT
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct TALER_AmountNBO coin_contribution;
+ struct GNUNET_TIME_AbsoluteNBO purse_expiration;
+ struct TALER_PursePublicKey purse_pub;
+ struct GNUNET_HashCode h_contract_terms;
+ };
+
+
+.. _TALER_PurseDepositConfirmedSignaturePS:
+.. sourcecode:: c
+
+ struct TALER_PurseDepositConfirmedSignaturePS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_PURSE_DEPOSIT_CONFIRMED
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct TALER_AmountNBO total_purse_amount;
+ struct TALER_AmountNBO total_deposit_fees;
+ struct TALER_PursePublicKey purse_pub;
+ struct GNUNET_TIME_AbsoluteNBO purse_expiration;
+ struct GNUNET_HashCode h_contract_terms;
+ };
+
+.. _TALER_PurseMergeSignaturePS:
+.. sourcecode:: c
+
+ struct TALER_PurseMergeSignaturePS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_PURSE_MERGE
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct TALER_ReservePublicKey reserve_pub;
+ struct GNUNET_TIME_AbsoluteNBO merge_timestamp;
+ struct GNUNET_TIME_AbsoluteNBO purse_expiration;
+ struct TALER_AmountNBO merge_value_after_fees;
+ struct GNUNET_HashCode h_contract_terms;
+ struct GNUNET_HashCode h_wire;
+ };
+
+
+.. _TALER_AccountMergeSignaturePS:
+.. sourcecode:: c
+
+ struct TALER_AccountMergeSignaturePS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_ACCOUNT_MERGE
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct TALER_PursePublicKey purse_pub;
+ struct GNUNET_TIME_AbsoluteNBO merge_timestamp;
+ struct GNUNET_TIME_AbsoluteNBO purse_expiration;
+ struct TALER_AmountNBO merge_value_after_fees;
+ struct GNUNET_HashCode h_contract_terms;
+ struct GNUNET_HashCode h_wire;
+ };
+
+
+.. _TALER_PurseMergeSuccessSignaturePS:
+.. sourcecode:: c
+
+ struct TALER_PurseMergeSuccessSignaturePS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_PURSE_MERGE_SUCCESS
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct TALER_ReservePublicKey reserve_pub;
+ struct TALER_PursePublicKey purse_pub;
+ struct TALER_AmountNBO merge_amount_after_fees;
+ struct GNUNET_TIME_AbsoluteNBO contract_time;
+ struct GNUNET_HashCode h_contract_terms;
+ struct GNUNET_HashCode h_wire;
+ };
+
+
+.. _TALER_AccountSetupRequestSignaturePS:
+.. sourcecode:: c
+
+ struct TALER_AccountSetupRequestSignaturePS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_ACCOUNT_SETUP_REQUEST
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct GNUNET_TIME_AbsoluteNBO kyc_timestamp;
+ struct TALER_AmountNBO kyc_fee;
+ struct GNUNET_HashCode h_wire;
+ };
+
+
+.. _TALER_AccountSetupSuccessSignaturePS:
+.. sourcecode:: c
+
+ struct TALER_AccountSetupRequestSignaturePS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_ACCOUNT_SETUP_SUCCESS
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct TALER_ReservePublicKey reserve_pub;
+ struct GNUNET_TIME_AbsoluteNBO now;
+ };
+
+
+.. _TALER_WadDataSignaturePS:
+.. sourcecode:: c
+
+ struct TALER_WadDataSignaturePS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_WAD_DATA
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct GNUNET_TIME_AbsoluteNBO wad_execution_time;
+ struct TALER_AmountNBO total_amount;
+ struct GNUNET_HashCode h_items;
+ struct TALER_WadId wad_id;
+ };
+
+.. _TALER_WadPartnerSignaturePS:
+.. sourcecode:: c
+
+ struct TALER_WadPartnerSignaturePS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_MASTER_PARTNER_DETAILS
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct GNUNET_HashCode h_partner_base_url;
+ struct TALER_MasterPublicKeyP master_public_key;
+ struct GNUNET_TIME_AbsoluteNBO start_date;
+ struct GNUNET_TIME_AbsoluteNBO end_date;
+ struct TALER_AmountNBO wad_fee;
+ struct GNUNET_TIME_RelativeNBO wad_frequency;
+ };
+
+
+.. _TALER_P2PFeesPS:
+.. sourcecode:: c
+
+ struct TALER_P2PFeesPS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_P2P_FEES
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct GNUNET_TIME_AbsoluteNBO start_date;
+ struct GNUNET_TIME_AbsoluteNBO end_date;
+ struct TALER_AmountNBO kyc_fee;
+ struct TALER_AmountNBO purse_fee;
+ struct TALER_AmountNBO account_history_fee;
+ struct TALER_AmountNBO account_annual_fee;
+ struct GNUNET_TIME_RelativeNBO account_kyc_timeout;
+ struct GNUNET_TIME_RelativeNBO purse_timeout;
+ uint32_t purse_account_limit;
+ };
+
+
+.. _TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_REFUND:
+.. sourcecode:: c
+
+ struct TALER_CoinPurseRefundConfirmationPS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_REFUND.
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct TALER_PursePublicKey purse_pub;
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+ struct TALER_MerchantPublicKeyP merchant;
+ struct TALER_AmountNBO remaining_amount;
+ struct TALER_AmountNBO purse_fee_share;
+ struct TALER_AmountNBO refund_fee;
+ };
+
+
+.. _TALER_DenominationKeyAnnouncementPS:
+.. sourcecode:: c
+
+ struct TALER_DenominationKeyAnnouncementPS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_SM_DENOMINATION_KEY
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct GNUNET_HashCode h_denom_pub;
+ struct GNUNET_HashCode h_section_name;
+ struct GNUNET_TIME_AbsoluteNBO anchor_time;
+ struct GNUNET_TIME_RelativeNBO duration_withdraw;
+ };
+
+
+.. _TALER_SigningKeyAnnouncementPS:
+.. sourcecode:: c
+
+ struct TALER_SigningKeyAnnouncementPS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_SM_SIGNING_KEY .
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct TALER_ExchangePublicKeyP exchange_pub;
+ struct GNUNET_TIME_AbsoluteNBO anchor_time;
+ struct GNUNET_TIME_RelativeNBO duration;
+ };
+
+.. _TALER_MasterDenominationKeyRevocationPS:
+.. sourcecode:: c
+
+ struct TALER_MasterDenominationKeyRevocationPS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED.
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct GNUNET_HashCode h_denom_pub;
+ };
+
+
+.. _TALER_MasterSigningKeyRevocationPS:
+.. sourcecode:: c
+
+ struct TALER_MasterSigningKeyRevocationPS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_MASTER_SIGNING_KEY_REVOKED.
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct TALER_ExchangePublicKeyP exchange_pub;
+ };
+
+
+.. _TALER_MasterAddAuditorPS:
+.. sourcecode:: c
+
+ struct TALER_MasterAddAuditorPS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_MASTER_ADD_AUDITOR
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct GNUNET_TIME_AbsoluteNBO start_date;
+ struct TALER_AuditorPublicKeyP auditor_pub;
+ struct GNUNET_HashCode h_auditor_url;
+ };
+
+.. _TALER_MasterDelAuditorPS:
+.. sourcecode:: c
+
+ struct TALER_MasterDelAuditorPS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_MASTER_DEL_AUDITOR
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct GNUNET_TIME_AbsoluteNBO end_date;
+ struct TALER_AuditorPublicKeyP auditor_pub;
+ };
+
+.. _TALER_MasterAddWirePS:
+.. sourcecode:: c
+
+ struct TALER_MasterAddWirePS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_MASTER_ADD_WIRE.
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct GNUNET_TIME_AbsoluteNBO start_date;
+ struct GNUNET_HashCode h_wire GNUNET_PACKED;
+ };
+
+.. _TALER_MasterDelWirePS:
+.. sourcecode:: c
+
+ struct TALER_MasterDelWirePS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_MASTER_DEL_WIRE.
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct GNUNET_TIME_AbsoluteNBO end_date;
+ struct GNUNET_HashCode h_wire GNUNET_PACKED;
+ };
diff --git a/core/api-exchange.rst b/core/api-exchange.rst
index 1e9db1d9..ce482837 100644
--- a/core/api-exchange.rst
+++ b/core/api-exchange.rst
@@ -127,8 +127,8 @@ possibly by using HTTPS.
// in ``denoms`` and ``signkeys``.
master_public_key: EddsaPublicKey;
- // Relative duration until inactive reserves are closed; not signed, expressed as
- // a string in relative time in microseconds, i.e. "/Delay(1000)/" for 1 second.
+ // Relative duration until inactive reserves are closed;
+ // not signed (!), can change without notice.
reserve_closing_delay: RelativeTime;
// Denominations offered by this exchange.
@@ -137,6 +137,11 @@ possibly by using HTTPS.
// Denominations for which the exchange currently offers/requests recoup.
recoup: Recoup[];
+ // Fees relevant for wallet-to-wallet (or peer-to-peer) payments.
+ // If no fees are provided for a given time range, then the
+ // exchange simply does not support purses/p2p-payments at that time.
+ p2p_fees: P2PFees[];
+
// The date when the denomination keys were last updated.
list_issue_date: Timestamp;
@@ -155,6 +160,7 @@ possibly by using HTTPS.
// is sabotaging end-user anonymity by giving disjoint denomination keys to
// different users. If an exchange were to do this, this signature allows the
// clients to demonstrate to the public that the exchange is dishonest.
+ // Signature of `TALER_ExchangeKeySetPS`
eddsa_sig: EddsaSignature;
// Public EdDSA key of the exchange that was used to generate the signature.
@@ -164,6 +170,66 @@ possibly by using HTTPS.
eddsa_pub: EddsaPublicKey;
}
+ .. ts:def:: P2PFees
+
+ interface P2PFees {
+
+ // What date (inclusive) does these fees go into effect?
+ start_date: Timestamp;
+
+ // What date (exclusive) does this fees stop going into effect?
+ end_date: Timestamp;
+
+ // KYC fee, charged when a user wants to create an account.
+ // The first year of the account_annual_fee after the KYC is
+ // always included.
+ kyc_fee: Amount;
+
+ // Account history fee, charged when a user wants to
+ // obtain the full account history, and not just the
+ // recent transactions in an account.
+ account_history_fee: Amount;
+
+ // Annual fee charged for having an open account at the
+ // exchange. Charged to the account. If the account
+ // balance is insufficient to cover this fee, the account
+ // is automatically deleted/closed. (Note that the exchange
+ // will keep the account history around for longer for
+ // regulatory reasons.)
+ account_annual_fee: Amount;
+
+ // How long will the exchange preserve the account history?
+ // After an account was deleted/closed, the exchange will
+ // retain the account history for legal reasons until this time.
+ legal_history_retention: RelativeTime;
+
+ // How long does the exchange promise to keep funds
+ // an account for which the KYC has never happened
+ // after a purse was merged into an account? Basically,
+ // after this time funds in an account without KYC are
+ // forfeit.
+ account_kyc_timeout: RelativeTime;
+
+ // Purse fee, charged only if a purse is abandoned
+ // and was not covered by the account limit.
+ purse_fee: Amount;
+
+ // Non-negative number of concurrent purses that any
+ // account holder is allowed to create without having
+ // to pay the purse_fee.
+ purse_account_limit: Integer;
+
+ // How long does an exchange keep a purse around after a purse
+ // has expired (or been successfully merged)? A 'GET' request
+ // for a purse will succeed until the purse expiration time
+ // plus this value.
+ purse_timeout: RelativeTime;
+
+ // Signature of `TALER_P2PFeesPS`.
+ master_sig: EddsaSignature;
+
+ }
+
.. ts:def:: Denom
interface Denom {
@@ -241,6 +307,7 @@ possibly by using HTTPS.
stamp_end: Timestamp;
// Signature over ``key`` and ``stamp_expire`` by the exchange master key.
+ // Signature of `TALER_ExchangeSigningKeyValidityPS`.
// Must have purpose ``TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY``.
master_sig: EddsaSignature;
}
@@ -317,6 +384,10 @@ possibly by using HTTPS.
// Object mapping names of wire methods (i.e. "sepa" or "x-taler-bank")
// to wire fees.
fees: { method : AggregateTransferFee };
+
+ // List of exchanges that this exchange is partnering
+ // with to enable wallet-to-wallet transfers.
+ wads: ExchangePartner[];
}
The specification for the account object is:
@@ -327,7 +398,8 @@ possibly by using HTTPS.
// ``payto://`` URI identifying the account and wire method
payto_uri: string;
- // Signature using the exchange's offline key
+ // Signature using the exchange's offline key over
+ // a `TALER_MasterWireDetailsPS`
// with purpose ``TALER_SIGNATURE_MASTER_WIRE_DETAILS``.
master_sig: EddsaSignature;
}
@@ -361,6 +433,35 @@ possibly by using HTTPS.
sig: EddsaSignature;
}
+ .. ts:def:: ExchangePartner
+
+ interface ExchangePartner {
+ // Base URL of the partner exchange.
+ partner_base_url: string;
+
+ // Public master key of the partner exchange.
+ partner_master_pub: EddsaPublicKey;
+
+ // Wallet-to-wallet transfer wad fee charged.
+ wad_fee: Amount;
+
+ // Exchange-to-exchange wad (wire) transfer frequency.
+ wad_frequency: RelativeTime;
+
+ // When did this partnership begin (under these conditions)?
+ start_date: Timestamp;
+
+ // How long is this partnership expected to last?
+ end_date: Timestamp;
+
+ // Signature using the exchange's offline key over
+ // `TALER_WadPartnerSignaturePS`
+ // with purpose ``TALER_SIGNATURE_MASTER_PARTNER_DETAILS``.
+ master_sig: EddsaSignature;
+ }
+
+
+
----------------------------------------------
Management operations authorized by master key
@@ -443,7 +544,10 @@ Management operations authorized by master key
// Fee charged by the exchange for refunding a coin of this denomination.
fee_refund: Amount;
- // Signature over this denomination by the denomination security module.
+ // Signature by the denomination security module
+ // over `TALER_DenominationKeyAnnouncementPS`
+ // for this denomination with purpose
+ // ``TALER_SIGNATURE_SM_DENOMINATION_KEY``.
denom_secmod_sig: EddsaSignature;
}
@@ -465,7 +569,9 @@ Management operations authorized by master key
// henceforth no longer be considered valid in legal disputes.
stamp_end: Timestamp;
- // Signature over this signing key by the signkey security module.
+ // Signature over `TALER_SigningKeyAnnouncementPS`
+ // for this signing key by the signkey security
+ // module using purpose ``TALER_SIGNATURE_SM_SIGNING_KEY``.
signkey_secmod_sig: EddsaSignature;
}
@@ -508,7 +614,8 @@ Management operations authorized by master key
// Hash of the public (RSA) key of the denomination.
h_denom_pub: HashCode;
- // Signature of `TALER_DenominationKeyValidityPS`.
+ // Signature over `TALER_DenominationKeyValidityPS`.
+ // Must have purpose ``TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY``
master_sig: EddsaSignature;
}
@@ -519,7 +626,8 @@ Management operations authorized by master key
// The actual exchange's EdDSA signing public key.
key: EddsaPublicKey;
- // Signature by the exchange master key.
+ // Signature by the exchange master key over
+ // `TALER_ExchangeSigningKeyValidityPS`.
// Must have purpose ``TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY``.
master_sig: EddsaSignature;
@@ -547,7 +655,8 @@ Management operations authorized by master key
interface DenomRevocationSignature {
- // Signature by the exchange master key.
+ // Signature by the exchange master key over a
+ // `TALER_MasterDenominationKeyRevocationPS`.
// Must have purpose ``TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED``.
master_sig: EddsaSignature;
@@ -574,7 +683,8 @@ Management operations authorized by master key
interface SignkeyRevocationSignature {
- // Signature by the exchange master key.
+ // Signature by the exchange master key over a
+ // `TALER_MasterSigningKeyRevocationPS`.
// Must have purpose ``TALER_SIGNATURE_MASTER_SIGN_KEY_REVOKED``.
master_sig: EddsaSignature;
@@ -613,8 +723,9 @@ Management operations authorized by master key
// The auditor's EdDSA signing public key.
auditor_pub: EddsaPublicKey;
- // Signature by the exchange master key.
- // Must have purpose ``TALER_SIGNATURE_MASTER_AUDITOR_ADD``.
+ // Signature by the exchange master ke yover a
+ // `TALER_MasterAddAuditorPS`.
+ // Must have purpose ``TALER_SIGNATURE_MASTER_ADD_AUDITOR``.
master_sig: EddsaSignature;
// When does the auditor become active?
@@ -657,7 +768,8 @@ Management operations authorized by master key
interface AuditorTeardownMessage {
- // Signature by the exchange master key.
+ // Signature by the exchange master key over a
+ // `TALER_MasterDelAuditorPS`.
// Must have purpose ``TALER_SIGNATURE_MASTER_AUDITOR_DEL``.
master_sig: EddsaSignature;
@@ -747,10 +859,12 @@ Management operations authorized by master key
payto_uri: string;
// Signature using the exchange's offline key
+ // over a `TALER_MasterWireDetailsPS`
// with purpose ``TALER_SIGNATURE_MASTER_WIRE_DETAILS``.
master_sig_wire: EddsaSignature;
- // Signature using the exchange's offline key
+ // Signature using the exchange's offline key over a
+ // `TALER_MasterAddWirePS`
// with purpose ``TALER_SIGNATURE_MASTER_WIRE_ADD``.
master_sig_add: EddsaSignature;
@@ -797,7 +911,8 @@ Management operations authorized by master key
// ``payto://`` URL identifying the account and wire method
payto_uri: string;
- // Signature using the exchange's offline key
+ // Signature using the exchange's offline key over a
+ // `TALER_MasterDelWirePS`.
// with purpose ``TALER_SIGNATURE_MASTER_WIRE_DEL``.
master_sig_del: EddsaSignature;
@@ -811,6 +926,44 @@ Management operations authorized by master key
}
+.. http:post:: /management/p2pfees
+
+ Provides fee configuration for purses.
+
+ **Request:**
+
+ The request must be a `P2PFees` message.
+
+ **Response**
+
+ :http:statuscode:`204 No content`:
+ The configuration update has been processed successfully. The body is empty.
+ :http:statuscode:`403 Forbidden`:
+ The signature is invalid.
+ :http:statuscode:`409 Conflict`:
+ The exchange has previously received a conflicting configuration message or the currency does not match.
+
+
+.. http:post:: /management/partners
+
+ Enables a partner exchange for wad transfers.
+
+ **Request:**
+
+ The request must be an `ExchangePartner` message.
+
+ **Response**
+
+ :http:statuscode:`204 No content`:
+ The partner has been added successfully.
+ :http:statuscode:`403 Forbidden`:
+ The signature is invalid.
+ :http:statuscode:`409 Conflict`:
+ The exchange has previously received a conflicting configuration message or the currency does not match.
+
+
+
+
---------------
Auditor actions
---------------
@@ -840,6 +993,7 @@ This part of the API is for the use by auditors interacting with the exchange.
The auditor signature is invalid.
:http:statuscode:`404 Not found`:
The denomination key for which the auditor is providing a signature is unknown.
+ The response will be a `DenominationUnkownMessage`.
:http:statuscode:`410 Gone`:
This auditor is no longer supported by the exchange.
:http:statuscode:`412 Precondition failed`:
@@ -847,12 +1001,37 @@ This part of the API is for the use by auditors interacting with the exchange.
**Details:**
+ .. ts:def:: DenominationUnknownMessage
+
+ interface DenominationUnknownMessage {
+
+ // Taler error code.
+ code: number;
+
+ // Signature by the exchange over a
+ // `TALER_DenominationUnknownAffirmationPS`.
+ // Must have purpose ``TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_UNKNOWN``.
+ exchange_sig: EddsaSignature;
+
+ // Public key of the exchange used to create
+ // the 'exchange_sig.
+ exchange_pub: EddsaPublicKey;
+
+ // Hash of the denomination public key that is unknown.
+ h_denom_pub: HashCode;
+
+ // When was the signature created.
+ timestamp: Timestamp;
+
+ }
+
.. ts:def:: AuditorSignatureAddMessage
interface AuditorSignatureAddMessage {
- // Signature by the auditor.
- // Must have purpose ``TALER_SIGNATURE_AUDITOR_XXX``.
+ // Signature by the auditor over a
+ // `TALER_ExchangeKeyValidityPS`.
+ // Must have purpose ``TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS``.
auditor_sig: EddsaSignature;
}
@@ -879,37 +1058,66 @@ exchange.
advertise those terms of service.
-.. http:get:: /reserves/$RESERVE_PUB
+.. http:post:: /reserves/$RESERVE_PUB/status
- Request information about a reserve.
-
- .. note::
- The client currently does not have to demonstrate knowledge of the private
- key of the reserve to make this request, which makes the reserve's public
- key privileged information known only to the client, their bank, and the
- exchange. In the future, we might wish to revisit this decision to improve
- security, such as by having the client EdDSA-sign an ECDHE key to be used
- to derive a symmetric key to encrypt the response. This would be useful if
- for example HTTPS were not used for communication with the exchange.
+ Request information about a reserve or an account.
**Request:**
+ :query history=BOOLEAN: *Optional.* If specified, the exchange
+ will return the recent account history.
+ This is still free of charge.
+ :query full_history=BOOLEAN: *Optional.* If 'true' is specified,
+ the exchange will return the full account history. This
+ may incur a fee that will be charged to the account.
+
+ The request body must be a `ReserveStatusRequest` object.
+
**Response:**
:http:statuscode:`200 OK`:
The exchange responds with a `ReserveStatus` object; the reserve was known to the exchange.
+ :http:statuscode:`401 Unauthorized`:
+ The *Account-Request-Signature* is invalid.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`403 Forbidden`:
+ The provided timestamp is not close to the current time.
:http:statuscode:`404 Not found`:
The reserve key does not belong to a reserve known to the exchange.
**Details:**
+ .. ts:def:: ReserveStatusRequest
+
+ interface ReserveStatusRequest {
+ // Signature of purpose
+ // ``TALER_SIGNATURE_RESERVE_STATUS_REQUEST`` over
+ // a `TALER_ReserveStatusRequestSignaturePS`.
+ reserve_sig: EddsaSignature;
+
+ // Time when the client made the request.
+ // Timestamp must be reasonably close to the time of
+ // the exchange, otherwise the exchange may reject
+ // the request.
+ request_timestamp: Timestamp;
+ }
+
.. ts:def:: ReserveStatus
interface ReserveStatus {
// Balance left in the reserve.
balance: Amount;
+ // True if the owner of the account currently satisfies
+ // the required KYC checks.
+ kyc_passed: boolean;
+
+ // True if the reserve history includes a merge of a purse
+ // and thus the owner must pass KYC checks before withdrawing.
+ kyc_required: boolean;
+
// Transaction history for this reserve.
+ // May be partial (!).
history: TransactionHistoryItem[];
}
@@ -918,12 +1126,99 @@ exchange.
.. ts:def:: TransactionHistoryItem
// Union discriminated by the "type" field.
- type ReserveTransaction =
+ type TransactionHistoryItem =
+ | AccountMergeTransaction
+ | AccountSetupTransaction
+ | ReserveHistoryTransaction
| ReserveWithdrawTransaction
| ReserveCreditTransaction
| ReserveClosingTransaction
| ReserveRecoupTransaction;
+ .. ts:def:: ReserveHistoryTransaction
+
+ interface ReserveHistoryTransaction {
+ type: "HISTORY";
+
+ // Fee agreed to by the reserve owner.
+ history_fee: Amount;
+
+ // Time when the request was made.
+ request_timestamp: Timestamp;
+
+ // Signature created with the reserve's private key.
+ // Must be of purpose ``TALER_SIGNATURE_RESERVE_HISTORY_REQUEST`` over
+ // a `TALER_ReserveHistoryRequestSignaturePS`.
+ reserve_sig: EddsaSignature;
+
+ }
+
+ .. ts:def:: AccountSetupTransaction
+
+ interface AccountSetupTransaction {
+ type: "SETUP";
+
+ // KYC fee agreed to by the reserve owner.
+ kyc_fee: Amount;
+
+ // Time when the KYC was triggered.
+ kyc_timestamp: Timestamp;
+
+ // Hash of the wire details of the account.
+ // Note that this hash is unsalted and potentially
+ // private (as it could be inverted), hence access
+ // to this endpoint must be authorized using the
+ // private key of the reserve.
+ h_wire: HashCode;
+
+ // Signature created with the reserve's private key.
+ // Must be of purpose ``TALER_SIGNATURE_ACCOUNT_SETUP_REQUEST`` over
+ // a `TALER_AccountSetupRequestSignaturePS`.
+ reserve_sig: EddsaSignature;
+
+ }
+
+ .. ts:def:: AccountMergeTransaction
+
+ interface AccountMergeTransaction {
+ type: "MERGE";
+
+ // Actual amount merged (what was left after fees).
+ amount: Amount;
+
+ // Minimum amount merged (amount signed by the
+ // reserve and purse signatures).
+ minimum_amount: Amount;
+
+ // Purse that was merged.
+ purse_pub: EddsaPublicKey;
+
+ // Time of the merge.
+ merge_timestamp: Timestamp;
+
+ // Expiration time of the purse.
+ purse_expiration: Timestamp;
+
+ // Hash of the contract.
+ h_contract: HashCode;
+
+ // Hash of the wire details of the reserve.
+ h_wire: HashCode;
+
+ // Signature created with the reserve's private key.
+ // Must be of purpose ``TALER_SIGNATURE_ACCOUNT_MERGE`` over
+ // a `TALER_AccountMergeSignaturePS`.
+ reserve_sig: EddsaSignature;
+
+ // Signature created with the purse's private key.
+ // Must be of purpose ``TALER_SIGNATURE_PURSE_MERGE``
+ // over a `TALER_PurseMergeSignaturePS`.
+ purse_sig: EddsaSignature;
+
+ // Deposit fees that were charged to the purse.
+ deposit_fees: Amount;
+ }
+
.. ts:def:: ReserveWithdrawTransaction
interface ReserveWithdrawTransaction {
@@ -938,8 +1233,9 @@ exchange.
// Hash of the blinded coin to be signed.
h_coin_envelope: HashCode;
- // Signature of ``TALER_WithdrawRequestPS`` created with the reserve's
- // private key.
+ // Signature over a `TALER_WithdrawRequestPS`
+ // with purpose ``TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW``
+ // created with the reserve's private key.
reserve_sig: EddsaSignature;
// Fee that is charged for withdraw.
@@ -985,11 +1281,11 @@ exchange.
receiver_account_details: string;
// This is a signature over a
- // struct ``TALER_ReserveCloseConfirmationPS`` with purpose
+ // struct `TALER_ReserveCloseConfirmationPS` with purpose
// ``TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED``.
exchange_sig: EddsaSignature;
- // Public key used to create ``exchange_sig``.
+ // Public key used to create 'exchange_sig'.
exchange_pub: EddsaPublicKey;
// Time when the reserve was closed.
@@ -1006,11 +1302,11 @@ exchange.
amount: Amount;
// This is a signature over
- // a struct ``TALER_PaybackConfirmationPS`` with purpose
- // ``TALER_SIGNATURE_EXCHANGE_CONFIRM_PAYBACK``.
+ // a struct `TALER_RecoupConfirmationPS` with purpose
+ // ``TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP``.
exchange_sig: EddsaSignature;
- // Public key used to create ``exchange_sig``.
+ // Public key used to create 'exchange_sig'.
exchange_pub: EddsaPublicKey;
// Time when the funds were paid back into the reserve.
@@ -1020,6 +1316,49 @@ exchange.
coin_pub: CoinPublicKey;
}
+
+.. http:post:: /reserves/$RESERVE_PUB/history
+
+ Request information about the full history of
+ a reserve or an account.
+
+ **Request:**
+
+ The request body must be a `ReserveHistoryRequest` object.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The exchange responds with a `ReserveStatus` object; the reserve was known to the exchange.
+ :http:statuscode:`401 Unauthorized`:
+ The *Account-Request-Signature* is invalid.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`403 Forbidden`:
+ The provided timestamp is not close to the current time.
+ :http:statuscode:`404 Not found`:
+ The reserve key does not belong to a reserve known to the exchange.
+ :http:statuscode:`412 Precondition failed`:
+ The balance in the reserve is insufficient to pay for the history request.
+ This response comes with a standard `ErrorDetail` response.
+
+ **Details:**
+
+ .. ts:def:: ReserveHistoryRequest
+
+ interface ReserveHistoryRequest {
+ // Signature of type
+ // ``TALER_SIGNATURE_RESERVE_HISTORY_REQUEST``
+ // over a `TALER_ReserveHistoryRequestSignaturePS`.
+ reserve_sig: EddsaSignature;
+
+ // Time when the client made the request.
+ // Timestamp must be reasonably close to the time of
+ // the exchange, otherwise the exchange may reject
+ // the request.
+ request_timestamp: Timestamp;
+ }
+
+
.. http:post:: /reserves/$RESERVE_PUB/withdraw
Withdraw a coin of the specified denomination. Note that the client should
@@ -1037,13 +1376,23 @@ exchange.
will again yield the same response, so if the network goes down during the
transaction or before the client can commit the coin signature to disk, the
coin is not lost.
+ :http:statuscode:`202 Accepted`:
+ This reserve has received funds from a purse and must
+ be upgraded to an account (with KYC) before the withdraw can
+ complete. Note that this response does NOT affirm that the
+ withdraw will ultimately complete with the requested amount.
+ The user should be redirected to the provided location to perform
+ the required KYC checks to open the account before withdrawing.
+ Afterwards, the request should be repeated.
+ The response will be an `AccountKycRedirect` object.
:http:statuscode:`403 Forbidden`:
The signature is invalid.
:http:statuscode:`404 Not found`:
The denomination key or the reserve are not known to the exchange. If the
denomination key is unknown, this suggests a bug in the wallet as the
- wallet should have used current denomination keys from ``/keys``. If the
- reserve is unknown, the wallet should not report a hard error yet, but
+ wallet should have used current denomination keys from ``/keys``.
+ In this case, the response will be a `DenominationUnkownMessage`.
+ If the reserve is unknown, the wallet should not report a hard error yet, but
instead simply wait for up to a day, as the wire transaction might simply
not yet have completed and might be known to the exchange in the near future.
In this case, the wallet should repeat the exact same request later again
@@ -1052,12 +1401,45 @@ exchange.
The balance of the reserve is not sufficient to withdraw a coin of the indicated denomination.
The response is `WithdrawError` object.
:http:statuscode:`410 Gone`:
- The requested denomination key is no longer valid. It either expired or was revoked.
- :http:statuscode:`412 Precondition failed`:
- The requested denomination key is not yet valid. It is too early to withdraw.
+ The requested denomination key is not yet or no longer valid.
+ It either before the validity start, past the expiration or was revoked. The response is a
+ `DenominationExpiredMessage`. Clients must evaluate
+ the error code provided to understand which of the
+ cases this is and handle it accordingly.
**Details:**
+ .. ts:def:: DenominationExpiredMessage
+
+ interface DenominationExpiredMessage {
+
+ // Taler error code. Note that beyond
+ // expiration this message format is also
+ // used if the key is not yet valid, or
+ // has been revoked.
+ code: number;
+
+ // Signature by the exchange over a
+ // `TALER_DenominationExpiredAffirmationPS`.
+ // Must have purpose ``TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_EXPIRED``.
+ exchange_sig: EddsaSignature;
+
+ // Public key of the exchange used to create
+ // the 'exchange_sig.
+ exchange_pub: EddsaPublicKey;
+
+ // Hash of the denomination public key that is unknown.
+ h_denom_pub: HashCode;
+
+ // When was the signature created.
+ timestamp: Timestamp;
+
+ // What kind of operation was requested that now
+ // failed?
+ oper: String;
+ }
+
+
.. ts:def:: WithdrawRequest
interface WithdrawRequest {
@@ -1070,16 +1452,16 @@ exchange.
coin_ev: CoinEnvelope;
// Signature of `TALER_WithdrawRequestPS` created with
- // the `reserves's private key <reserve-priv>`.
+ // the `reserves's private key <reserve-priv>`
+ // using purpose ``TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW``.
reserve_sig: EddsaSignature;
}
-
.. ts:def:: WithdrawResponse
interface WithdrawResponse {
- // The blinded RSA signature over the ``coin_ev``, affirms the coin's
+ // The blinded RSA signature over the 'coin_ev', affirms the coin's
// validity after unblinding.
ev_sig: BlindedRsaSignature;
@@ -1102,6 +1484,64 @@ exchange.
history: TransactionHistoryItem[]
}
+.. _delete-reserve:
+
+.. http:DELETE:: /reserves/$RESERVE_PUB
+
+ Forcefully closes a reserve.
+ The request header must contain an *Account-Request-Signature*.
+
+ **Request:**
+
+ *Account-Request-Signature*: The client must provide Base-32 encoded EdDSA signature made with ``$ACCOUNT_PRIV``, affirming its authorization to delete the account. The purpose used MUST be ``TALER_SIGNATURE_RESERVE_CLOSE``.
+
+ :query force=BOOLEAN: *Optional.* If set to 'true' specified, the exchange
+ will delete the account even if there is a balance remaining.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The operation succeeded, the exchange provides details
+ about the account deletion.
+ The response will include a `ReserveClosedResponse` object.
+ :http:statuscode:`401 Unauthorized`:
+ The *Account-Request-Signature* is invalid.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`404 Not found`:
+ The account is unknown to the exchange.
+ :http:statuscode:`409 Conflict`:
+ The account is still has digital cash in it, the associated
+ wire method is ``void`` and the *force* option was not provided.
+ This response comes with a standard `ErrorDetail` response.
+
+ **Details:**
+
+ .. ts:def:: ReserveClosedResponse
+
+ interface ReserveClosedResponse {
+
+ // Final balance of the account.
+ closing_amount: Amount;
+
+ // Current time of the exchange, used as part of
+ // what the exchange signs over.
+ close_time: Timestamp;
+
+ // Hash of the wire account into which the remaining
+ // balance will be transferred. Note: may be the
+ // hash over ``payto://void/`, in which case the
+ // balance is forfeit to the profit of the exchange.
+ h_wire: HashCode;
+
+ // This is a signature over a
+ // struct ``TALER_AccountDeleteConfirmationPS`` with purpose
+ // ``TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED``.
+ exchange_sig: EddsaSignature;
+
+ }
+
+
+
.. _deposit-par:
-------
@@ -1115,7 +1555,6 @@ credited an amount specified in the deposit permission, possibly a fraction of
the total coin's value, minus the deposit fee as specified by the coin's
denomination.
-
.. _deposit:
.. http:POST:: /coins/$COIN_PUB/deposit
@@ -1128,10 +1567,9 @@ denomination.
exchange. The exchange MUST return a 307 or 308 redirection to the correct
base URL if this is the case.
- The request should contain a JSON object with the
- following fields:
+ **Request:**
- **Request:** The request body must be a `DepositRequest` object.
+ The request body must be a `DepositRequest` object.
**Response:**
@@ -1141,8 +1579,10 @@ denomination.
:http:statuscode:`401 Unauthorized`:
One of the signatures is invalid.
:http:statuscode:`404 Not found`:
- Either the denomination key is not recognized (expired or invalid) or
- the wire type is not recognized.
+ Either the denomination key is not recognized (expired or invalid),
+ or the wire type is not recognized.
+ If the denomination key is unknown, the response will be
+ a `DenominationUnkownMessage`.
:http:statuscode:`409 Conflict`:
The deposit operation has either failed because the coin has insufficient
residual value, or because the same public key of the coin has been
@@ -1152,6 +1592,12 @@ denomination.
The fields of the response are the same in both cases.
The request should not be repeated again with this coin.
In this case, the response is a `DepositDoubleSpendError`.
+ :http:statuscode:`410 Gone`:
+ The requested denomination key is not yet or no longer valid.
+ It either before the validity start, past the expiration or was revoked. The response is a
+ `DenominationExpiredMessage`. Clients must evaluate
+ the error code provided to understand which of the
+ cases this is and handle it accordingly.
**Details:**
@@ -1199,7 +1645,7 @@ denomination.
// exchange, possibly zero if refunds are not allowed.
refund_deadline: Timestamp;
- // Signature of `TALER_DepositRequestPS`, made by the customer with the
+ // Signature over `TALER_DepositRequestPS`, made by the customer with the
// `coin's private key <coin-priv>`.
coin_sig: EddsaSignature;
}
@@ -1251,101 +1697,296 @@ denomination.
.. ts:def:: CoinSpendHistoryItem
- interface CoinSpendHistoryItem {
- // Either "DEPOSIT", "MELT", "REFUND", "RECOUP",
- // "OLD-COIN-RECOUP" or "RECOUP-REFRESH".
- type: string;
+ // Union discriminated by the "type" field.
+ type CoinSpendHistoryItem =
+ | CoinDepositTransaction
+ | CoinMeltTransaction
+ | CoinRefundTransaction
+ | CoinRecoupTransaction
+ | CoinOldCoinRecoupTransaction
+ | CoinRecoupRefreshTransaction
+ | CoinPurseDepositTransaction
+ | CoinPurseRefundTransaction;
+
+
+ .. ts:def:: CoinDepositTransaction
+
+ interface CoinDepositTransaction {
+ type: "DEPOSIT";
// The total amount of the coin's value absorbed (or restored in the
// case of a refund) by this transaction.
- // Note that for deposit and melt this means the amount given includes
- // the transaction fee, while for refunds the amount given excludes
- // the transaction fee. The current coin value can thus be computed by
- // subtracting deposit and melt amounts and adding refund amounts from
- // the coin's denomination value.
+ // The amount given includes
+ // the deposit fee. The current coin value can thus be computed by
+ // subtracting this amount.
amount: Amount;
- // Deposit fee in case of type "DEPOSIT".
+ // Deposit fee.
deposit_fee: Amount;
- // Public key of the merchant, for "DEPOSIT" operations.
- merchant_pub?: EddsaPublicKey;
+ // Public key of the merchant.
+ merchant_pub: EddsaPublicKey;
// Date when the operation was made.
- // Only for "DEPOSIT", "RECOUP", "OLD-COIN-RECOUP" and
- // "RECOUP-REFRESH" operations.
- timestamp?: Timestamp;
+ timestamp: Timestamp;
// Date until which the merchant can issue a refund to the customer via the
- // exchange, possibly zero if refunds are not allowed. Only for "DEPOSIT" operations.
- refund_deadline?: Timestamp;
+ // exchange, possibly zero if refunds are not allowed.
+ refund_deadline: Timestamp;
- // Signature by the coin, only present if ``type`` is "DEPOSIT", "MELT", "RECOUP",
- // or "RECOUP-REFRESH".
- coin_sig?: EddsaSignature;
+ // Signature over `TALER_DepositRequestPS`, made by the customer with the
+ // `coin's private key <coin-priv>`.
+ coin_sig: EddsaSignature;
- // Deposit fee in case of type "MELT".
- melt_fee: Amount;
+ // Hash of the bank account from where we received the funds.
+ h_wire: HashCode;
+
+ // Hash of the public denomination key used to sign the coin.
+ // Needed because 'coin_sig' signs over this, and
+ // that is important to fix the coin's denomination.
+ h_denom_pub: HashCode;
+
+ // Hash over the proposal data of the contract that
+ // is being paid.
+ h_contract_terms: HashCode;
+
+ }
+
+ .. ts:def:: CoinMeltTransaction
- // Commitment from the melt operation, only for "MELT".
- rc?: TALER_RefreshCommitmentP;
+ interface CoinMeltTransaction {
+ type: "MELT";
- // Hash of the bank account from where we received the funds,
- // only present if ``type`` is "DEPOSIT".
- h_wire?: HashCode;
+ // The total amount of the coin's value absorbed by this transaction.
+ // Note that for melt this means the amount given includes
+ // the melt fee. The current coin value can thus be computed by
+ // subtracting the amounts.
+ amount: Amount;
+
+ // Signature by the coin over a
+ // `TALER_RefreshMeltCoinAffirmationPS` of
+ // purpose ``TALER_SIGNATURE_WALLET_COIN_MELT``.
+ coin_sig: EddsaSignature;
+
+ // Melt fee.
+ melt_fee: Amount;
+
+ // Commitment from the melt operation.
+ rc: TALER_RefreshCommitmentP;
// Hash of the public denomination key used to sign the coin.
- // only present if ``type`` is "DEPOSIT", "RECOUP",
- // "RECOUP-REFRESH", or "MELT".
- h_denom_pub?: HashCode;
+ // Needed because 'coin_sig' signs over this, and
+ // that is important to fix the coin's denomination.
+ h_denom_pub: HashCode;
- // Deposit fee in case of type "REFUND".
- refund_fee?: Amount;
+ }
- // Hash over the proposal data of the contract that
- // is being paid (if type is "DEPOSIT") or refunded (if
- // ``type`` is "REFUND"); otherwise absent.
- h_contract_terms?: HashCode;
+ .. ts:def:: CoinRefundTransaction
+
+ interface CoinRefundTransaction {
+ type: "REFUND";
+
+ // The total amount of the coin's value restored
+ // by this transaction.
+ // The amount given excludes the transaction fee.
+ // The current coin value can thus be computed by
+ // adding the amounts to the coin's denomination value.
+ amount: Amount;
- // Refund transaction ID. Only present if ``type`` is
- // "REFUND".
- rtransaction_id?: Integer;
+ // Refund fee.
+ refund_fee: Amount;
- // Coin blinding key. Only present if ``type`` is
- // "RECOUP" or "RECOUP-REFRESH".
- coin_blind?: DenominationBlindingKeyP;
+ // Hash over the proposal data of the contract that
+ // is being refunded.
+ h_contract_terms: HashCode;
- // Reserve receiving the recoup. Only present if ``type`` is
- // "RECOUP".
- reserve_pub?: EddsaPublicKey;
+ // Refund transaction ID.
+ rtransaction_id: Integer;
- // `EdDSA Signature <eddsa-sig>` authorizing the REFUND. Made with
+ // `EdDSA Signature <eddsa-sig>` authorizing the REFUND over a
+ // `TALER_MerchantRefundConfirmationPS` with
+ // purpose ``TALER_SIGNATURE_MERCHANT_REFUND_OK``. Made with
// the `public key of the merchant <merchant-pub>`.
- // Only present if ``type`` is "REFUND".
- merchant_sig?: EddsaSignature;
+ merchant_sig: EddsaSignature;
+
+ }
+
+ .. ts:def:: CoinRecoupTransaction
+
+ interface CoinRecoupTransaction {
+ type: "RECOUP";
+
+ // The total amount of the coin's value absorbed
+ // by this transaction.
+ // The current coin value can thus be computed by
+ // subtracting the amount from
+ // the coin's denomination value.
+ amount: Amount;
+
+ // Date when the operation was made.
+ timestamp: Timestamp;
+
+ // Signature by the coin over a
+ // `TALER_RecoupRequestPS` with purpose
+ // ``TALER_SIGNATURE_WALLET_COIN_RECOUP``.
+ coin_sig: EddsaSignature;
+
+ // Hash of the public denomination key used to sign the coin.
+ // Needed because 'coin_sig' signs over this, and
+ // that is important to fix the coin's denomination.
+ h_denom_pub: HashCode;
- // Public key of the reserve that will receive the funds, for "RECOUP" operations.
- reserve_pub?: EddsaPublicKey;
+ // Coin blinding key.
+ coin_blind: DenominationBlindingKeyP;
- // Signature by the exchange, only present if ``type`` is "RECOUP",
- // "OLD-COIN-RECOUP" or "RECOUP-REFRESH". Signature is
- // of type TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP for "RECOUP",
- // and of type TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP_REFRESH otherwise.
- exchange_sig?: EddsaSignature;
+ // Reserve receiving the recoup.
+ reserve_pub: EddsaPublicKey;
- // Public key used to sign ``exchange_sig``,
- // only present if ``exchange_sig`` present.
- exchange_pub?: EddsaPublicKey;
+ // Signature by the exchange over a
+ // `TALER_RecoupConfirmationPS`, must be
+ // of purpose ``TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP``.
+ exchange_sig: EddsaSignature;
+
+ // Public key of the private key used to create 'exchange_sig'.
+ exchange_pub: EddsaPublicKey;
+
+ }
+
+ .. ts:def:: CoinOldCoinRecoupTransaction
+
+ interface CoinOldCoinRecoupTransaction {
+ type: "OLD-COIN-RECOUP";
+
+ // The total amount of the coin's value restored
+ // by this transaction.
+ // The current coin value can thus be computed by
+ // adding the amount to the coin's denomination value.
+ amount: Amount;
+
+ // Date when the operation was made.
+ timestamp: Timestamp;
- // Blinding factor of the revoked new coin,
- // only present if ``type`` is "REFRESH_RECOUP".
+ // Signature by the exchange over a
+ // `TALER_RecoupRefreshConfirmationPS`
+ // of purpose ``TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP_REFRESH``.
+ exchange_sig: EddsaSignature;
+
+ // Public key of the private key used to create 'exchange_sig'.
+ exchange_pub: EddsaPublicKey;
+
+ }
+
+ .. ts:def:: CoinRecoupRefreshTransaction
+
+ interface CoinRecoupRefreshTransaction {
+ type: "RECOUP-REFRESH";
+
+ // The total amount of the coin's value absorbed
+ // by this transaction.
+ // The current coin value can thus be computed by
+ // subtracting this amounts from
+ // the coin's denomination value.
+ amount: Amount;
+
+ // Date when the operation was made.
+ timestamp: Timestamp;
+
+ // Signature by the coin over a `TALER_RecoupRequestPS`
+ // with purpose ``TALER_SIGNATURE_WALLET_COIN_RECOUP``.
+ coin_sig: EddsaSignature;
+
+ // Hash of the public denomination key used to sign the coin.
+ // Needed because 'coin_sig' signs over this, and
+ // that is important to fix the coin's denomination.
+ h_denom_pub: HashCode;
+
+ // Coin blinding key.
+ coin_blind: DenominationBlindingKeyP;
+
+ // Signature by the exchange over a
+ // `TALER_RecoupRefreshConfirmationPS`
+ // of purpose ``TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP_REFRESH``.
+ exchange_sig: EddsaSignature;
+
+ // Public key used to sign 'exchange_sig'.
+ exchange_pub: EddsaPublicKey;
+
+ // Blinding factor of the revoked new coin.
new_coin_blinding_secret: RsaBlindingKeySecret;
- // Blinded public key of the revoked new coin,
- // only present if ``type`` is "REFRESH_RECOUP".
+ // Blinded public key of the revoked new coin.
new_coin_ev: RsaBlindingKeySecret;
}
+ .. ts:def:: CoinPurseDepositTransaction
+
+ interface CoinPurseDepositTransaction {
+ type: "PURSE_DEPOSIT";
+
+ // The total amount of the coin's value absorbed
+ // by this transaction.
+ // Note that this means the amount given includes
+ // the deposit fee. The current coin value can thus be computed by
+ // subtracting the amount from
+ // the coin's denomination value.
+ amount: Amount;
+
+ // Deposit fee.
+ deposit_fee: Amount;
+
+ // Public key of the purse.
+ purse_pub: EddsaPublicKey;
+
+ // Date when the purse was set to expire.
+ purse_expiration: Timestamp;
+
+ // Signature by the coin over a
+ // `TALER_PurseDepositSignaturePS` of
+ // purpose ``TALER_SIGNATURE_PURSE_DEPOSIT``.
+ coin_sig: EddsaSignature;
+
+ // Hash of the public denomination key used to sign the coin.
+ // Needed because 'coin_sig' signs over this, and
+ // that is important to fix the coin's denomination.
+ h_denom_pub: HashCode;
+
+ }
+
+ .. ts:def:: CoinPurseRefundTransaction
+
+ interface CoinPurseRefundTransaction {
+ type: "PURSE_REFUND";
+
+ // The total amount of the coin's value restored
+ // by this transaction.
+ // The amount given excludes the refund fee.
+ // The current coin value can thus be computed by
+ // adding the amount to the coin's denomination value.
+ amount: Amount;
+
+ // Refund fee (of the coin's denomination). The deposit
+ // fee will be waived.
+ refund_fee: Amount;
+
+ // Share of the purse fee charged to this coin.
+ // The sum of all purse fee shares will match the
+ // total purse fee.
+ purse_fee_share: Amount;
+
+ // Public key of the purse that expired.
+ purse_pub: EddsaPublicKey;
+
+ // Signature by the exchange over a
+ // `TALER_CoinPurseRefundConfirmationPS`
+ // of purpose ``TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_REFUND``.
+ exchange_sig: EddsaSignature;
+
+ // Public key used to sign 'exchange_sig'.
+ exchange_pub: EddsaPublicKey;
+
+ }
+
+
----------
Refreshing
----------
@@ -1382,6 +2023,8 @@ the API during normal operation.
:http:statuscode:`404 Not found`:
The exchange does not recognize the denomination key as belonging to the exchange,
or it has expired.
+ If the denomination key is unknown, the response will be
+ a `DenominationUnkownMessage`.
:http:statuscode:`409 Conflict`:
The operation is not allowed as the coin has insufficient
residual value, or because the same public key of the coin has been
@@ -1389,6 +2032,12 @@ the API during normal operation.
can be decided by looking at the error code
(``TALER_EC_EXCHANGE_MELT_INSUFFICIENT_FUNDS`` or ``TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY``).
The response is `MeltForbiddenResponse` in both cases.
+ :http:statuscode:`410 Gone`:
+ The requested denomination key is not yet or no longer valid.
+ It either before the validity start, past the expiration or was revoked. The response is a
+ `DenominationExpiredMessage`. Clients must evaluate
+ the error code provided to understand which of the
+ cases this is and handle it accordingly.
**Details:**
@@ -1515,6 +2164,12 @@ the API during normal operation.
rather verbose, as it includes most of the original /refresh/melt request,
but of course expected to be primarily used for diagnostics.
The response body is a `RevealConflictResponse`.
+ :http:statuscode:`410 Gone`:
+ The requested denomination key (for the fresh coins) is not yet or no longer valid.
+ It either before the validity start, past the expiration or was revoked. The response is a
+ `DenominationExpiredMessage`. Clients must evaluate
+ the error code provided to understand which of the
+ cases this is and handle it accordingly.
**Details:**
@@ -1659,16 +2314,24 @@ in using this API.
:http:statuscode:`401 Unauthorized`:
The coin's signature is invalid.
:http:statuscode:`404 Not found`:
- The denomination key is not in the set of denomination
- keys where emergency pay back is enabled, or the blinded
+ The denomination key is unknown, or the blinded
coin is not known to have been withdrawn.
+ If the denomination key is unknown, the response will be
+ a `DenominationUnkownMessage`.
:http:statuscode:`409 Conflict`:
The operation is not allowed as the coin has insufficient
residual value, or because the same public key of the coin has been
previously used with a different denomination. Which case it is
can be decided by looking at the error code
- (``TALER_EC_EXCHANGE_RECOUP_COIN_BALANCE_ZERO`` or ``TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY``).
+ (``TALER_EC_EXCHANGE_RECOUP_COIN_BALANCE_ZERO`` or
+ ``TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY``).
The response is a `DepositDoubleSpendError`.
+ :http:statuscode:`410 Gone`:
+ The requested denomination key is not yet or no longer valid.
+ It either before the validity start, past the expiration or was not yet revoked. The response is a
+ `DenominationExpiredMessage`. Clients must evaluate
+ the error code provided to understand which of the
+ cases this is and handle it accordingly.
**Details:**
@@ -1707,6 +2370,7 @@ in using this API.
interface RecoupWithdrawalConfirmation {
// Tag to distinguish the `RecoupConfirmation` response type.
refreshed: false;
+
// Public key of the reserve that will receive the recoup.
reserve_pub: EddsaPublicKey;
}
@@ -1716,6 +2380,7 @@ in using this API.
interface RecoupRefreshConfirmation {
// Tag to distinguish the `RecoupConfirmation` response type.
refreshed: true;
+
// Public key of the old coin that will receive the recoup.
old_coin_pub: EddsaPublicKey;
}
@@ -1790,7 +2455,8 @@ typically also view the balance.)
deposits: TrackTransferDetail[];
// Signature from the exchange made with purpose
- // `TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT`.
+ // ``TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT``
+ // over a `TALER_WireDepositDataPS`.
exchange_sig: EddsaSignature;
// Public EdDSA key of the exchange that was used to generate the signature.
@@ -1826,7 +2492,7 @@ typically also view the balance.)
**Request:**
- :query merchant_sig: EdDSA signature of the merchant made with purpose ``TALER_SIGNATURE_MERCHANT_TRACK_TRANSACTION``, affirming that it is really the merchant who requires obtaining the wire transfer identifier.
+ :query merchant_sig: EdDSA signature of the merchant made with purpose ``TALER_SIGNATURE_MERCHANT_TRACK_TRANSACTION`` over a `TALER_DepositTrackPS`, affirming that it is really the merchant who requires obtaining the wire transfer identifier.
**Response:**
@@ -1839,7 +2505,7 @@ typically also view the balance.)
merchant should come back later and ask again.
The response body is a `TrackTransactionAcceptedResponse`.
:http:statuscode:`401 Unauthorized`:
- The signature is invalid.
+ A signature is invalid.
:http:statuscode:`404 Not found`:
The deposit operation is unknown to the exchange.
@@ -1860,7 +2526,8 @@ typically also view the balance.)
// Total amount transferred.
total_amount: Amount;
- // Binary-only Signature_ for purpose `TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE`
+ // Binary-only Signature_ with purpose ``TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE``
+ // over a `TALER_ConfirmWirePS`
// whereby the exchange affirms the successful wire transfer.
exchange_sig: EddsaSignature;
@@ -1932,7 +2599,10 @@ Refunds
// EdDSA public key of the merchant.
merchant_pub: EddsaPublicKey;
- // EdDSA signature of the merchant affirming the refund.
+ // EdDSA signature of the merchant over a
+ // `TALER_RefundRequestPS` with purpose
+ // ``TALER_SIGNATURE_MERCHANT_REFUND``
+ // affirming the refund.
merchant_sig: EddsaPublicKey;
}
@@ -1942,7 +2612,9 @@ Refunds
interface RefundSuccess {
// The EdDSA :ref:`signature` (binary-only) with purpose
- // `TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND` using a current signing key of the
+ // ``TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND`` over
+ // a `TALER_RecoupRefreshConfirmationPS`
+ // using a current signing key of the
// exchange affirming the successful refund.
exchange_sig: EddsaSignature;
@@ -1971,3 +2643,692 @@ Refunds
// the relevant subset of the transactions.
history: CoinSpendHistoryItem[];
}
+
+
+.. _exchange_w2w:
+
+--------------------------
+Wallet-to-wallet transfers
+--------------------------
+
+.. http:GET:: /purses/$PURSE_PUB
+
+ Obtain information about a purse. The request header must
+ contain a *Purse-Request-Signature*. Endpoint used by
+ the party that did not create the purse.
+
+ **Request:**
+
+ *Purse-Request-Signature*: The client must provide Base-32 encoded EdDSA signature made with ``$PURSE_PRIV``, affirming its authorization to download the purse status. The purpose used MUST be ``TALER_SIGNATURE_PURSE_STATUS_REQUEST``.
+
+ :query merge_timeout_ms=NUMBER: *Optional.* If specified,
+ the exchange
+ will wait up to ``timeout_ms`` milliseconds for completion
+ of a merge operation before sending the HTTP response.
+ :query deposit_timeout_ms=NUMBER: *Optional.* If specified,
+ the exchange
+ will wait up to ``timeout_ms`` milliseconds for completion
+ of a deposit operation before sending the HTTP response.
+ :query contract=BOOLEAN: *Optional.* If 'false' is specified,
+ the exchange will not return the encrypted contract, saving
+ bandwidth for clients that already know it.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The operation succeeded, the exchange provides details
+ about the purse.
+ The response will include a `PurseStatus` object.
+ :http:statuscode:`401 Unauthorized`:
+ The *Purse-Request-Signature* is invalid.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`404 Not found`:
+ The purse is unknown to the exchange.
+
+ **Details:**
+
+ .. ts:def:: PurseStatus
+
+ interface PurseStatus {
+
+ // Total amount deposited into the purse so far.
+ // If 'total_deposit_amount' minus 'deposit_fees'
+ // exceeds 'merge_value_after_fees', and a
+ // 'merge_request' exists for the purse, then the
+ // purse will (have been) merged with the account.
+ total_deposit_amount: Amount;
+
+ // Indicative time by which the purse expires
+ // if it has not been merged into an account. At this
+ // point, all of the deposits made will be auto-refunded.
+ purse_expiration: Timestamp;
+
+ // Desired total amount to be merged into the reserve.
+ // (excludes fees).
+ merge_value_after_fees: Amount;
+
+ // Indicative time at which the exchange is answering the
+ // status request. Used as part of 'exchange_sig'.
+ status_timestamp: Timestamp;
+
+ // Deposit fees charged so far to all deposited coins.
+ deposit_fees: Amount;
+
+ // SHA-512 hash of the contact of the purse.
+ h_contract_terms: HashCode;
+
+ // EdDSA signature of the exchange over a
+ // `TALER_PurseStatusResponseSignaturePS`
+ // with purpose ``TALER_SIGNATURE_PURSE_STATUS_RESPONSE``
+ // affirming the purse status.
+ exchange_sig: EddsaSignature;
+
+ // EdDSA public key exchange used for 'exchange_sig'.
+ exchange_pub: EddsaPublicKey;
+
+ // AES-GCM Encrypted contract terms using encryption
+ // key derived from DH of 'contract_pub' and the 'purse_pub'.
+ // Optional, may be omitted if not desired by the client.
+ e_contract_terms?: string;
+
+ // If a merge request was received, information about the
+ // merge request. Omitted if the purse has not yet received
+ // a merge request.
+ merge_request?: MergeRequest;
+
+ }
+
+
+.. http:POST:: /purses/$PURSE_PUB/deposit
+
+ Deposit money into a purse. Endpoint used by the buyer.
+
+ **Request:**
+
+ The request body must be a `PurseRequest` object.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The operation succeeded, the exchange confirms that all
+ coins were deposited into the purse.
+ The response will include a `PurseDepositSuccess` object.
+ :http:statuscode:`202 Accepted`:
+ The payment was accepted, but insufficient to reach the
+ specified purse balance. If an encrypted contract was
+ provided, it will have been stored in the database.
+ The client should make further
+ purse deposits before the expiration deadline.
+ The response will include a `PurseDepositAccepted` object.
+ :http:statuscode:`401 Unauthorized`:
+ A coin signature is invalid. The response will
+ include a `PurseDepositSignatureErrorDetail`
+ :http:statuscode:`403 Forbidden`:
+ The server is denying the operation as a purse with a
+ different contract or total amount already exists.
+ This response comes with a standard `PurseConflict` response.
+ :http:statuscode:`404 Not found`:
+ FIXME: when exactly does this happen?
+ :http:statuscode:`409 Conflict`:
+ The deposit operation has either failed because a coin has insufficient
+ residual value, or because the same public key of the coin has been
+ previously used with a different denomination. Which case it is
+ can be decided by looking at the error code
+ (``TALER_EC_EXCHANGE_DEPOSIT_INSUFFICIENT_FUNDS`` or
+ ``TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY``).
+ The fields of the response are the same in both cases.
+ The request should not be repeated again with this coin.
+ In this case, the response is a `PurseDepositDoubleSpendError`.
+ If the value of all successful coins is below the purse fee,
+ the exchange may not setup the purse at all. The encrypted
+ contract will not have been associated with the purse if this
+ status code is returned. However, all coins that were not
+ double-spent will have been deposited into the purse.
+ :http:statuscode:`425 Too Early`:
+ This response type is used if the given purse expiration time
+ is too far in the future (at least from the perspective
+ of the exchange). Thus, retrying at a later time may
+ succeed. The client should look at the ``Date:`` header of the response to see if a minor time difference is to blame and possibly adjust the request accordingly.
+
+
+ **Details:**
+
+ .. ts:def:: PurseRequest
+
+ interface PurseRequest {
+
+ // EdDSA signature of the purse over a
+ // `TALER_PurseRequestSignaturePS`
+ // of purpose ``TALER_SIGNATURE_PURSE_REQUEST``
+ // confirming the key
+ // invariants associated with the purse.
+ // (amount, h_contract_terms, expiration).
+ purse_sig: EddsaSignature;
+
+ // Total amount to be paid into the purse.
+ // Clients may make several requests, i.e. if a
+ // first request failed with a double-spending error.
+ // The exchange will confirm the creation of the
+ // purse once the amount given here is reached.
+ merge_value_after_fees: Amount;
+
+ // SHA-512 hash of the contact of the purse.
+ h_contract_terms: HashCode;
+
+ // Client-side timestamp of when the payment was made.
+ payment_timestamp: Timestamp;
+
+ // Indicative time by which the purse should expire
+ // if it has not been merged into an account. At this
+ // point, all of the deposits made will be auto-refunded.
+ purse_expiration: Timestamp;
+
+ // Optional encrypted contract, in case the buyer is
+ // proposing the contract and thus establishing the
+ // purse with the payment.
+ contract?: EncryptedContract;
+
+ // Array of coins being deposited into the purse.
+ // Maximum length is 128.
+ deposits: PurseDeposit[];
+ }
+
+ .. ts:def:: EncryptedContract
+
+ interface EncryptedContract {
+
+ // ECDH contract_public key used to encrypt the contract.
+ // Optional as the contract terms may already be known
+ // to the exchange or the other wallet from a different
+ // interaction.
+ contract_pub: TALER_EcdhEphemeralPublicKeyP;
+
+ // AES-GCM Encrypted contract terms using encryption
+ // key derived from DH of ``contract_pub`` and the ``purse_pub``.
+ // Optional as the contract terms may already be known
+ // to the exchange or the other wallet from a different
+ // interaction.
+ e_contract_terms: string;
+ }
+
+ .. ts:def:: PurseDeposit
+
+ interface PurseDeposit {
+
+ // Public key of the coin being deposited into the purse.
+ coin_pub: EddsaPublicKey;
+
+ // Amount to be deposited, can be a fraction of the
+ // coin's total value.
+ contribution: Amount;
+
+ // Hash of denomination RSA key with which the coin is signed.
+ denom_pub_hash: HashCode;
+
+ // Exchange's unblinded RSA signature of the coin.
+ ub_sig: RsaSignature;
+
+ // Signature over `TALER_PurseDepositSignaturePS`
+ // of purpose ``TALER_SIGNATURE_PURSE_DEPOSIT``
+ // made by the customer with the
+ // `coin's private key <coin-priv>`.
+ coin_sig: EddsaSignature;
+
+ }
+
+ .. ts:def:: PurseDepositSuccess
+
+ interface PurseDepositSuccess {
+
+ // Total amount paid into the purse.
+ total_purse_amount: Amount;
+
+ // Total deposit fees charged.
+ total_deposit_fees: Amount;
+
+ // EdDSA signature of the exchange affirming the payment,
+ // of purpose ``TALER_SIGNATURE_PURSE_DEPOSIT_CONFIRMED``
+ // over a `TALER_PurseDepositConfirmedSignaturePS`.
+ // Signs over the above and the purse public key and
+ // the hash of the contract terms.
+ exchange_sig: EddsaSignature;
+
+ // public key used to create the signature.
+ exchange_pub: EddsaPublicKey;
+
+ }
+
+ .. ts:def:: PurseDepositAccepted
+
+ interface PurseDepositAccepted {
+
+ // Total amount paid so far into the purse, in this
+ // and previous requests.
+ total_amount_deposited: Amount;
+
+ // Total amount contributed by the current request.
+ total_amount_contributed: Amount;
+
+ }
+
+ .. ts:def:: PurseConflict
+
+ // Union discriminated by the "type" field.
+ type PurseConflict =
+ | PurseMergeConflict
+ | PurseRequestConflict;
+
+ .. ts:def:: PurseMergeConflict
+
+ interface PurseMergeConflict {
+ type: "MERGE";
+
+ // SHA-512 hash of the contact of the purse.
+ h_contract_terms: HashCode;
+
+ // Hash of the wire details of the reserve.
+ h_wire: HashCode;
+
+ // Reserve merging the purse.
+ reserve_pub: EddsaPublicKey;
+
+ // Indicative time by which the purse should expire
+ // if it has not been merged into an account. At this
+ // point, all of the deposits made should be
+ // auto-refunded.
+ purse_expiration: Timestamp;
+
+ // When was the merge request generated.
+ merge_timestamp: Timestamp;
+
+ // Total amount to be merged into the reserve.
+ // (excludes fees).
+ merge_value_after_fees: Amount;
+
+ // EdDSA signature of the purse over
+ // `TALER_PurseMergeSignaturePS` of
+ // purpose ``TALER_SIGNATURE_PURSE_MERGE``
+ // confirming that the
+ // above details hold for this purse.
+ purse_sig: EddsaSignature;
+ }
+
+ .. ts:def:: PurseRequestConflict
+
+ interface PurseRequestConflict {
+ type: "REQUEST";
+
+ // SHA-512 hash of the contact of the purse.
+ h_contract_terms: HashCode;
+
+ // Indicative time by which the purse should expire
+ // if it has not been merged into an account. At this
+ // point, all of the deposits made should be
+ // auto-refunded.
+ purse_expiration: Timestamp;
+
+ // Total amount to be paid into the purse as per
+ // the previous request.
+ total_purse_amount: Amount;
+
+ // EdDSA signature of the purse over
+ // `TALER_PurseRequestSignaturePS` of
+ // purpose ``TALER_SIGNATURE_PURSE_REQUEST``
+ // confirming that the
+ // above details hold for this purse.
+ purse_sig: EddsaSignature;
+
+ }
+
+ .. ts:def:: PurseDepositDoubleSpendError
+
+ interface DepositDoubleSpendError {
+ // Taler error code.
+ code: number;
+
+ // Human-readable description of the error, i.e. "insufficient funds".
+ hint?: string;
+
+ // Total amount contributed by the current request.
+ // Note that some coins may have been successfully
+ // deposited into the purse, so the total amount
+ // from these coins is listed here.
+ total_amount_contributed: Amount;
+
+ // Public keys of coins that could not be deposited
+ // into the purse, mapped to the coin's histories.
+ coin_map: EddsaPublicKey -> CoinSpendHistoryItem[];
+ }
+
+
+ .. ts:def:: PurseDepositSignatureErrorDetail
+
+ interface PurseDepositSignatureErrorDetail {
+ // Taler error code, summarizing the problem.
+ // Note that for problems about specific
+ // coins, the 'coin_error_map' should be consulted.
+ // The 'coin_error_map' will be empty if the
+ // 'purse_sig' was invalid. In this case,
+ // the coins will not even have been checked by
+ // the exchange.
+ code: number;
+
+ // Human-readable description of the error, i.e. "invalid siganture".
+ hint?: string;
+
+ // Total amount contributed by the current request.
+ // Note that some coins may have been successfully
+ // deposited into the purse, so the total amount
+ // from these coins is listed here.
+ total_amount_contributed: Amount;
+
+ // Public keys of coins that could not be deposited
+ // into the purse, mapped to the coin's histories.
+ coin_error_map: EddsaPublicKey -> ErrorDetail[];
+ }
+
+
+.. http:POST:: /purses/$PURSE_PUB/merge
+
+ Merge purse with account, adding the value of the purse into
+ the account. Endpoint to be used by the seller.
+
+ **Request:**
+
+ The request body must be a `MergeRequest` object.
+
+ :query timeout_ms=NUMBER: *Optional.* If specified, the exchange will
+ wait up to ``timeout_ms`` milliseconds to receive payment before
+ reporting on the completion of merge operation. Basically
+ forstalls returning a 202 response for up to timeout milliseconds
+ to possibly return a 200 response instead.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The operation succeeded, the exchange confirms that the
+ funds were merged into the account.
+ The response will include a `MergeSuccess` object.
+ :http:statuscode:`202 Accepted`:
+ The operation succeeded, the exchange confirms that the
+ merge request is valid. Alas, the purse was still not
+ funded and thus the actual merge is delayed.
+ The response will include a `MergeAccepted` object.
+ :http:statuscode:`401 Unauthorized`:
+ Account signature is invalid.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`404 Not found`:
+ The refund operation failed as we could not find the purse.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`410 Gone`:
+ The purse has already expired and thus can no longer be merged.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`429 Too Many Requests`:
+ This account is not at this exchange, has not yet passed the
+ KYC checks, or it has exceeded the number of open purses.
+ The client must include payment to create another purse or
+ wait until existing purses have expired.
+
+ **Details:**
+
+ .. ts:def:: MergeRequest
+
+ interface MergeRequest {
+
+ // payto://-URI of the account the purse is to be merged into.
+ // Must be of the form: 'payto://taler/$EXCHANGE_URL/$RESERVE_PUB'.
+ payto_uri: string;
+
+ // EdDSA signature of the account/reserve affirming the merge
+ // over a `TALER_AccountMergeSignaturePS`.
+ // Must be of purpose ``TALER_SIGNATURE_ACCOUNT_MERGE``
+ reserve_sig: EddsaSignature;
+
+ // EdDSA signature of the purse private key affirming the merge
+ // over a `TALER_PurseMergeSignaturePS`.
+ // Must be of purpose ``TALER_SIGNATURE_PURSE_MERGE``.
+ purse_sig: EddsaSignature;
+
+ // Minimum amount that must be credited to the reserve, that is
+ // the total value of the purse minus the deposit fees.
+ // If the deposit fees are lower, the contribution to the
+ // reserve can be higher!
+ merge_value_after_fees: Amount;
+
+ // SHA-512 hash of the contact of the purse.
+ h_contract_terms: HashCode;
+
+ // Client-side timestamp of when the merge request was made.
+ merge_timestamp: Timestamp;
+
+ // Indicative time by which the purse should expire
+ // if it has not been paid.
+ purse_expiration: Timestamp;
+
+ // Optional encrypted contract, in case the seller is
+ // proposing the contract and thus establishing the
+ // purse with the payment.
+ contract?: EncryptedContract;
+
+ }
+
+ .. ts:def:: MergeSuccess
+
+ interface MergeSuccess {
+
+ // Amount merged (excluding deposit fees).
+ merge_amount: Amount;
+
+ // SHA-512 hash of the contact of the purse.
+ h_contract_terms: HashCode;
+
+ // Time at which the merge came into effect.
+ // Maximum of the "payment_timestamp" and the
+ // "merge_timestamp".
+ contract_time: Timestamp;
+
+ // EdDSA signature of the exchange affirming the merge of
+ // purpose ``TALER_SIGNATURE_PURSE_MERGE_SUCCESS``
+ // over `TALER_PurseMergeSuccessSignaturePS`.
+ // Signs over the above and the account public key.
+ exchange_sig: EddsaSignature;
+
+ // public key used to create the signature.
+ exchange_pub: EddsaPublicKey;
+
+ }
+
+ .. ts:def:: MergeAccepted
+
+ interface MergeAccepted {
+
+ // The number of remaining purses that can still be opened
+ // under the given account.
+ remaining_purses: Integer;
+
+ }
+
+
+.. http:POST:: /reserves/$RESERVE_PUB/kyc
+
+ Upgrade a reserve to an *account*. The reserve must
+ (from wire transfers or merges of purses) already have a
+ sufficient balance to cover the KYC fee. The signature
+ affirms that the KYC fee can and should be charged to the reserve.
+ The request always updates the payto URI associated with
+ the reserve, even if the KYC process fails or is not completed.
+
+ **Request:** The request body must be a `AccountSetupRequest` object.
+
+ :query timeout_ms=NUMBER: *Optional.* If specified, the exchange will
+ wait up to ``timeout_ms`` milliseconds for the KYC gateway to
+ confirm completion of the KYC process.
+
+ **Response:**
+
+ :http:statuscode:`200 Ok`:
+ The operation succeeded, the exchange confirms that the account
+ can now be used.
+ The response will be an `AccountKycStatus` object.
+ :http:statuscode:`202 Accepted`:
+ The user should be redirected to the provided location to perform
+ the required KYC checks to open the account. Afterwards, the
+ request should be repeated.
+ The response will be an `AccountKycRedirect` object.
+ :http:statuscode:`504 Gateway Timeout`:
+ The exchange did not receive a confirmation from the KYC service
+ within the specified time period. Used when long-polling for the
+ result.
+
+ **Details:**
+
+ .. ts:def:: AccountSetupRequest
+
+ interface AccountSetupRequest {
+
+ // Time of the request to perform the KYC. Determines
+ // the KYC fee charged by the exchange. Must be
+ // reasonably close to the current time of the exchange.
+ kyc_timestamp: Timestamp;
+
+ // Bank account to be associated with the account.
+ // Can be 'payto://void/' to not associate the
+ // account with any bank account. In this case,
+ // closing the account will result in the balance
+ // being forfeit. If the provided wire method is
+ // not supported by the exchange *and* not 'void',
+ // this is a ``Bad Request`` (HTTP status 400).
+ payto_uri: string;
+
+ // EdDSA signature of the reserve affirming the request
+ // to create the account, must be of purpose
+ // ``TALER_SIGNATURE_ACCOUNT_SETUP_REQUEST``
+ // and over `TALER_AccountSetupRequestSignaturePS`.
+ reserve_sig: EddsaPublicKey;
+
+ }
+
+ .. ts:def:: AccountKycStatus
+
+ interface AccountKycStatus {
+
+ // Current time of the exchange, used as part of
+ // what the exchange signs over.
+ now: Timestamp;
+
+ // EdDSA signature of the exchange affirming the account
+ // is KYC'ed, must be of purpose
+ // ``TALER_SIGNATURE_ACCOUNT_SETUP_SUCCESS``
+ // and over `TALER_AccountSetupRequestSignaturePS`.
+ exchange_sig: EddsaSignature;
+
+ // public key used to create the signature.
+ exchange_pub: EddsaPublicKey;
+ }
+
+ .. ts:def:: AccountKycRedirect
+
+ interface AccountKycRedirect {
+
+ // URL that the user should open in a browser to
+ // proceed with the KYC process.
+ kyc_url: string;
+
+ }
+
+
+
+
+
+.. _exchange_wads:
+
+
+Wads
+^^^^
+
+These endpoints are used to manage exchange-to-exchange payments in support of
+wallet-to-wallet payments. Only another exchange should access this endpoint.
+
+
+.. http:GET:: /wads/$WAD_ID
+
+ Obtain information about a wad.
+
+ **Request:**
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The operation succeeded, the exchange provides details
+ about the wad.
+ The response will include a `WadDetails` object.
+ :http:statuscode:`404 Not found`:
+ The wad is unknown to the exchange.
+
+ **Details:**
+
+ .. ts:def:: WadDetails
+
+ interface WadDetails {
+
+ // Total transfer amount claimed by the exchange.
+ total: Amount;
+
+ // Indicative time by which the wad was given to the
+ // bank to execute the wire transfer.
+ wad_execution_time: Timestamp;
+
+ // Transfers aggregated in the wad.
+ items: WadItem[];
+
+ // EdDSA signature of the exchange affirming the wad
+ // data is correct, must be over `TALER_WadDataSignaturePS`
+ // and of purpose ``TALER_SIGNATURE_WAD_DATA``.
+ exchange_sig: EddsaSignature;
+
+ // public key used to create the signature.
+ exchange_pub: EddsaPublicKey;
+ }
+
+ Objects in the wad item list have the following format:
+
+ .. ts:def:: WadItem
+
+ interface WadItem {
+
+ // Amount in the purse.
+ amount: Amount;
+
+ // payto://-URI of the account the purse is to be merged into.
+ // Must be of the form: 'payto://taler/EXCHANGE_URL/RESERVE_PUB'.
+ payto_uri: string;
+
+ // Purse public key.
+ purse_pub: EddsaPublicKey;
+
+ // Hash of the contract.
+ h_contract: HashCode;
+
+ // Indicative time by which the purse should expire
+ // if it has not been paid.
+ purse_expiration: Timestamp;
+
+ // Client-side timestamp of when the merge request was made.
+ merge_timestamp: Timestamp;
+
+ // Signature created with the reserve's private key.
+ // Must be of purpose ``TALER_SIGNATURE_ACCOUNT_MERGE``
+ // and over `TALER_AccountMergeSignaturePS`.
+ reserve_sig: EddsaSignature;
+
+ // Signature created with the purse's private key.
+ // Must be of purpose ``TALER_SIGNATURE_PURSE_MERGE``
+ // and over `TALER_PurseMergeSignaturePS`.
+ purse_sig: EddsaSignature;
+
+ // Deposit fees that were charged to the purse.
+ deposit_fees: Amount;
+
+ // Wad fees that was charged to the purse.
+ wad_fees: Amount;
+ }
diff --git a/core/api-merchant.rst b/core/api-merchant.rst
index 5a55e2d2..d8e3c910 100644
--- a/core/api-merchant.rst
+++ b/core/api-merchant.rst
@@ -1546,12 +1546,21 @@ Creating orders
The backend has successfully created the proposal. The response is a
:ts:type:`PostOrderResponse`.
:http:statuscode:`404 Not found`:
- The order given used products from the inventory, but those were not found
- in the inventory. Or the merchant instance is unknown (including possibly the instance being not configured for new orders). Details in the
- error code. NOTE: no good way to find out which product is not in the
- inventory, we MAY want to specify that in the reply.
+ Possible reasons are:
+
+ (1) The order given used products from the inventory, but those were
+ not found in the inventory.
+ (2) The merchant instance is unknown (including possibly the instance
+ being not configured for new orders).
+ (3) The wire method specified is not supported by the backend.
+
+ Details in the error code.
+ NOTE: currently the client has no good way to find out which product
+ is not in the inventory, we MAY want to specify that in the reply.
:http:statuscode:`409 Conflict`:
- A different proposal already exists under the specified order ID.
+ A different proposal already exists under the specified order ID,
+ or the requested currency is not supported by this backend. Details in
+ the error code.
:http:statuscode:`410 Gone`:
The order given used products from the inventory that are out of stock.
The response is a :ts:type:`OutOfStockResponse`.
@@ -1622,7 +1631,7 @@ Creating orders
fulfillment_url?: string;
}
- The following `ProductSpecification` can be provided if the parts of the
+ The following `MinimalInventoryProduct` can be provided if the parts of the
order are inventory-based, that is if the `PostOrderRequest` uses
``inventory_products``. For such products, which must be in the backend's inventory,
the backend can automatically fill in the amount and other details about
@@ -1968,6 +1977,9 @@ the contract!) to minimize risks from information leakage.
:http:statuscode:`200 OK`:
The merchant deleted the specified fields from the contract of
order $ORDER_ID.
+ :http:statuscode:`204 No content`:
+ The merchant had already deleted the specified fields
+ from the contract of order $ORDER_ID.
:http:statuscode:`400 Bad request`:
The request is malformed or one of the paths is invalid.
:http:statuscode:`404 Not found`:
@@ -2103,10 +2115,11 @@ Informing the backend about incoming wire transfers
resolve it. So in that respect, 202 is the right status code as more
work remains to be done for a final resolution.)
:http:statuscode:`404 Not found`:
- The instance is unknown to the exchange.
+ The instance or account are unknown to the exchange.
:http:statuscode:`409 Conflict`:
The wire transfer identifier is already known to us, but for a different amount,
- wire method or exchange.
+ wire method or exchange, or the amount reported by the exchange differs from
+ the amount reported by the merchant.
:http:statuscode:`502 Bad gateway`:
The exchange returned an error when we asked it about the ``GET /transfer`` status
for this wire transfer. Details of the exchange error are returned.
@@ -2352,7 +2365,7 @@ Querying known wire transfers
exchange_url: string;
// Serial number identifying the transfer in the merchant backend.
- // Used for filgering via ``offset``.
+ // Used for filtering via ``offset``.
transfer_serial_id: number;
// Time of the execution of the wire transfer by the exchange, according to the exchange
@@ -2371,6 +2384,30 @@ Querying known wire transfers
}
+Deleting wire transfer
+----------------------
+
+Deleting a wire transfer can be useful in case of a data entry
+mistake. In particular, if the exchange base URL was entered
+badly, deleting the old entry and adding a correct one is a
+good idea. Note that deleting wire transfers is no longer possible
+once we got a reply from the exchange.
+
+.. http:delete:: [/instances/$INSTANCE]/private/transfers/$TID
+
+ Here, the TID ist the 'transfer_serial_id' of the transfer
+ to delete.
+
+ **Response:**
+
+ :http:statuscode:`204 No content`:
+ The transfer was deleted.
+ :http:statuscode:`404 Not found`:
+ The transfer was already unknown.
+ :http:statuscode:`409 Conflict`:
+ The transfer cannot be deleted anymore.
+
+
--------------------
Backend: Giving tips
--------------------
diff --git a/core/api-wire.rst b/core/api-wire.rst
index fbf27469..654d72f3 100644
--- a/core/api-wire.rst
+++ b/core/api-wire.rst
@@ -175,7 +175,15 @@ Querying the transaction history
.. ts:def:: IncomingBankTransaction
- interface IncomingBankTransaction {
+ // Union discriminated by the "type" field.
+ type IncomingBankTransaction =
+ | IncomingReserveTransaction
+ | IncomingWadTransaction;
+
+ .. ts:def:: IncomingReserveTransaction
+
+ interface IncomingReserveTransaction {
+ type: "RESERVE";
// Opaque identifier of the returned record.
row_id: SafeUint64;
@@ -195,6 +203,35 @@ Querying the transaction history
// The reserve public key extracted from the transaction details.
reserve_pub: EddsaPublicKey;
+
+ }
+
+ .. ts:def:: IncomingWadTransaction
+
+ interface IncomingWadTransaction {
+ type: "WAD";
+
+ // Opaque identifier of the returned record.
+ row_id: SafeUint64;
+
+ // Date of the transaction.
+ date: Timestamp;
+
+ // Amount transferred.
+ amount: Amount;
+
+ // Payto URI to identify the receiver of funds.
+ // This must be one of the exchange's bank accounts.
+ credit_account: string;
+
+ // Payto URI to identify the sender of funds.
+ debit_account: string;
+
+ // Base URL of the exchange that originated the wad.
+ origin_exchange_url: string;
+
+ // The reserve public key extracted from the transaction details.
+ wad_id: WadId;
}
@@ -308,6 +345,8 @@ exposed by bank gateways in production.
Authentication failed, likely the credentials are wrong.
:http:statuscode:`404 Not found`:
The endpoint is wrong or the user name is unknown. The bank replies with an `ErrorDetail` object.
+ :http:statuscode:`409 Conflict`:
+ The 'reserve_pub' argument was used previously in another transfer, and the specification mandates that reserve public keys must not be reused.
.. ts:def:: AddIncomingRequest
diff --git a/core/index.rst b/core/index.rst
index 95037d48..7ead2193 100644
--- a/core/index.rst
+++ b/core/index.rst
@@ -32,12 +32,13 @@ interfaces between the core components of Taler.
api-common
api-error
api-exchange
- api-wire
api-merchant
api-auditor
+ api-sync
+ api-wire
+ api-bank-merchant
api-bank-integration
api-bank-access
wireformats
- api-sync
taler-uri
errors