From a9b004e61928c8d839adba026c7170f2010963c7 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 18 Mar 2024 14:25:36 -0300 Subject: wip --- packages/taler-util/src/http-client/merchant.ts | 396 +++++++++++++++++++++--- packages/taler-util/src/http-client/types.ts | 330 ++++++++++++++++++-- 2 files changed, 652 insertions(+), 74 deletions(-) diff --git a/packages/taler-util/src/http-client/merchant.ts b/packages/taler-util/src/http-client/merchant.ts index 32384f8b4..1d498fb57 100644 --- a/packages/taler-util/src/http-client/merchant.ts +++ b/packages/taler-util/src/http-client/merchant.ts @@ -17,7 +17,6 @@ import { HttpStatusCode, LibtoolVersion, - MerchantApiClient, TalerMerchantApi, codecForMerchantConfig } from "@gnu-taler/taler-util"; @@ -26,10 +25,8 @@ import { createPlatformHttpLib, } from "@gnu-taler/taler-util/http"; import { - FailCasesByMethod, - ResultByMethod, opSuccessFromHttp, - opUnknownFailure, + opUnknownFailure } from "../operation.js"; import { CacheEvictor, nullEvictor } from "./utils.js"; @@ -242,7 +239,7 @@ class TalerMerchantInstanceHttpClient { /** * https://docs.taler.net/core/api-merchant.html#get--instances-$INSTANCE-private-kyc */ - async getCurrentIntanceKycStatus(params: { wireHash?: string, exchangeURL?: string, timeout: number }) { + async getCurrentIntanceKycStatus(params: TalerMerchantApi.GetKycStatusRequestParams) { const url = new URL(`private/kyc`, this.baseUrl); if (params.wireHash) { @@ -329,37 +326,69 @@ class TalerMerchantInstanceHttpClient { /** * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-products */ - async addProduct() { + async addProduct(body: TalerMerchantApi.ProductAddDetail) { + const url = new URL(`private/products`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body, + }); } /** * https://docs.taler.net/core/api-merchant.html#patch-[-instances-$INSTANCE]-private-products-$PRODUCT_ID */ - async updateProduct() { + async updateProduct(productId: string, body: TalerMerchantApi.ProductAddDetail) { + const url = new URL(`private/products/${productId}`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "PATCH", + body, + }); } /** * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-products */ async listProducts() { + const url = new URL(`private/products`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + }); } /** * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-products-$PRODUCT_ID */ - async getProduct() { + async getProduct(productId: string) { + const url = new URL(`private/products/${productId}`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + }); } /** * https://docs.taler.net/core/api-merchant.html#reserving-inventory */ - async lockProduct() { + async lockProduct(productId: string) { + const url = new URL(`private/products/${productId}/lock`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + }); } /** * https://docs.taler.net/core/api-merchant.html#removing-products-from-inventory */ - async removeProduct() { + async removeProduct(productId: string) { + const url = new URL(`private/products/${productId}`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "DELETE", + }); } // @@ -369,31 +398,96 @@ class TalerMerchantInstanceHttpClient { /** * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-orders */ - async createOrder() { + async createOrder(body: TalerMerchantApi.PostOrderRequest) { + const url = new URL(`private/orders`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body, + }); } /** * https://docs.taler.net/core/api-merchant.html#inspecting-orders */ - async listOrders() { + async listOrders(params: TalerMerchantApi.ListOrdersRequestParams = {}) { + const url = new URL(`private/orders`, this.baseUrl); + + if (params.date) { + url.searchParams.set("date_s", String(params.date)) + } + if (params.delta) { + url.searchParams.set("delta", String(params.delta)) + } + if (params.fulfillmentUrl) { + url.searchParams.set("fulfillment_url", params.fulfillmentUrl) + } + if (params.paid) { + url.searchParams.set("paid", "YES") + } + if (params.refunded) { + url.searchParams.set("refunded", "YES") + } + if (params.sessionId) { + url.searchParams.set("session_id", params.sessionId) + } + if (params.start) { + url.searchParams.set("start", String(params.start)) + } + if (params.timeout) { + url.searchParams.set("timeout", String(params.timeout)) + } + if (params.wired) { + url.searchParams.set("wired", "YES") + } + + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + }); } /** * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-orders-$ORDER_ID */ - async getOrder() { + async getOrder(orderId: string, params: TalerMerchantApi.GetOrderRequestParams = {}) { + const url = new URL(`private/orders/${orderId}`, this.baseUrl); + + if (params.allowRefundedForRepurchase) { + url.searchParams.set("allow_refunded_for_repurchase", "YES") + } + if (params.sessionId) { + url.searchParams.set("session_id", params.sessionId) + } + if (params.timeout) { + url.searchParams.set("timeout_ms", String(params.timeout)) + } + + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + }); } /** * https://docs.taler.net/core/api-merchant.html#private-order-data-cleanup */ - async forgetOrder() { + async forgetOrder(orderId: string, body: TalerMerchantApi.ForgetRequest) { + const url = new URL(`private/orders/${orderId}/forget`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "PATCH", + body, + }); } /** * https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCE]-private-orders-$ORDER_ID */ - async deleteOrder() { + async deleteOrder(orderId: string) { + const url = new URL(`private/orders/${orderId}`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "DELETE", + }); } // @@ -403,7 +497,13 @@ class TalerMerchantInstanceHttpClient { /** * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-orders-$ORDER_ID-refund */ - async addRefund() { + async addRefund(orderId: string, body: TalerMerchantApi.RefundRequest) { + const url = new URL(`private/orders/${orderId}/refund`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body, + }); } // @@ -413,19 +513,54 @@ class TalerMerchantInstanceHttpClient { /** * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-transfers */ - async informWireTransfer() { + async informWireTransfer(body: TalerMerchantApi.TransferInformation) { + const url = new URL(`private/transfers`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body, + }); } /** * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-transfers */ - async listWireTransfers() { + async listWireTransfers(params: TalerMerchantApi.ListWireTransferRequestParams = {}) { + const url = new URL(`private/transfers`, this.baseUrl); + + if (params.after) { + url.searchParams.set("after", String(params.after)) + } + if (params.before) { + url.searchParams.set("before", String(params.before)) + } + if (params.limit) { + url.searchParams.set("limit", String(params.limit)) + } + if (params.offset) { + url.searchParams.set("offset", String(params.offset)) + } + if (params.paytoURI) { + url.searchParams.set("payto_uri", params.paytoURI) + } + if (params.verified) { + url.searchParams.set("verified", "YES") + } + + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + }); } /** * https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCE]-private-transfers-$TID */ - async deleteWireTransfer() { + async deleteWireTransfer(transferId: string) { + const url = new URL(`private/transfers/${transferId}`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "DELETE", + }); } // @@ -435,31 +570,65 @@ class TalerMerchantInstanceHttpClient { /** * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-otp-devices */ - async addOtpDevice() { + async addOtpDevice(body: TalerMerchantApi.OtpDeviceAddDetails) { + const url = new URL(`private/otp-devices`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body, + }); } /** * https://docs.taler.net/core/api-merchant.html#patch-[-instances-$INSTANCE]-private-otp-devices-$DEVICE_ID */ - async updateOtpDevice() { + async updateOtpDevice(deviceId: string, body: TalerMerchantApi.OtpDevicePatchDetails) { + const url = new URL(`private/otp-devices/${deviceId}`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "PATCH", + body, + }); } /** * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-otp-devices */ async listOtpDevices() { + const url = new URL(`private/otp-devices`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + }); } /** * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-otp-devices-$DEVICE_ID */ - async getOtpDevice() { + async getOtpDevice(deviceId: string, params: TalerMerchantApi.GetOtpDeviceRequestParams = {}) { + const url = new URL(`private/otp-devices/${deviceId}`, this.baseUrl); + + if (params.faketime) { + url.searchParams.set("faketime", String(params.faketime)) + } + if (params.price) { + url.searchParams.set("price", params.price) + } + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + }); + } /** * https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCE]-private-otp-devices-$DEVICE_ID */ - async deleteOtpDevice() { + async deleteOtpDevice(deviceId: string) { + const url = new URL(`private/otp-devices/${deviceId}`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "DELETE", + }); } // @@ -469,37 +638,82 @@ class TalerMerchantInstanceHttpClient { /** * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-templates */ - async addTemplate() { + async addTemplate(body: TalerMerchantApi.TemplateAddDetails) { + const url = new URL(`private/templates`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body, + }); } /** * https://docs.taler.net/core/api-merchant.html#patch-[-instances-$INSTANCE]-private-templates-$TEMPLATE_ID */ - async updateTemplate() { + async updateTemplate(templateId: string, body: TalerMerchantApi.TemplatePatchDetails) { + const url = new URL(`private/templates/${templateId}`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "PATCH", + body, + }); } /** * https://docs.taler.net/core/api-merchant.html#inspecting-template */ async listTemplates() { + const url = new URL(`private/templates`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + }); } /** * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-templates-$TEMPLATE_ID */ - async getTemplate() { + async getTemplate(templateId: string) { + const url = new URL(`private/templates/${templateId}`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + }); } /** * https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCE]-private-templates-$TEMPLATE_ID */ - async deleteTemplate() { + async deleteTemplate(templateId: string) { + const url = new URL(`private/templates/${templateId}`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "DELETE", + }); + } + + /** + * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-templates-$TEMPLATE_ID + */ + async useTemplateGetInfo(templateId: string) { + const url = new URL(`templates/${templateId}`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + }); + } /** * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCES]-templates-$TEMPLATE_ID */ - async useTemplate() { + async useTemplateCreateOrder(templateId: string, body: TalerMerchantApi.UsingTemplateDetails) { + const url = new URL(`templates/${templateId}`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body, + }); } // @@ -510,31 +724,58 @@ class TalerMerchantInstanceHttpClient { /** * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCES]-private-webhooks */ - async addWebhook() { + async addWebhook(body: TalerMerchantApi.WebhookAddDetails) { + const url = new URL(`private/webhooks`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body, + }); } /** * https://docs.taler.net/core/api-merchant.html#patch-[-instances-$INSTANCES]-private-webhooks-$WEBHOOK_ID */ - async updateWebhook() { + async updateWebhook(webhookId: string, body: TalerMerchantApi.WebhookPatchDetails) { + const url = new URL(`private/webhooks/${webhookId}`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "PATCH", + body, + }); } /** * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCES]-private-webhooks */ async listWebhooks() { + const url = new URL(`private/webhooks`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + }); } /** * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCES]-private-webhooks-$WEBHOOK_ID */ - async getWebhook() { + async getWebhook(webhookId: string) { + const url = new URL(`private/webhooks/${webhookId}`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + }); } /** * https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCES]-private-webhooks-$WEBHOOK_ID */ - async removeWebhook() { + async removeWebhook(webhookId: string) { + const url = new URL(`private/webhooks/${webhookId}`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "DELETE", + }); } // @@ -544,31 +785,59 @@ class TalerMerchantInstanceHttpClient { /** * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCES]-private-tokenfamilies */ - async createTokenFamily() { + async createTokenFamily(body: TalerMerchantApi.TokenFamilyCreateRequest) { + const url = new URL(`private/tokenfamilies`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body, + }); } /** * https://docs.taler.net/core/api-merchant.html#patch-[-instances-$INSTANCES]-private-tokenfamilies-$TOKEN_FAMILY_SLUG */ - async updateTokenFamily() { + async updateTokenFamily(tokenSlug: string,body: TalerMerchantApi.TokenFamilyCreateRequest) { + const url = new URL(`private/tokenfamilies/${tokenSlug}`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body, + }); } /** * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCES]-private-tokenfamilies */ async listTokenFamilies() { + const url = new URL(`private/tokenfamilies`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + }); } /** * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCES]-private-tokenfamilies-$TOKEN_FAMILY_SLUG */ - async getTokenFamily() { + async getTokenFamily(tokenSlug: string) { + const url = new URL(`private/tokenfamilies/${tokenSlug}`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + }); + } /** * https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCES]-private-tokenfamilies-$TOKEN_FAMILY_SLUG */ - async deleteTokenFamily() { + async deleteTokenFamily(tokenSlug: string) { + const url = new URL(`private/tokenfamilies/${tokenSlug}`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "DELETE", + }); } } @@ -591,6 +860,10 @@ export class TalerMerchantManagementHttpClient extends TalerMerchantInstanceHttp return compare?.compatible ?? false; } + getSubInstanceApi(instanceId: string) { + return new URL(`instances/${instanceId}`, this.baseUrl) + } + /** * https://docs.taler.net/core/api-merchant.html#get--config * @@ -645,32 +918,75 @@ export class TalerMerchantManagementHttpClient extends TalerMerchantInstanceHttp /** * https://docs.taler.net/core/api-merchant.html#patch--management-instances-$INSTANCE */ - async updateInstance() { + async updateInstance(isntanceId: string, body: TalerMerchantApi.InstanceReconfigurationMessage) { + const url = new URL(`management/instances/${isntanceId}`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "PATCH", + body, + }); + + } /** * https://docs.taler.net/core/api-merchant.html#get--management-instances */ async listInstances() { + const url = new URL(`management/instances`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + }); + } /** * https://docs.taler.net/core/api-merchant.html#get--management-instances-$INSTANCE * */ - async getInstance() { + async getInstance(instanceId: string) { + const url = new URL(`management/instances/${instanceId}`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + }); } /** * https://docs.taler.net/core/api-merchant.html#delete--management-instances-$INSTANCE */ - async deleteInstance() { + async deleteInstance(instanceId: string, params: {purge?: boolean} = {}) { + const url = new URL(`management/instances/${instanceId}`, this.baseUrl); + + if (params.purge) { + url.searchParams.set("purge", "YES") + } + + const resp = await this.httpLib.fetch(url.href, { + method: "DELETE", + }); } /** * https://docs.taler.net/core/api-merchant.html#get--management-instances-$INSTANCE-kyc */ - async getIntanceKycStatus() { + async getIntanceKycStatus(instanceId: string, params: TalerMerchantApi.GetKycStatusRequestParams) { + const url = new URL(`management/instances/${instanceId}/kyc`, this.baseUrl); + + if (params.wireHash) { + url.searchParams.set("h_wire", params.wireHash) + } + if (params.exchangeURL) { + url.searchParams.set("exchange_url", params.exchangeURL) + } + if (params.timeout) { + url.searchParams.set("timeout_ms", String(params.timeout)) + } + + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + }); } diff --git a/packages/taler-util/src/http-client/types.ts b/packages/taler-util/src/http-client/types.ts index 08b29106e..97e37cf7d 100644 --- a/packages/taler-util/src/http-client/types.ts +++ b/packages/taler-util/src/http-client/types.ts @@ -18,6 +18,7 @@ import { PaytoString, codecForPaytoString } from "../payto.js"; import { AmountString } from "../taler-types.js"; import { TalerActionString, codecForTalerActionString } from "../taleruri.js"; import { + AbsoluteTime, TalerProtocolDuration, TalerProtocolTimestamp, codecForTimestamp, @@ -293,6 +294,14 @@ export const codecForCoreBankConfig = (): Codec => //FIXME: implement this codec export const codecForURN = codecForString; +export const codecForExchangeConfigInfo = + (): Codec => + buildCodecForObject() + .property("base_url", codecForString()) + .property("currency", codecForString()) + .property("master_pub", codecForString()) + .build("TalerMerchantApi.ExchangeConfigInfo"); + export const codecForMerchantConfig = (): Codec => buildCodecForObject() @@ -300,6 +309,7 @@ export const codecForMerchantConfig = .property("currency", codecForString()) .property("version", codecForString()) .property("currencies", codecForMap(codecForCurrencySpecificiation())) + .property("exchanges", codecForList(codecForExchangeConfigInfo())) .build("TalerMerchantApi.VersionResponse"); export const codecForExchangeConfig = @@ -2414,12 +2424,17 @@ export namespace TalerMerchantApi { // supported currencies and how to render them. currency: string; - // How wallets should render currencies supported + // How services should render currencies supported // by this backend. Maps // currency codes (e.g. "EUR" or "KUDOS") to // the respective currency specification. // All currencies in this map are supported by - // the backend. + // the backend. Note that the actual currency + // specifications are a *hint* for applications + // that would like *advice* on how to render amounts. + // Applications *may* ignore the currency specification + // if they know how to render currencies that they are + // used with. currencies: { [currency: string]: CurrencySpecification }; // Array of exchanges trusted by the merchant. @@ -2471,39 +2486,126 @@ export namespace TalerMerchantApi { } export interface PaymentStatusRequestParams { - // Hash of the order’s contract terms (this is used to - // authenticate the wallet/customer in case - // $ORDER_ID is guessable). + // Hash of the order’s contract terms (this is used to + // authenticate the wallet/customer in case + // $ORDER_ID is guessable). // Required once an order was claimed. contractTermHash?: string; // Authorizes the request via the claim token that - // was returned in the PostOrderResponse. Used with + // was returned in the PostOrderResponse. Used with // unclaimed orders only. Whether token authorization is // required is determined by the merchant when the // frontend creates the order. claimToken?: string; - // Session ID that the payment must be bound to. + // Session ID that the payment must be bound to. // If not specified, the payment is not session-bound. sessionId?: string; - // If specified, the merchant backend will wait up to - // timeout_ms milliseconds for completion of the payment - // before sending the HTTP response. A client must never - // rely on this behavior, as the merchant backend may return + // If specified, the merchant backend will wait up to + // timeout_ms milliseconds for completion of the payment + // before sending the HTTP response. A client must never + // rely on this behavior, as the merchant backend may return // a response immediately. timeout?: number; // If set to “yes”, poll for the order’s pending refunds - // to be picked up. timeout_ms specifies how long we + // to be picked up. timeout_ms specifies how long we // will wait for the refund. awaitRefundObtained?: boolean; - // Indicates that we are polling for a refund above the - // given AMOUNT. timeout_ms will specify how long we + // Indicates that we are polling for a refund above the + // given AMOUNT. timeout_ms will specify how long we // will wait for the refund. refund?: AmountString; - // Since protocol v9 refunded orders are only returned - // under “already_paid_order_id” if this flag is set + // Since protocol v9 refunded orders are only returned + // under “already_paid_order_id” if this flag is set // explicitly to “YES”. allowRefundedForRepurchase?: boolean; - + } + export interface GetKycStatusRequestParams { + // If specified, the KYC check should return + // the KYC status only for this wire account. + // Otherwise, for all wire accounts. + wireHash?: string; + // If specified, the KYC check should return + // the KYC status only for the given exchange. + // Otherwise, for all exchanges we interacted with. + exchangeURL?: string; + // If specified, the merchant will wait up to + // timeout_ms milliseconds for the exchanges to + // confirm completion of the KYC process(es). + timeout?: number; + } + export interface GetOtpDeviceRequestParams { + // Timestamp in seconds to use when calculating + // the current OTP code of the device. Since protocol v10. + faketime?: number; + // Price to use when calculating the current OTP + // code of the device. Since protocol v10. + price?: AmountString; + } + export interface GetOrderRequestParams { + // Session ID that the payment must be bound to. + // If not specified, the payment is not session-bound. + sessionId?: string; + // Timeout in milliseconds to wait for a payment if + // the answer would otherwise be negative (long polling). + timeout?: number; + // Since protocol v9 refunded orders are only returned + // under “already_paid_order_id” if this flag is set + // explicitly to “YES”. + allowRefundedForRepurchase?: boolean; + } + export interface ListWireTransferRequestParams { + // Filter for transfers to the given bank account + // (subject and amount MUST NOT be given in the payto URI). + paytoURI?: string; + // Filter for transfers executed before the given timestamp. + before?: number; + // Filter for transfers executed after the given timestamp. + after?: number; + // At most return the given number of results. Negative for + // descending in execution time, positive for ascending in + // execution time. Default is -20. + limit?: number; + // Starting transfer_serial_id for an iteration. + offset?: number; + // Filter transfers by verification status. + verified?: boolean; + } + export interface ListOrdersRequestParams { + // 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. + paid?: boolean; + // 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. + refunded?: boolean; + // 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. + wired?: boolean; + // 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). + delta?: number; + // 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. + date?: AbsoluteTime; + // Row number threshold, see delta for its interpretation. + // Defaults to INT64_MAX, namely the biggest row id possible in + // the database. + start?: number; + // 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. + timeout?: number; + // Since protocol v6. Filters by session ID. + sessionId?: string; + // Since protocol v6. Filters by fulfillment URL. + fulfillmentUrl?: string; } export interface PayRequest { @@ -2847,7 +2949,6 @@ export namespace TalerMerchantApi { token?: string; } - export interface InstanceReconfigurationMessage { // Merchant name corresponding to this instance. name: string; @@ -3085,7 +3186,7 @@ export namespace TalerMerchantApi { active: boolean; } - interface ProductAddDetail { + export interface ProductAddDetail { // Product ID to use. product_id: string; @@ -3127,7 +3228,7 @@ export namespace TalerMerchantApi { minimum_age?: Integer; } - interface ProductPatchDetail { + export interface ProductPatchDetail { // Human-readable product description. description: string; @@ -3235,7 +3336,7 @@ export namespace TalerMerchantApi { quantity: Integer; } - interface PostOrderRequest { + export interface PostOrderRequest { // The order must at least contain the minimal // order detail, but can override all. order: Order; @@ -3287,6 +3388,9 @@ export namespace TalerMerchantApi { // 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. @@ -3498,13 +3602,13 @@ export namespace TalerMerchantApi { coin_pub: CoinPublicKey; } - interface ForgetRequest { + export interface ForgetRequest { // Array of valid JSON paths to forgettable fields in the order's // contract terms. fields: string[]; } - interface RefundRequest { + export interface RefundRequest { // Amount to be refunded. refund: AmountString; @@ -3522,7 +3626,7 @@ export namespace TalerMerchantApi { h_contract: HashCode; } - interface TransferInformation { + export interface TransferInformation { // How much was wired to the merchant (minus fees). credit_amount: AmountString; @@ -3740,28 +3844,40 @@ export namespace TalerMerchantApi { reward_amount: AmountString; } - interface OtpDeviceAddDetails { + export interface OtpDeviceAddDetails { // Device ID to use. otp_device_id: string; // 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; } - interface OtpDevicePatchDetails { + export interface OtpDevicePatchDetails { // 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. @@ -3788,12 +3904,50 @@ export namespace TalerMerchantApi { 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; } - interface TemplateAddDetails { + export interface TemplateAddDetails { // Template ID to use. template_id: string; @@ -3829,7 +3983,7 @@ export namespace TalerMerchantApi { // It is deleted if the customer did not pay and if the duration is over. pay_duration: RelativeTime; } - interface TemplatePatchDetails { + export interface TemplatePatchDetails { // Human-readable description for the template. template_description: string; @@ -3864,7 +4018,7 @@ export namespace TalerMerchantApi { // Additional information in a separate template. template_contract: TemplateContractDetails; } - interface UsingTemplateDetails { + export interface UsingTemplateDetails { // Summary of the template summary?: string; @@ -3872,7 +4026,7 @@ export namespace TalerMerchantApi { amount?: AmountString; } - interface WebhookAddDetails { + export interface WebhookAddDetails { // Webhook ID to use. webhook_id: string; @@ -3892,7 +4046,7 @@ export namespace TalerMerchantApi { body_template?: string; } - interface WebhookPatchDetails { + export interface WebhookPatchDetails { // The event of the webhook: why the webhook is used. event_type: string; @@ -3939,6 +4093,114 @@ export namespace TalerMerchantApi { body_template?: string; } + export 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; + } + + enum TokenFamilyKind { + Discount = "discount", + Subscription = "subscription", + } + + export 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; + } + + interface TokenFamiliesList { + // All configured token families of this instance. + token_families: 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; + } + + 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; + } interface ContractTerms { // Human-readable description of the whole purchase. summary: string; -- cgit v1.2.3