summaryrefslogtreecommitdiff
path: root/core/api-merchant.rst
diff options
context:
space:
mode:
Diffstat (limited to 'core/api-merchant.rst')
-rw-r--r--core/api-merchant.rst967
1 files changed, 409 insertions, 558 deletions
diff --git a/core/api-merchant.rst b/core/api-merchant.rst
index ffaef0a2..d9c6611f 100644
--- a/core/api-merchant.rst
+++ b/core/api-merchant.rst
@@ -1,6 +1,6 @@
..
This file is part of GNU TALER.
- Copyright (C) 2014-2023 Taler Systems SA
+ Copyright (C) 2014-2024 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software
@@ -25,7 +25,7 @@ Merchant Backend RESTful API
============================
.. contents:: Table of Contents
-
+ :local:
-----------------------
Base URLs and Instances
@@ -36,11 +36,13 @@ This is useful when multiple businesses want to share the same payment
infrastructure.
Merchant backends have one special ``default`` instance. This ``default``
-instance is used when no explicit instance is specified. Despite its name,
-this instance must be created after the installation. In case *no* default
-instance is found - or its credentials got lost -, the administrator can use
-the default instance's rights by resorting on the ``--auth`` command line option,
-or by restarting the service by providing an environment variable called
+instance is used when no explicit instance is specified. Note that using
+``/instances/default/$ANYTHING`` is deprecated and will result in a permanent
+redirect (HTTP status 308) to ``$ANYTHING``. a Despite its name, this instance
+must be created after the installation. In case *no* default instance is
+found - or its credentials got lost -, the administrator can use the default
+instance's rights by resorting on the ``--auth`` command line option, or by
+restarting the service by providing an environment variable called
``TALER_MERCHANT_TOKEN``.
Each instance (default and others) has a base URL. The resources under
@@ -74,10 +76,10 @@ Examples:
https://merchant-backend.example.com/instances/myinst/orders/ABCD
A private endpoint (explicit "default" instance):
- https://merchant-backend.example.com/instances/default/private/orders
+ https://merchant-backend.example.com/private/orders
A public endpoint (explicit "default" instance):
- https://merchant-backend.example.com/instances/default/orders
+ https://merchant-backend.example.com/orders
Endpoints to manage other instances (ONLY for implicit "default" instance):
https://merchant-backend.example.com/management/instances
@@ -121,7 +123,7 @@ such as the implemented version of the protocol and the currency used.
.. http:get:: /config
Return the protocol version and currency supported by this merchant backend.
- This specification corresponds to ``current`` protocol being version **6**.
+ This specification corresponds to ``current`` protocol being version **13**.
**Response:**
@@ -139,6 +141,10 @@ such as the implemented version of the protocol and the currency used.
// Name of the protocol.
name: "taler-merchant";
+ // URN of the implementation (needed to interpret 'revision' in version).
+ // @since **v8**, may become mandatory in the future.
+ implementation?: string;
+
// Default (!) currency supported by this backend.
// This is the currency that the backend should
// suggest by default to the user when entering
@@ -160,7 +166,7 @@ such as the implemented version of the protocol and the currency used.
currencies: { currency : CurrencySpecification};
// Array of exchanges trusted by the merchant.
- // Since protocol v6.
+ // Since protocol **v6**.
exchanges: ExchangeConfigInfo[];
}
@@ -193,8 +199,7 @@ This section describes (public) endpoints that wallets must be able
to interact with directly (without HTTP-based authentication). These
endpoints are used to process payments (claiming an order, paying
for the order, checking payment/refund status and aborting payments),
-process refunds (checking refund status, obtaining the refund),
-and to pick up rewards.
+and to process refunds (checking refund status, obtaining the refund).
Claiming an order
@@ -283,17 +288,17 @@ Making the payment
Either the client request is malformed or some specific processing error
happened that may be the fault of the client as detailed in the JSON body
of the response.
+ This includes the case where the payment is insufficient (sum is below
+ the required total amount, for example because the wallet calculated the
+ fees wrong).
:http:statuscode:`402 Payment required`:
There used to be a sufficient payment, but due to refunds the amount effectively
paid is no longer sufficient. (If the amount is generally insufficient, we
- return "406 Not Acceptable", only if this is because of refunds we return 402.)
+ return "400 Bad Request", only if this is because of refunds we return 402.)
:http:statuscode:`403 Forbidden`:
One of the coin signatures was not valid.
:http:statuscode:`404 Not found`:
The merchant backend could not find the order or the instance and thus cannot process the payment.
- :http:statuscode:`406 Not acceptable`:
- The payment is insufficient (sum is below the required total amount).
- TODO: Should probably change to a different status code in the future as 406 is technically wrong.
:http:statuscode:`408 Request timeout`:
The backend took too long to process the request. Likely the merchant's connection
to the exchange timed out. Try again.
@@ -364,7 +369,7 @@ Making the payment
coin_pub: EddsaPublicKey;
// Signature made by the denomination public key.
- ub_sig: RsaSignature;
+ ub_sig: UnblindedSignature;
// The hash of the denomination public key associated with this coin.
h_denom: HashCode;
@@ -407,6 +412,7 @@ Querying payment status
merchant backend may return a response immediately.
:query await_refund_obtained=BOOLEAN: *Optional*. If set to "yes", poll for the order's pending refunds to be picked up. ``timeout_ms`` specifies how long we will wait for the refund.
:query refund=AMOUNT: *Optional*. Indicates that we are polling for a refund above the given AMOUNT. ``timeout_ms`` will specify how long we will wait for the refund.
+ :query allow_refunded_for_repurchase: *Optional*. Since protocol **v9** refunded orders are only returned under "already_paid_order_id" if this flag is set explicitly to "YES".
**Response:**
@@ -586,7 +592,7 @@ are for incomplete payments for an order and never for established contracts.
:http:statuscode:`200 OK`:
The merchant accepted the request, and passed it on to the exchange. The body is a
- a `merchant refund response <MerchantRefundResponse>`. Note that the exchange
+ a `abort response <AbortResponse>`. Note that the exchange
MAY still have encountered errors in processing. Those will then be part of
the body. Wallets MUST carefully consider errors for each of the coins as
returned by the exchange.
@@ -831,111 +837,6 @@ the contract. Refunds must be approved by the merchant's business logic.
}
-Picking up rewards
-------------------
-
-Rewards are a way for wallets to obtain e-cash from
-a website.
-
-.. http:get:: [/instances/$INSTANCE]/rewards/$REWARD_ID
-
- Handle request from wallet to provide details about a reward.
-
- This endpoint typically also supports requests with the "Accept" header
- requesting "text/html". In this case, an HTML response suitable for
- triggering the interaction with the wallet is returned. If the backend
- installation does not include the required HTML templates, a 406 status
- code is returned.
-
- **Response:**
-
- :http:statuscode:`200 OK`:
- A reward is being returned. The backend responds with a `RewardInformation`.
- :http:statuscode:`404 Not found`:
- The reward identifier is unknown.
- :http:statuscode:`406 Not acceptable`:
- The merchant backend could not load the template required to generate a reply in the desired format. (Likely HTML templates were not properly installed.)
- :http:statuscode:`410 Gone`:
- A reward has been fully claimed. The JSON reply still contains the `RewardInformation`.
-
- .. ts:def:: RewardInformation
-
- interface RewardInformation {
-
- // Exchange from which the reward will be withdrawn. Needed by the
- // wallet to determine denominations, fees, etc.
- exchange_url: string;
-
- // URL where to go after obtaining the reward.
- next_url: string;
-
- // (Remaining) amount of the reward (including fees).
- reward_amount: Amount;
-
- // Timestamp indicating when the reward is set to expire (may be in the past).
- // Note that rewards that have expired MAY also result in a 404 response.
- expiration: Timestamp;
- }
-
-
-.. http:post:: [/instances/$INSTANCE]/rewards/$REWARD_ID/pickup
-
- Handle request from wallet to pick up a reward.
-
- **Request:**
-
- The request body is a `RewardPickupRequest` object.
-
- **Response:**
-
- :http:statuscode:`200 OK`:
- A reward is being returned. The backend responds with a `RewardResponse`.
- :http:statuscode:`401 Unauthorized`:
- The reward amount requested exceeds the reward.
- :http:statuscode:`404 Not found`:
- The reward identifier is unknown.
- :http:statuscode:`409 Conflict`:
- Some of the denomination key hashes of the request do not match those currently available from the exchange (hence there is a conflict between what the wallet requests and what the merchant believes the exchange can provide).
- :http:statuscode:`410 Gone`:
- The reward has expired.
-
- .. ts:def:: RewardPickupRequest
-
- interface RewardPickupRequest {
-
- // List of planchets the wallet wants to use for the reward.
- planchets: PlanchetDetail[];
- }
-
- .. ts:def:: PlanchetDetail
-
- interface PlanchetDetail {
- // Hash of the denomination's public key (hashed to reduce
- // bandwidth consumption).
- denom_pub_hash: HashCode;
-
- // Coin's blinded public key.
- coin_ev: CoinEnvelope;
- }
-
- .. ts:def:: RewardResponse
-
- interface RewardResponse {
-
- // Blind RSA signatures over the planchets.
- // The order of the signatures matches the planchets list.
- blind_sigs: BlindSignature[];
- }
-
- .. ts:def:: BlindSignature
-
- interface BlindSignature {
-
- // The (blind) RSA signature. Still needs to be unblinded.
- blind_sig: BlindedRsaSignature;
- }
-
-
-------------------
Instance management
-------------------
@@ -1795,6 +1696,11 @@ Inspecting inventory
This is used to return the list of all items in the inventory.
+ **Request:**
+
+ :query limit: *Optional*. At most return the given number of results. Negative for descending by row ID, positive for ascending by row ID. Default is ``20``. Since protocol **v12**.
+ :query offset: *Optional*. Starting ``product_serial_id`` for an iteration. Since protocol **v12**.
+
**Response:**
:http:statuscode:`200 OK`:
@@ -1818,6 +1724,8 @@ Inspecting inventory
// Product identifier, as found in the product.
product_id: string;
+ // ``product_serial_id`` of the product in the database.
+ product_serial: integer;
}
@@ -2036,7 +1944,7 @@ Creating orders
// The session for which the payment is made (or replayed).
// Only set for session-based payments.
- // Since protocol v6.
+ // Since protocol **v6**.
session_id?: string;
// Specifies that some products are to be included in the
@@ -2082,14 +1990,14 @@ Creating orders
// Short summary of the order.
summary: string;
- // See documentation of fulfillment_url in ContractTerms.
+ // See documentation of fulfillment_url in `ContractTerms`.
// Either fulfillment_url or fulfillment_message must be specified.
// When creating an order, the fulfillment URL can
// contain ``${ORDER_ID}`` which will be substituted with the
// order ID of the newly created order.
fulfillment_url?: string;
- // See documentation of fulfillment_message in ContractTerms.
+ // See documentation of fulfillment_message in `ContractTerms`.
// Either fulfillment_url or fulfillment_message must be specified.
fulfillment_message?: string;
}
@@ -2165,12 +2073,14 @@ Inspecting orders
:query paid: *Optional*. If set to yes, only return paid orders, if no only unpaid orders. Do not give (or use "all") to see all orders regardless of payment status.
:query refunded: *Optional*. If set to yes, only return refunded orders, if no only unrefunded orders. Do not give (or use "all") to see all orders regardless of refund status.
:query wired: *Optional*. If set to yes, only return wired orders, if no only orders with missing wire transfers. Do not give (or use "all") to see all orders regardless of wire transfer status.
- :query delta: *Optional*. takes value of the form ``N (-N)``, so that at most ``N`` values strictly older (younger) than ``start`` and ``date_s`` are returned. Defaults to ``-20`` to return the last 20 entries (before ``start`` and/or ``date_s``).
+ :query delta: *Optional*. takes value of the form ``N (-N)``, so that at most ``N`` values strictly older (younger) than ``start`` and ``date_s`` are returned. Defaults to ``-20`` to return the last 20 entries (before ``start`` and/or ``date_s``). Deprecated in protocol **v12**. Use *limit* instead.
+ :query limit: *Optional*. At most return the given number of results. Negative for descending by row ID, positive for ascending by row ID. Default is ``20``. Since protocol **v12**.
:query date_s: *Optional.* Non-negative date in seconds after the UNIX Epoc, see ``delta`` for its interpretation. If not specified, we default to the oldest or most recent entry, depending on ``delta``.
- :query start: *Optional*. Row number threshold, see ``delta`` for its interpretation. Defaults to ``INT64_MAX``, namely the biggest row id possible in the database.
+ :query start: *Optional*. Row number threshold, see ``delta`` for its interpretation. Defaults to ``INT64_MAX``, namely the biggest row id possible in the database. Deprecated in protocol **v12**. Use *offset* instead.
+ :query offset: *Optional*. Starting ``product_serial_id`` for an iteration. Since protocol **v12**.
:query timeout_ms: *Optional*. Timeout in milliseconds to wait for additional orders if the answer would otherwise be negative (long polling). Only useful if delta is positive. Note that the merchant MAY still return a response that contains fewer than ``delta`` orders.
- :query session_id: *Optional*. Since protocol v6. Filters by session ID.
- :query fulfillment_url: *Optional*. Since protocol v6. Filters by fulfillment URL.
+ :query session_id: *Optional*. Since protocol **v6**. Filters by session ID.
+ :query fulfillment_url: *Optional*. Since protocol **v6**. Filters by fulfillment URL.
**Response:**
@@ -2227,8 +2137,9 @@ Inspecting orders
**Request:**
:query session_id: *Optional*. Session ID that the payment must be bound to. If not specified, the payment is not session-bound.
- :query transfer: *Deprecated in protocol V6*. *Optional*. If set to "YES", try to obtain the wire transfer status for this order from the exchange. Otherwise, the wire transfer status MAY be returned if it is available.
+ :query transfer: Deprecated in protocol **V6**. *Optional*. If set to "YES", try to obtain the wire transfer status for this order from the exchange. Otherwise, the wire transfer status MAY be returned if it is available.
:query timeout_ms: *Optional*. Timeout in milliseconds to wait for a payment if the answer would otherwise be negative (long polling).
+ :query allow_refunded_for_repurchase: *Optional*. Since protocol **v9** refunded orders are only returned under "already_paid_order_id" if this flag is set explicitly to "YES".
**Response:**
@@ -2291,7 +2202,7 @@ Inspecting orders
// Reports about trouble obtaining wire transfer details,
// empty array if no trouble were encountered.
- // @deprecated in protocol v6
+ // @deprecated in protocol **v6**.
wire_reports: TransactionWireReport[];
// The refund details for this order. One entry per
@@ -2692,418 +2603,6 @@ once we got a reply from the exchange.
The transfer cannot be deleted anymore.
------------------------
-Backend: Giving rewards
------------------------
-
-Rewards are a way for websites to give small amounts of e-cash to visitors (for
-example as a financial reward for providing information or viewing
-advertisements). Rewards are non-contractual: neither merchant nor consumer
-have any contractual information about the other party as a result of the
-reward.
-
-
-Create reserve
---------------
-
-Reserves are basically funds a merchant has provided to an exchange for a
-rewards campaign. Each reserve has a limited lifetime (say 2--4 weeks). Any
-funds not used to reward customers will automatically be wired back from the
-exchange to the originating account.
-
-Before handing out rewards, a merchant must tell the backend to set up a
-reserve. The backend will return a reserve public key which must be used as
-the wire transfer subject when wiring the reward campaign funds to the
-exchange.
-
-.. _rewards:
-.. http:post:: [/instances/$INSTANCE]/private/reserves
-
- Create a reserve for rewards.
-
- This request is **not** idempotent. However, while repeating
- it will create another reserve, that is generally pretty harmless
- (assuming only one of the reserves is filled with a wire transfer).
- Clients may want to eventually delete the unused reserves to
- avoid clutter.
-
- **Request:**
-
- The request body is a `ReserveCreateRequest` object.
-
- **Response:**
-
- :http:statuscode:`200 OK`:
- The backend is waiting for the reserve to be established. The merchant
- must now perform the wire transfer indicated in the `ReserveCreateConfirmation`.
- :http:statuscode:`408 Request timeout`:
- The exchange did not respond on time.
- :http:statuscode:`409 Conflict`:
- The exchange does not support the requested wire method or does not allow rewards.
- :http:statuscode:`502 Bad gateway`:
- We could not obtain ``/wire`` details from the specified exchange base URL.
- :http:statuscode:`504 Gateway timeout`:
- The merchant's interaction with the exchange took too long.
- The client might want to try again later.
-
- .. ts:def:: ReserveCreateRequest
-
- interface ReserveCreateRequest {
- // Amount that the merchant promises to put into the reserve.
- initial_balance: Amount;
-
- // Exchange the merchant intends to use for rewards.
- exchange_url: string;
-
- // Desired wire method, for example "iban" or "x-taler-bank".
- wire_method: string;
- }
-
- .. ts:def:: ReserveCreateConfirmation
-
- interface ReserveCreateConfirmation {
- // Public key identifying the reserve.
- reserve_pub: EddsaPublicKey;
-
- // Wire accounts of the exchange where to transfer the funds.
- accounts: WireAccount[];
- }
-
-.. http:get:: [/instances/$INSTANCE]/private/reserves
-
- Obtain list of reserves that have been created for rewards.
-
- **Request:**
-
- :query after: *Optional*. Only return reserves created after the given timestamp in milliseconds.
- :query active: *Optional*. Only return active/inactive reserves depending on the boolean given.
- :query failures: *Optional*. Only return reserves where we disagree with the exchange about the initial balance.
-
- **Response:**
-
- :http:statuscode:`200 OK`:
- Returns a list of known reward reserves.
- The body is a `RewardReserveStatus`.
-
- .. ts:def:: RewardReserveStatus
-
- interface RewardReserveStatus {
- // Array of all known reserves (possibly empty!).
- reserves: ReserveStatusEntry[];
- }
-
- .. ts:def:: ReserveStatusEntry
-
- interface ReserveStatusEntry {
- // Public key of the reserve.
- reserve_pub: EddsaPublicKey;
-
- // Timestamp when it was established.
- creation_time: Timestamp;
-
- // Timestamp when it expires.
- expiration_time: Timestamp;
-
- // Initial amount as per reserve creation call.
- merchant_initial_amount: Amount;
-
- // Initial amount as per exchange, 0 if exchange did
- // not confirm reserve creation yet.
- exchange_initial_amount: Amount;
-
- // Amount picked up so far.
- pickup_amount: Amount;
-
- // Amount approved for rewards that exceeds the pickup_amount.
- committed_amount: Amount;
-
- // Is this reserve active (false if it was deleted but not purged)?
- active: boolean;
- }
-
-
-Query funds remaining
----------------------
-
-.. http:get:: [/instances/$INSTANCE]/private/reserves/$RESERVE_PUB
-
- Obtain information about a specific reserve that have been created for rewards.
-
- **Request:**
-
- :query rewards: *Optional*. If set to "yes", returns also information about all of the rewards created.
-
- **Response:**
-
- :http:statuscode:`200 OK`:
- Returns the `ReserveDetail`.
- :http:statuscode:`404 Not found`:
- The reward reserve is not known.
- :http:statuscode:`502 Bad gateway`:
- We are having trouble with the request because of a problem with the exchange.
- Likely returned with an "exchange_code" in addition to a "code" and
- an "exchange_http_status" in addition to our own HTTP status. Also usually
- includes the full exchange reply to our request under "exchange_reply".
- This is only returned if there was actual trouble with the exchange, not
- if the exchange merely did not respond yet or if it responded that the
- reserve was not yet filled.
- :http:statuscode:`504 Gateway timeout`:
- The merchant's interaction with the exchange took too long.
- The client might want to try again later.
-
- .. ts:def:: ReserveDetail
-
- interface ReserveDetail {
- // Timestamp when it was established.
- creation_time: Timestamp;
-
- // Timestamp when it expires.
- expiration_time: Timestamp;
-
- // Initial amount as per reserve creation call.
- merchant_initial_amount: Amount;
-
- // Initial amount as per exchange, 0 if exchange did
- // not confirm reserve creation yet.
- exchange_initial_amount: Amount;
-
- // Amount picked up so far.
- pickup_amount: Amount;
-
- // Amount approved for rewards that exceeds the pickup_amount.
- committed_amount: Amount;
-
- // Array of all rewards created by this reserves (possibly empty!).
- // Only present if asked for explicitly.
- rewards?: RewardStatusEntry[];
-
- // Is this reserve active (false if it was deleted but not purged)?
- active: boolean;
-
- // Array of wire accounts of the exchange that could
- // be used to fill the reserve, can be NULL
- // if the reserve is inactive or was already filled
- accounts?: WireAccount[];
-
- // URL of the exchange hosting the reserve,
- // NULL if the reserve is inactive
- exchange_url: string;
- }
-
- .. ts:def:: RewardStatusEntry
-
- interface RewardStatusEntry {
-
- // Unique identifier for the reward.
- reward_id: HashCode;
-
- // Total amount of the reward that can be withdrawn.
- total_amount: Amount;
-
- // Human-readable reason for why the reward was granted.
- reason: string;
- }
-
-
-Authorizing rewards
--------------------
-
-.. http:post:: [/instances/$INSTANCE]/private/reserves/$RESERVE_PUB/authorize-reward
-
- Authorize creation of a reward from the given reserve.
-
- **Request:**
-
- The request body is a `RewardCreateRequest` object.
-
- **Response:**
-
- :http:statuscode:`200 OK`:
- A reward has been created. The backend responds with a `RewardCreateConfirmation`.
- :http:statuscode:`404 Not found`:
- The instance or the reserve is unknown to the backend.
- :http:statuscode:`412 Precondition failed`:
- The reward amount requested exceeds the available reserve balance for rewards.
-
- .. ts:def:: RewardCreateRequest
-
- interface RewardCreateRequest {
- // Amount that the customer should be rewarded.
- amount: Amount;
-
- // Justification for giving the reward.
- justification: string;
-
- // URL that the user should be directed to after receiving the reward,
- // will be included in the reward_token.
- next_url: string;
- }
-
- .. ts:def:: RewardCreateConfirmation
-
- interface RewardCreateConfirmation {
- // Unique reward identifier for the reward that was created.
- reward_id: HashCode;
-
- // taler://reward URI for the reward.
- taler_reward_uri: string;
-
- // URL that will directly trigger processing
- // the reward when the browser is redirected to it.
- reward_status_url: string;
-
- // When does the reward expire?
- reward_expiration: Timestamp;
- }
-
-
-.. http:post:: [/instances/$INSTANCE]/private/rewards
-
- Authorize creation of a reward, with
- automatic selection of a working reserve of the instance by the
- backend. Intentionally otherwise identical to the ``/authorize-reward``
- endpoint given above.
-
- **Request:**
-
- The request body is a `RewardCreateRequest` object.
-
- **Response:**
-
- :http:statuscode:`200 OK`:
- A reward has been created. The backend responds with a `RewardCreateConfirmation`.
- :http:statuscode:`404 Not found`:
- The instance is unknown to the backend.
- :http:statuscode:`412 Precondition failed`:
- The reward amount requested exceeds the available reserve balance for rewards
- in all of the reserves of the instance.
-
-
-Deleting reserves
------------------
-
-.. http:delete:: [/instances/$INSTANCE]/private/reserves/$RESERVE_PUB
-
- Delete information about a reserve. Fails if the reserve still has
- committed to rewards that were not yet picked up and that have not yet
- expired.
-
- **Request:**
-
- :query purge: *Optional*. If set to YES, the reserve and all information
- about rewards it issued will be fully deleted.
- Otherwise only the private key would be deleted.
-
- **Response:**
-
- :http:statuscode:`204 No content`:
- The backend has successfully deleted the reserve.
- :http:statuscode:`404 Not found`:
- The backend does not know the instance or the reserve.
- :http:statuscode:`409 Conflict`:
- The backend refuses to delete the reserve (committed rewards awaiting pickup).
-
-
-Checking reward status
-----------------------
-
-.. http:get:: [/instances/$INSTANCE]/private/rewards/$REWARD_ID
-
- Obtain information about a particular reward.
-
- **Request:**
-
- :query pickups: *Optional*. If set to "yes", returns also information about all of the pickups.
- :query min_amount: *Optional*. Minimum pick-up amount the client is interested in.
- :query timeout_ms=NUMBER: *Optional.* If specified, the merchant backend will
- wait up to ``timeout_ms`` milliseconds for rewards of at least min_pick_up to be
- picked up. A client must never rely on this behavior, as the
- merchant backend may return a response immediately.
-
- **Response:**
-
- :http:statuscode:`200 OK`:
- The reward is known. The backend responds with a `RewardDetails` message.
- :http:statuscode:`404 Not found`:
- The reward is unknown to the backend.
-
- .. ts:def:: RewardDetails
-
- interface RewardDetails {
- // Amount that we authorized for this reward.
- total_authorized: Amount;
-
- // Amount that was picked up by the user already.
- total_picked_up: Amount;
-
- // Human-readable reason given when authorizing the reward.
- reason: string;
-
- // Timestamp indicating when the reward is set to expire (may be in the past).
- expiration: Timestamp;
-
- // Reserve public key from which the reward is funded.
- reserve_pub: EddsaPublicKey;
-
- // Array showing the pickup operations of the wallet (possibly empty!).
- // Only present if asked for explicitly.
- pickups?: PickupDetail[];
- }
-
- .. ts:def:: PickupDetail
-
- interface PickupDetail {
- // Unique identifier for the pickup operation.
- pickup_id: HashCode;
-
- // Number of planchets involved.
- num_planchets: Integer;
-
- // Total amount requested for this pickup_id.
- requested_amount: Amount;
- }
-
-
-.. http:get:: [/instances/$INSTANCE]/private/rewards
-
- Return the list of all rewards.
-
- **Request:**
-
- :query include_expired: *Optional*. If set to "yes", the result includes expired rewards also. Otherwise, only active rewards are returned.
-
- :query limit: *Optional*. At most return the given number of results. Negative for descending in database row id, positive for ascending in database row id.
-
- :query offset: *Optional*. Starting ``row_id`` for an iteration.
-
- **Response:**
-
- :http:statuscode:`200 OK`:
- The backend has successfully found the list of rewards. The backend responds
- with a `RewardsResponse`.
-
- .. ts:def:: RewardsResponse
-
- interface RewardsResponse {
-
- // List of rewards that are present in the backend.
- rewards: Reward[];
- }
-
- .. ts:def:: Reward
-
- interface Reward {
-
- // ID of the reward in the backend database.
- row_id: number;
-
- // Unique identifier for the reward.
- reward_id: HashCode;
-
- // (Remaining) amount of the reward (including fees).
- reward_amount: Amount;
- }
-
-----------
OTP Devices
-----------
@@ -3137,11 +2636,19 @@ to validate that a customer made a payment.
// Human-readable description for the device.
otp_device_description: string;
- // A base64-encoded key
+ // A key encoded with RFC 3548 Base32.
+ // IMPORTANT: This is not using the typical
+ // Taler base32-crockford encoding.
+ // Instead it uses the RFC 3548 encoding to
+ // be compatible with the TOTP standard.
otp_key: string;
// Algorithm for computing the POS confirmation.
- otp_algorithm: Integer;
+ // "NONE" or 0: No algorithm (no pos confirmation will be generated)
+ // "TOTP_WITHOUT_PRICE" or 1: Without amounts (typical OTP device)
+ // "TOTP_WITH_PRICE" or 2: With amounts (special-purpose OTP device)
+ // The "String" variants are supported @since protocol **v7**.
+ otp_algorithm: Integer | string;
// Counter for counter-based OTP devices.
otp_ctr?: Integer;
@@ -3173,8 +2680,12 @@ to validate that a customer made a payment.
// Human-readable description for the device.
otp_device_description: string;
- // A base64-encoded key
- otp_key: string;
+ // A key encoded with RFC 3548 Base32.
+ // IMPORTANT: This is not using the typical
+ // Taler base32-crockford encoding.
+ // Instead it uses the RFC 3548 encoding to
+ // be compatible with the TOTP standard.
+ otp_key?: string;
// Algorithm for computing the POS confirmation.
otp_algorithm: Integer;
@@ -3218,6 +2729,17 @@ to validate that a customer made a payment.
This is used to obtain detailed information about a specific OTP device.
+ The client can provide additional inputs in the query to allow the backend
+ to compute and return a sample OTP code. Note that it is not an error if
+ the client provides query arguments that are not being used *or* that are
+ insufficient for the server to compute the ``otp_code``: If the client
+ provides inadequate query parameters, the ``otp_code`` is simply omitted
+ from the response.
+
+ **Query:**
+
+ :query faketime=TIMESTAMP: *Optional*. Timestamp in seconds to use when calculating the current OTP code of the device. Since protocol **v10**.
+ :query price=AMOUNT: *Optional*. Price to use when calculating the current OTP code of the device. Since protocol **v10**.
**Response:**
@@ -3235,11 +2757,49 @@ to validate that a customer made a payment.
device_description: string;
// Algorithm for computing the POS confirmation.
+ //
+ // Currently, the following numbers are defined:
+ // 0: None
+ // 1: TOTP without price
+ // 2: TOTP with price
otp_algorithm: Integer;
// Counter for counter-based OTP devices.
otp_ctr?: Integer;
+ // Current time for time-based OTP devices.
+ // Will match the ``faketime`` argument of the
+ // query if one was present, otherwise the current
+ // time at the backend.
+ //
+ // Available since protocol **v10**.
+ otp_timestamp: Integer;
+
+ // Current OTP confirmation string of the device.
+ // Matches exactly the string that would be returned
+ // as part of a payment confirmation for the given
+ // amount and time (so may contain multiple OTP codes).
+ //
+ // If the ``otp_algorithm`` is time-based, the code is
+ // returned for the current time, or for the ``faketime``
+ // if a TIMESTAMP query argument was provided by the client.
+ //
+ // When using OTP with counters, the counter is **NOT**
+ // increased merely because this endpoint created
+ // an OTP code (this is a GET request, after all!).
+ //
+ // If the ``otp_algorithm`` requires an amount, the
+ // ``amount`` argument must be specified in the
+ // query, otherwise the ``otp_code`` is not
+ // generated.
+ //
+ // This field is *optional* in the response, as it is
+ // only provided if we could compute it based on the
+ // ``otp_algorithm`` and matching client query arguments.
+ //
+ // Available since protocol **v10**.
+ otp_code?: string;
+
}
.. http:delete:: [/instances/$INSTANCE]/private/otp-devices/$DEVICE_ID
@@ -3335,9 +2895,27 @@ Adding templates
// This parameter is optional.
otp_id?: string;
- // Additional information in a separate template.
+ // Fixed contract information for orders created from
+ // this template.
template_contract: TemplateContractDetails;
- }
+
+ // Key-value pairs matching a subset of the
+ // fields from `template_contract` that are
+ // user-editable defaults for this template.
+ // Since protocol **v13**.
+ editable_defaults?: Object;
+
+ // Required currency for payments. Useful if no
+ // amount is specified in the `template_contract`
+ // but the user should be required to pay in a
+ // particular currency anyway. Merchant backends
+ // may reject requests if the `template_contract`
+ // or `editable_defaults` do
+ // specify an amount in a different currency.
+ // This parameter is optional.
+ // Since protocol **v13**.
+ required_currency?: string;
+ }
.. ts:def:: TemplateContractDetails
@@ -3497,6 +3075,30 @@ Removing template
Using template
----------------
+.. http:get:: [/instances/$INSTANCE]/templates/$TEMPLATE_ID
+
+ This is used to obtain information about a specific template by wallets
+ before they ask the user to fill in details.
+ This endpoint is available since protocol **v11**.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The backend has successfully returned the detailed information about a specific template.
+ Returns a `WalletTemplateDetails`.
+ :http:statuscode:`404 Not found`:
+ The instance or template(ID) is unknown to the backend.
+
+ .. ts:def:: WalletTemplateDetails
+
+ interface WalletTemplateDetails {
+
+ // Hard-coded information about the contrac terms
+ // for this template.
+ template_contract: TemplateContractDetails;
+ }
+
+
.. http:post:: [/instances/$INSTANCES]/templates/$TEMPLATE_ID
This using template can be modified by everyone and will be used to create order.
@@ -3552,7 +3154,7 @@ Adding webhooks
The creation of the webhook is successsful.
:http:statuscode:`404 Not found`:
- The merchant instance is unknowm or it not in our data.
+ The merchant instance is unknown or it not in our data.
.. ts:def:: WebhookAddDetails
@@ -3713,6 +3315,242 @@ Removing webhook
+----------------------------------------
+Token Families: Subscriptions, Discounts
+----------------------------------------
+
+This API provides functionalities for the issuance, management, and revocation
+of token families. Tokens facilitate the implementation of subscriptions and
+discounts, engaging solely the merchant and the user. Each token family
+encapsulates details pertaining to its respective tokens, guiding the merchant's
+backend on the appropriate processing and handling.
+
+
+Creating token families
+-----------------------
+
+.. http:post:: [/instances/$INSTANCES]/private/tokenfamilies
+
+ This is used to create a token family.
+
+ **Request:**
+
+ The request must be a `TokenFamilyCreateRequest`.
+
+ **Response:**
+
+ :http:statuscode:`204 No content`:
+ The token family was created successfully.
+
+ :http:statuscode:`404 Not found`:
+ The merchant backend is unaware of the instance.
+
+ .. ts:def:: TokenFamilyCreateRequest
+
+ interface TokenFamilyCreateRequest {
+
+ // Identifier for the token family consisting of unreserved characters
+ // according to RFC 3986.
+ slug: string;
+
+ // Human-readable name for the token family.
+ name: string;
+
+ // Human-readable description for the token family.
+ description: string;
+
+ // Optional map from IETF BCP 47 language tags to localized descriptions.
+ description_i18n?: { [lang_tag: string]: string };
+
+ // Start time of the token family's validity period.
+ // If not specified, merchant backend will use the current time.
+ valid_after?: Timestamp;
+
+ // End time of the token family's validity period.
+ valid_before: Timestamp;
+
+ // Validity duration of an issued token.
+ duration: RelativeTime;
+
+ // Kind of the token family.
+ kind: TokenFamilyKind;
+
+ }
+
+ .. ts:def:: TokenFamilyKind
+
+ enum TokenFamilyKind {
+ Discount = "discount",
+ Subscription = "subscription",
+ }
+
+
+Updating token families
+-----------------------
+
+.. http:patch:: [/instances/$INSTANCES]/private/tokenfamilies/$TOKEN_FAMILY_SLUG
+
+ This is used to update a token family.
+
+ **Request:**
+
+ The request must be a `TokenFamilyUpdateRequest`.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The token family was successsful updated. Returns a `TokenFamilyDetails`.
+
+ :http:statuscode:`404 Not found`:
+ The merchant backend is unaware of the token family or instance.
+
+ .. ts:def:: TokenFamilyUpdateRequest
+
+ interface TokenFamilyUpdateRequest {
+
+ // Human-readable name for the token family.
+ name: string;
+
+ // Human-readable description for the token family.
+ description: string;
+
+ // Optional map from IETF BCP 47 language tags to localized descriptions.
+ description_i18n: { [lang_tag: string]: string };
+
+ // Start time of the token family's validity period.
+ valid_after: Timestamp;
+
+ // End time of the token family's validity period.
+ valid_before: Timestamp;
+
+ // Validity duration of an issued token.
+ duration: RelativeTime;
+
+ }
+
+
+
+Inspecting token families
+-------------------------
+
+.. http:get:: [/instances/$INSTANCES]/private/tokenfamilies
+
+ This is used to list all configured token families for an instance.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The merchant backend has successfully returned all token families.
+ Returns a `TokenFamiliesList`.
+
+ :http:statuscode:`404 Not found`:
+ The merchant backend is unaware of the instance.
+
+ .. ts:def:: TokenFamiliesList
+
+ // TODO: Add pagination
+
+ interface TokenFamiliesList {
+
+ // All configured token families of this instance.
+ token_families: TokenFamilySummary[];
+
+ }
+
+ .. ts:def:: TokenFamilySummary
+
+ interface TokenFamilySummary {
+ // Identifier for the token family consisting of unreserved characters
+ // according to RFC 3986.
+ slug: string;
+
+ // Human-readable name for the token family.
+ name: string;
+
+ // Start time of the token family's validity period.
+ valid_after: Timestamp;
+
+ // End time of the token family's validity period.
+ valid_before: Timestamp;
+
+ // Kind of the token family.
+ kind: TokenFamilyKind;
+ }
+
+
+.. http:get:: [/instances/$INSTANCES]/private/tokenfamilies/$TOKEN_FAMILY_SLUG
+
+ This is used to get detailed information about a specific token family.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The merchant backend has successfully returned the detailed information
+ about a specific token family. Returns a `TokenFamilyDetails`.
+
+ :http:statuscode:`404 Not found`:
+ The merchant backend is unaware of the token family or instance.
+
+
+ The `TokenFamilyDetails` object describes a configured token family.
+
+ .. ts:def:: TokenFamilyDetails
+
+ interface TokenFamilyDetails {
+
+ // Identifier for the token family consisting of unreserved characters
+ // according to RFC 3986.
+ slug: string;
+
+ // Human-readable name for the token family.
+ name: string;
+
+ // Human-readable description for the token family.
+ description: string;
+
+ // Optional map from IETF BCP 47 language tags to localized descriptions.
+ description_i18n?: { [lang_tag: string]: string };
+
+ // Start time of the token family's validity period.
+ valid_after: Timestamp;
+
+ // End time of the token family's validity period.
+ valid_before: Timestamp;
+
+ // Validity duration of an issued token.
+ duration: RelativeTime;
+
+ // Kind of the token family.
+ kind: TokenFamilyKind;
+
+ // How many tokens have been issued for this family.
+ issued: Integer;
+
+ // How many tokens have been redeemed for this family.
+ redeemed: Integer;
+
+ }
+
+
+
+Deleting token families
+-----------------------
+
+.. http:delete:: [/instances/$INSTANCES]/private/tokenfamilies/$TOKEN_FAMILY_SLUG
+
+ This is used to delete a token family. Issued tokens of this family will not
+ be spendable anymore.
+
+ **Response:**
+
+ :http:statuscode:`204 No content`:
+ The backend has successfully deleted the token family.
+
+ :http:statuscode:`404 Not found`:
+ The merchant backend is unaware of the token family or instance.
+
+
+
------------------
The Contract Terms
------------------
@@ -3754,13 +3592,26 @@ The contract terms must have the following structure:
public_reorder_url?: string;
// URL that will show that the order was successful after
- // it has been paid for. Optional. When POSTing to the
- // merchant, the placeholder "${ORDER_ID}" will be
- // replaced with the actual order ID (useful if the
+ // it has been paid for. Optional, but either ``fulfillment_url``
+ // or ``fulfillment_message`` must be specified in every
+ // contract terms.
+ //
+ // If a non-unique fulfillment URL is used, a customer can only
+ // buy the order once and will be redirected to a previous purchase
+ // when trying to buy an order with the same fulfillment URL a second
+ // time. This is useful for digital goods that a customer only needs
+ // to buy once but should be able to repeatedly download.
+ //
+ // For orders where the customer is expected to be able to make
+ // repeated purchases (for equivalent goods), the fulfillment URL
+ // should be made unique for every order. The easiest way to do
+ // this is to include a unique order ID in the fulfillment URL.
+ //
+ // When POSTing to the merchant, the placeholder text "${ORDER_ID}"
+ // is be replaced with the actual order ID (useful if the
// order ID is generated server-side and needs to be
- // in the URL).
- // Note that this placeholder can only be used once.
- // Either fulfillment_url or fulfillment_message must be specified.
+ // in the URL). Note that this placeholder can only be used once.
+ // Front-ends may use other means to generate a unique fulfillment URL.
fulfillment_url?: string;
// Message shown to the customer after paying for the order.