aboutsummaryrefslogtreecommitdiff
path: root/core/api-merchant.rst
diff options
context:
space:
mode:
Diffstat (limited to 'core/api-merchant.rst')
-rw-r--r--core/api-merchant.rst664
1 files changed, 586 insertions, 78 deletions
diff --git a/core/api-merchant.rst b/core/api-merchant.rst
index 6682ac17..325b4b36 100644
--- a/core/api-merchant.rst
+++ b/core/api-merchant.rst
@@ -123,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 **v14**.
+ This specification corresponds to ``current`` protocol being version **v16**.
**Response:**
@@ -342,6 +342,11 @@ Making the payment
// payment.
pos_confirmation?: string;
+ // Signed tokens. Returned in the same order as the
+ // token envelopes were provided in the request.
+ // @since protocol **vSUBSCRIBE**
+ token_sigs?: SignedTokenEnvelope[];
+
}
.. ts:def:: PayRequest
@@ -350,11 +355,6 @@ Making the payment
// The coins used to make the payment.
coins: CoinPaySig[];
- // Index of the selected choice within the ``choices`` array of
- // the contract terms.
- // @since protocol **vSUBSCRIBE**
- choice_index?: Integer;
-
// Input tokens required by choice indicated by ``choice_index``.
// @since protocol **vSUBSCRIBE**
tokens?: TokenUseSig[];
@@ -365,7 +365,7 @@ Making the payment
tokens_evs?: TokenEnvelope[];
// Custom inputs from the wallet for the contract.
- wallet_data?: Object;
+ wallet_data?: PayWalletData;
// The session for which the payment is made (or replayed).
// Only set for session-based payments.
@@ -373,9 +373,59 @@ Making the payment
}
+ .. ts:def:: SignedTokenEnvelope
+
+ interface SignedTokenEnvelope {
+
+ // Blind signature made by the merchant.
+ blind_sig: TokenIssueBlindSig;
+
+ }
+
+ .. ts:def:: TokenIssueBlindSig
+
+ type TokenIssueBlindSig = RSATokenIssueBlindSig | CSTokenIssueBlindSig;
+
+ .. ts:def:: RSATokenIssueBlindSig
+
+ interface RSATokenIssueBlindSig {
+ cipher: "RSA";
+
+ // (blinded) RSA signature
+ blinded_rsa_signature: BlindedRsaSignature;
+ }
+
+ .. ts:def:: CSTokenIssueBlindSig
+
+ interface CSTokenIssueBlindSig {
+ cipher: "CS";
+
+ // Signer chosen bit value, 0 or 1, used
+ // in Clause Blind Schnorr to make the
+ // ROS problem harder.
+ b: Integer;
+
+ // Blinded scalar calculated from c_b.
+ s: Cs25519Scalar;
+
+ }
+
+ .. ts:def:: PayWalletData
+
+ interface PayWalletData {
+ // Index of the selected choice within the ``choices`` array of
+ // the contract terms.
+ // @since protocol **vSUBSCRIBE**
+ choice_index?: Integer;
+
+ // Output commitment. Hash over output token envelopes.
+ // @since protocol **vSUBSCRIBE**
+ h_outputs?: HashCode;
+ }
+
.. ts:def:: CoinPaySig
- export interface CoinPaySig {
+ interface CoinPaySig {
// Signature by the coin.
coin_sig: EddsaSignature;
@@ -418,19 +468,17 @@ Making the payment
interface TokenUseSig {
- // Signature on ``TALER_DepositRequestPS`` with the public key of the
- // token being provisioned to the merchant.
+ // Signature on ``TALER_TokenUseRequestPS`` with the token use key of
+ // the token being used in this request.
token_sig: EddsaSignature;
- // Public key of the token being provisioned to the merchant.
+ // Token use public key.
token_pub: EddsaPublicKey;
- // Unblinded signature made by the token family public key of the merchant.
+ // Unblinded signature on ``TALER_TokenIssueRequestPS`` with the token
+ // issue public key of the merchant.
ub_sig: UnblindedSignature;
- // The hash of the token family public key associated with this token.
- h_denom: HashCode;
-
}
.. ts:def:: TokenEnvelope
@@ -525,7 +573,7 @@ Querying payment status
.. ts:def:: StatusPaidResponse
- interface StatusPaid {
+ interface StatusPaidResponse {
// Was the payment refunded (even partially, via refund or abort)?
refunded: boolean;
@@ -1635,9 +1683,165 @@ Taler merchant backend to process payments *without* using its inventory
management.
+Managing product categories
+---------------------------
+
+.. http:get:: [/instances/$INSTANCE]/private/categories
+
+ This request returns the known product categories
+ and the number of products in each category.
+ Since API version **v16**.
+
+ **Response:**
+
+ :http:statuscode:`200 Ok`:
+ The body is a `CategoryListResponse`.
+
+ **Details:**
+
+ .. ts:def:: CategoryListResponse
+
+ interface CategoryListResponse {
+
+ // Array with all of the categories we know.
+ categories: CategoryListEntry[];
+
+ }
+
+ .. ts:def:: CategoryListEntry
+
+ interface CategoryListEntry {
+
+ // Unique number for the category.
+ category_id: Integer;
+
+ // Name of the category.
+ name: string;
+
+ // Translations of the name into various
+ // languages.
+ name_i18n?: { [lang_tag: string]: string };
+
+ // Number of products in this category.
+ // A product can be in more than one category.
+ product_count: Integer;
+
+ }
+
+.. http:get:: [/instances/$INSTANCE]/private/categories/$CATEGORY_ID
+
+ This request returns the known products in the given
+ category.
+ Since API version **v16**.
+
+ **Response:**
+
+ :http:statuscode:`200 Ok`:
+ The body is a `CategoryProductList`.
+
+ **Details:**
+
+ .. ts:def:: CategoryProductList
+
+ interface CategoryProductList {
+
+ // Name of the category.
+ name: string;
+
+ // Translations of the name into various
+ // languages.
+ name_i18n?: { [lang_tag: string]: string };
+
+ // The products in this category.
+ products: ProductSummary[];
+
+ }
+
+ .. ts:def:: ProductSummary
+
+ interface ProductSummary {
+
+ // Product ID to use.
+ product_id: string;
+
+ // Human-readable product description.
+ description: string;
+
+ // Map from IETF BCP 47 language tags to localized descriptions.
+ description_i18n?: { [lang_tag: string]: string };
+
+ }
+
+
+.. http:post:: [/instances/$INSTANCE]/private/categories
+
+ This is used to create a new category for the inventory.
+ Since API version **v16**.
+
+ **Request:**
+
+ The request is a `CategoryCreateRequest`.
+
+ **Response:**
+
+ :http:statuscode:`200 Ok`:
+ The response is a `CategoryCreatedResponse`.
+
+ **Details:**
+
+ .. ts:def:: CategoryCreateRequest
+
+ interface CategoryCreateRequest {
+
+ // Name of the category.
+ name: string;
+
+ // Translations of the name into various
+ // languages.
+ name_i18n?: { [lang_tag: string]: string };
+
+ }
+
+ .. ts:def:: CategoryCreatedResponse
+
+ interface CategoryCreatedResponse {
+
+ // Number of the newly created category.
+ category_id: Integer;
+ }
+
+
+.. http:patch:: [/instances/$INSTANCE]/private/categories/$CATEGORY_ID
+
+ This is used to edit a category.
+ Since API version **v16**.
+
+ **Request:**
+
+ The request is a `CategoryCreateRequest`.
+
+ **Response:**
+
+ :http:statuscode:`204 No Content`:
+ The category was modified successfully.
+
+.. http:delete:: [/instances/$INSTANCE]/private/categories/$CATEGORY_ID
+
+ This is used to delete a category.
+ Since API version **v16**.
+
+ **Response:**
+
+ :http:statuscode:`204 No Content`:
+ The category was deleted.
+ :http:statuscode:`404 Not Found`:
+ The category was possibly already deleted or is unknown.
+
+
Adding products to the inventory
--------------------------------
+
.. http:post:: [/instances/$INSTANCE]/private/products
This is used to add a product to the inventory.
@@ -1653,6 +1857,7 @@ Adding products to the inventory
:http:statuscode:`409 Conflict`:
The backend already knows a product with this product ID, but with different details.
+ **Details:**
.. ts:def:: ProductAddDetail
@@ -1667,6 +1872,11 @@ Adding products to the inventory
// Map from IETF BCP 47 language tags to localized descriptions.
description_i18n?: { [lang_tag: string]: string };
+ // Categories into which the product belongs.
+ // Used in the POS-endpoint.
+ // Since API version **v16**.
+ categories?: Integer[];
+
// Unit in which the product is measured (liters, kilograms, packages, etc.).
unit: string;
@@ -1742,6 +1952,11 @@ Adding products to the inventory
// Unit in which the product is measured (liters, kilograms, packages, etc.).
unit: string;
+ // Categories into which the product belongs.
+ // Used in the POS-endpoint.
+ // Since API version **v16**.
+ categories?: Integer[];
+
// The price for one ``unit`` of the product. Zero is used
// to imply that this product is not sold separately, or
// that the price is not fixed, and must be supplied by the
@@ -1812,6 +2027,9 @@ Inspecting inventory
// ``product_serial_id`` of the product in the database.
product_serial: Integer;
+
+ // TODO: also return description/description_i18n here?
+ // TODO: what's the point in returning product_serial?
}
@@ -1840,6 +2058,10 @@ Inspecting inventory
// Unit in which the product is measured (liters, kilograms, packages, etc.).
unit: string;
+ // Categories into which the product belongs.
+ // Since API version **v16**.
+ categories: Integer[];
+
// The price for one ``unit`` of the product. Zero is used
// to imply that this product is not sold separately, or
// that the price is not fixed, and must be supplied by the
@@ -1851,7 +2073,8 @@ Inspecting inventory
image: ImageDataUrl;
// A list of taxes paid by the merchant for one unit of this product.
- taxes: Tax[];
+ // Optional since **v15**.
+ taxes?: Tax[];
// Number of units of the product in stock in sum in total,
// including all existing sales ever. Given in product-specific
@@ -1866,7 +2089,8 @@ Inspecting inventory
total_lost: Integer;
// Identifies where the product is in stock.
- address: Location;
+ // Optional since **v15**.
+ address?: Location;
// Identifies when we expect the next restocking to happen.
next_restock?: Timestamp;
@@ -1876,6 +2100,93 @@ Inspecting inventory
}
+.. http:get:: [/instances/$INSTANCE]/private/pos
+
+ This is used to return the point-of-sale (POS) configuration with full details on all items in the inventory.
+
+ Endpoint was introduced in protocol **v15**.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The backend has successfully returned the inventory. Returns
+ a `FullInventoryDetailsResponse`.
+ :http:statuscode:`404 Not found`:
+ The backend has does not know about the instance.
+
+ .. ts:def:: FullInventoryDetailsResponse
+
+ interface FullInventoryDetailsResponse {
+
+ // List of products that are present in the inventory.
+ products: MerchantPosProductDetail[];
+
+ // List of categories in the inventory.
+ categories: MerchantCategory[];
+
+ }
+
+ .. ts:def:: MerchantPosProductDetail
+
+ interface MerchantPosProductDetail {
+
+ // A unique numeric ID of the product
+ product_serial: number;
+
+ // A merchant-internal unique identifier for the product
+ product_id?: string;
+
+ // A list of category IDs this product belongs to.
+ // Typically, a product only belongs to one category, but more than one is supported.
+ categories: number[];
+
+ // Human-readable product description.
+ description: string;
+
+ // Map from IETF BCP 47 language tags to localized descriptions.
+ description_i18n: { [lang_tag: string]: string };
+
+ // Unit in which the product is measured (liters, kilograms, packages, etc.).
+ unit: string;
+
+ // The price for one ``unit`` of the product. Zero is used
+ // to imply that this product is not sold separately, or
+ // that the price is not fixed, and must be supplied by the
+ // front-end. If non-zero, this price MUST include applicable
+ // taxes.
+ price: Amount;
+
+ // An optional base64-encoded product image.
+ image?: ImageDataUrl;
+
+ // A list of taxes paid by the merchant for one unit of this product.
+ taxes?: Tax[];
+
+ // Number of units of the product in stock in sum in total,
+ // including all existing sales ever. Given in product-specific
+ // units.
+ // Optional, if missing treat as "infinite".
+ total_stock?: Integer;
+
+ // Minimum age buyer must have (in years).
+ minimum_age?: Integer;
+
+ }
+
+ .. ts:def:: MerchantCategory
+
+ interface MerchantCategory {
+ // A unique numeric ID of the category
+ id: number;
+
+ // The name of the category. This will be shown to users and used in the order summary.
+ name: string;
+
+ // Map from IETF BCP 47 language tags to localized names
+ name_i18n?: { [lang_tag: string]: string };
+ }
+
+
Reserving inventory
-------------------
@@ -2053,7 +2364,7 @@ Creating orders
// False can make sense if the ORDER_ID is sufficiently
// high entropy to prevent adversarial claims (like it is
// if the backend auto-generates one). Default is 'true'.
- // Note: This is NOT related to tokens used for subscriptins or refunds.
+ // Note: This is NOT related to tokens used for subscriptins or discounts.
create_token?: boolean;
// OTP device ID to associate with the order.
@@ -2068,12 +2379,39 @@ Creating orders
.. ts:def:: Order
- interface Order {
- // Total price for the transaction.
- // The exchange will subtract deposit fees from that amount
- // before transferring it to the merchant.
+ type Order = (OrderV1 | OrderV0) & OrderCommon;
+
+ .. ts:def:: OrderV1
+
+ interface OrderV1 {
+ // Version 1 order support discounts and subscriptions.
+ // https://docs.taler.net/design-documents/046-mumimo-contracts.html
+ // @since protocol **vSUBSCRIBE**
+ version: 1;
+
+ // List of contract choices that the customer can select from.
+ // @since protocol **vSUBSCRIBE**
+ choices?: OrderChoice[];
+ }
+
+ .. ts:def:: OrderV0
+
+ interface OrderV0 {
+ // Optional, defaults to 0 if not set.
+ version?: 0;
+
+ // Total price for the transaction. The exchange will subtract deposit
+ // fees from that amount before transferring it to the merchant.
amount: Amount;
+ // Maximum total deposit fee accepted by the merchant for this contract.
+ // Overrides defaults of the merchant instance.
+ max_fee?: Amount;
+ }
+
+ .. ts:def:: OrderCommon
+
+ interface OrderCommon {
// Human-readable description of the whole purchase.
summary: string;
@@ -2088,10 +2426,6 @@ Creating orders
// encoded in it (such as a short product identifier and timestamp).
order_id?: string;
- // List of contract choices that the customer can select from.
- // @since protocol **vSUBSCRIBE**
- choices?: OrderChoice[];
-
// URL where the same contract could be ordered again (if
// available). Returned also at the public order endpoint
// for people other than the actual buyer (hence public,
@@ -2113,10 +2447,6 @@ Creating orders
// messages.
fulfillment_message_i18n?: { [lang_tag: string]: string };
- // Maximum total deposit fee accepted by the merchant for this contract.
- // Overrides defaults of the merchant instance.
- max_fee?: Amount;
-
// List of products that are part of the purchase.
products?: Product[];
@@ -2163,7 +2493,6 @@ Creating orders
// contract without storing it separately in their database.
// Must really be an Object (not a string, integer, float or array).
extra?: Object;
-
}
@@ -2176,11 +2505,21 @@ protocol **vSUBSCRIBE**.
.. ts:def:: OrderChoice
interface OrderChoice {
+ // Total price for the choice. The exchange will subtract deposit
+ // fees from that amount before transferring it to the merchant.
+ amount: Amount;
+
// Inputs that must be provided by the customer, if this choice is selected.
- inputs: OrderInput[];
+ // Defaults to empty array if not specified.
+ inputs?: OrderInput[];
// Outputs provided by the merchant, if this choice is selected.
- outputs: OrderOutput[];
+ // Defaults to empty array if not specified.
+ outputs?: OrderOutput[];
+
+ // Maximum total deposit fee accepted by the merchant for this contract.
+ // Overrides defaults of the merchant instance.
+ max_fee?: Amount;
}
.. ts:def:: OrderInput
@@ -2199,11 +2538,6 @@ protocol **vSUBSCRIBE**.
// across all configured tokens of a merchant.
token_family_slug: string;
- // Start of the validity period of the token. Based on this, the merchant
- // will select the relevant signing key. This value is rounded down
- // according to the configured rounding duration in the token family.
- valid_after: Timestamp;
-
// How many units of the input are required.
// Defaults to 1 if not specified. Output with count == 0 are ignored by
// the merchant backend.
@@ -2229,7 +2563,8 @@ protocol **vSUBSCRIBE**.
// Start of the validity period of the token. Based on this, the merchant
// will select the relevant signing key. This value is rounded down
// according to the configured rounding duration in the token family.
- valid_after: Timestamp;
+ // If not specified, the current time is used.
+ valid_after?: Timestamp;
// How many units of the output are issued by the merchant.
// Defaults to 1 if not specified. Output with count == 0 are ignored by
@@ -3160,17 +3495,6 @@ Adding templates
// 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;
}
@@ -3245,17 +3569,6 @@ Editing templates
// 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;
}
@@ -3678,6 +3991,9 @@ Creating token families
// Validity duration of an issued token.
duration: RelativeTime;
+ // Rounding granularity of generated keys.
+ rounding: RelativeTime;
+
// Kind of the token family.
kind: TokenFamilyKind;
@@ -3826,14 +4142,17 @@ Inspecting token families
// Validity duration of an issued token.
duration: RelativeTime;
+ // Rounding granularity of generated keys.
+ rounding: 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;
+ // How many tokens have been used for this family.
+ used: Integer;
}
@@ -3871,7 +4190,45 @@ The contract terms must have the following structure:
.. ts:def:: ContractTerms
- interface ContractTerms {
+ type ContractTerms = (ContractTermsV1 | ContractTermsV0) & ContractTermsCommon;
+
+.. ts:def:: ContractTermsV1
+
+ interface ContractTermsV1 {
+ // Version 1 supports the ``choices`` array, see
+ // https://docs.taler.net/design-documents/046-mumimo-contracts.html.
+ // @since protocol **vSUBSCRIBE**
+ version: 1;
+
+ // List of contract choices that the customer can select from.
+ // @since protocol **vSUBSCRIBE**
+ choices: ContractChoice[];
+
+ // Map of storing metadata and issue keys of
+ // token families referenced in this contract.
+ // @since protocol **vSUBSCRIBE**
+ token_families: { [token_family_slug: string]: ContractTokenFamily };
+ }
+
+.. ts:def:: ContractTermsV0
+
+ interface ContractTermsV0 {
+ // Defaults to version 0.
+ version?: 0;
+
+ // Total price for the transaction.
+ // The exchange will subtract deposit fees from that amount
+ // before transferring it to the merchant.
+ amount: Amount;
+
+ // Maximum total deposit fee accepted by the merchant for this contract.
+ // Overrides defaults of the merchant instance.
+ max_fee: Amount;
+ }
+
+.. ts:def:: ContractTermsCommon
+
+ interface ContractTermsCommon {
// Human-readable description of the whole purchase.
summary: string;
@@ -3886,15 +4243,6 @@ The contract terms must have the following structure:
// encoded in it (such as a short product identifier and timestamp).
order_id: string;
- // List of contract choices that the customer can select from.
- // @since protocol **vSUBSCRIBE**
- choices: ContractChoice[];
-
- // Total price for the transaction.
- // The exchange will subtract deposit fees from that amount
- // before transferring it to the merchant.
- amount: Amount;
-
// URL where the same contract could be ordered again (if
// available). Returned also at the public order endpoint
// for people other than the actual buyer (hence public,
@@ -3932,10 +4280,6 @@ The contract terms must have the following structure:
// messages.
fulfillment_message_i18n?: { [lang_tag: string]: string };
- // Maximum total deposit fee accepted by the merchant for this contract.
- // Overrides defaults of the merchant instance.
- max_fee: Amount;
-
// List of products that are part of the purchase (see `Product`).
products: Product[];
@@ -4020,6 +4364,170 @@ The contract terms must have the following structure:
}
+.. ts:def:: ContractChoice
+
+ interface ContractChoice {
+ // Price to be paid for this choice. Could be 0.
+ // The price is in addition to other instruments,
+ // such as rations and tokens.
+ // The exchange will subtract deposit fees from that amount
+ // before transferring it to the merchant.
+ amount: Amount;
+
+ // List of inputs the wallet must provision (all of them) to
+ // satisfy the conditions for the contract.
+ inputs: ContractInput[];
+
+ // List of outputs the merchant promises to yield (all of them)
+ // once the contract is paid.
+ outputs: ContractOutput[];
+
+ // Maximum total deposit fee accepted by the merchant for this contract.
+ max_fee: Amount;
+ }
+
+.. ts:def:: ContractInput
+
+ // For now, only tokens are supported as inputs.
+ type ContractInput = ContractInputToken;
+
+.. ts:def:: ContractInputToken
+
+ interface ContractInputToken {
+ type: "token";
+
+ // Slug of the token family in the
+ // 'token_families' map on the order.
+ token_family_slug: string;
+
+ // Start of the validity period of the token. This is used to find the
+ // matching public key within the token family.
+ valid_after: Timestamp;
+
+ // Number of tokens of this type required.
+ // Defaults to one if the field is not provided.
+ number?: Integer;
+ };
+
+.. ts:def:: ContractOutput
+
+ // For now, only tokens are supported as outputs.
+ type ContractOutput = ContractOutputToken;
+
+.. ts:def:: ContractOutputToken
+
+ interface ContractOutputToken {
+ type: "token";
+
+ // Slug of the token family in the
+ // 'token_families' map on the top-level.
+ token_family_slug: string;
+
+ // Start of the validity period of the token. This is used to find the
+ // matching public key within the token family.
+ valid_after: Timestamp;
+
+ // Number of tokens to be issued.
+ // Defaults to one if the field is not provided.
+ number?: Integer;
+ }
+
+.. ts:def:: ContractTokenFamily
+
+ interface ContractTokenFamily {
+ // Human-readable name of the token family.
+ name: string;
+
+ // Human-readable description of the semantics of
+ // this token family (for display).
+ description: string;
+
+ // Map from IETF BCP 47 language tags to localized descriptions.
+ description_i18n?: { [lang_tag: string]: string };
+
+ // Public keys used to validate tokens issued by this token family.
+ keys: TokenIssuePublicKey[];
+
+ // Kind-specific information of the token
+ details: ContractTokenDetails;
+
+ // Must a wallet understand this token type to
+ // process contracts that use or issue it?
+ critical: boolean;
+ };
+
+.. ts:def:: TokenIssuePublicKey
+
+ type TokenIssuePublicKey =
+ | TokenIssueRsaPublicKey
+ | TokenIssueCsPublicKey;
+
+.. ts:def:: TokenIssueRsaPublicKey
+
+ interface TokenIssueRsaPublicKey {
+ cipher: "RSA";
+
+ // RSA public key.
+ rsa_pub: RsaPublicKey;
+
+ // Start time of this key's validity period.
+ valid_after: Timestamp;
+
+ // End time of this key's validity period.
+ valid_before: Timestamp;
+ }
+
+.. ts:def:: TokenIssueCsPublicKey
+
+ interface TokenIssueCsPublicKey {
+ cipher: "CS";
+
+ // CS public key.
+ cs_pub: Cs25519Point;
+
+ // Start time of this key's validity period.
+ valid_after: Timestamp;
+
+ // End time of this key's validity period.
+ valid_before: Timestamp;
+ }
+
+.. ts:def:: ContractTokenDetails
+
+ type ContractTokenDetails =
+ | ContractSubscriptionTokenDetails
+ | ContractDiscountTokenDetails;
+
+.. ts:def:: ContractSubscriptionTokenDetails
+
+ interface ContractSubscriptionTokenDetails {
+ class: "subscription";
+
+ // Array of domain names where this subscription
+ // can be safely used (e.g. the issuer warrants that
+ // these sites will re-issue tokens of this type
+ // if the respective contract says so). May contain
+ // "*" for any domain or subdomain.
+ trusted_domains: string[];
+ };
+
+.. ts:def:: ContractDiscountTokenDetails
+
+ interface ContractDiscountTokenDetails {
+ class: "discount";
+
+ // Array of domain names where this discount token
+ // is intended to be used. May contain "*" for any
+ // domain or subdomain. Users should be warned about
+ // sites proposing to consume discount tokens of this
+ // type that are not in this list that the merchant
+ // is accepting a coupon from a competitor and thus
+ // may be attaching different semantics (like get 20%
+ // discount for my competitors 30% discount token).
+ expected_domains: string[];
+ };
+
+
The wallet must select an exchange that either the merchant accepts directly by
listing it in the exchanges array, or for which the merchant accepts an auditor
that audits that exchange by listing it in the auditors array.