/*
  This file is part of TALER
  Copyright (C) 2014-2025 Taler Systems SA

  TALER is free software; you can redistribute it and/or modify it under the
  terms of the GNU Lesser General Public License as published by the Free Software
  Foundation; either version 3, or (at your option) any later version.

  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.

  You should have received a copy of the GNU General Public License along with
  TALER; see the file COPYING.GPL.  If not, see <http://www.gnu.org/licenses/>
*/
/**
 * @file taler_merchantdb_plugin.h
 * @brief database access for the merchant
 * @author Florian Dold
 * @author Christian Grothoff
 * @author Priscilla Huang
 */
#ifndef TALER_MERCHANTDB_PLUGIN_H
#define TALER_MERCHANTDB_PLUGIN_H

#include <gnunet/gnunet_common.h>
#include <gnunet/gnunet_time_lib.h>
#include <gnunet/gnunet_util_lib.h>
#include <gnunet/gnunet_db_lib.h>
#include <taler/taler_exchange_service.h>
#include <taler_merchant_util.h>
#include <jansson.h>

#ifdef HAVE_DONAU_DONAU_SERVICE_H
#include <donau/donau_service.h>
#include "taler_merchant_donau.h"
#endif

/**
 * Handle to interact with the database.
 */
struct TALER_MERCHANTDB_Plugin;


GNUNET_NETWORK_STRUCT_BEGIN


/**
 * Format of the data hashed to generate the notification
 * string whenever the KYC status for an account has
 * changed.
 */
struct TALER_MERCHANTDB_MerchantKycStatusChangeEventP
{
  /**
   * Type is TALER_DBEVENT_MERCHANT_EXCHANGE_KYC_STATUS_CHANGED.
   */
  struct GNUNET_DB_EventHeaderP header;

  /**
   * Salted hash of the affected account.
   */
  struct TALER_MerchantWireHashP h_wire;
};

GNUNET_NETWORK_STRUCT_END

/**
 * Current exposed deposit limits by an exchange
 * for a merchant (until other rules may apply).
 */
struct TALER_MERCHANTDB_DepositLimits
{
  /**
   * Maximum amount to be deposited within @a timeframe.
   */
  struct TALER_Amount threshold;

  /**
   * Timeframe over which the limit applies.
   */
  struct GNUNET_TIME_Relative timeframe;

  /**
   * True if this is a soft limit that could be
   * raised (by AML staff or by passing KYC checks).
   */
  bool soft_limit;
};

/**
 * Details about a wire account of the merchant.
 */
struct TALER_MERCHANTDB_AccountDetails
{
  /**
   * Hash of the wire details (@e payto_uri and @e salt).
   */
  struct TALER_MerchantWireHashP h_wire;

  /**
   * Salt value used for hashing @e payto_uri.
   */
  struct TALER_WireSaltP salt;

  /**
   * Instance ID. Do not free (may be aliased with
   * the instance ID given in the query!).
   * FIXME: set in all functions involving this struct!
   */
  const char *instance_id;

  /**
   * Actual account address as a payto://-URI.
   */
  struct TALER_FullPayto payto_uri;

  /**
   * Where can the taler-merchant-wirewatch helper
   * download information about incoming transfers?
   * NULL if not available.
   */
  char *credit_facade_url;

  /**
   * JSON with credentials to use to access the
   * @e credit_facade_url.
   */
  json_t *credit_facade_credentials;

  /**
   * Is the account set for active use in new contracts?
   */
  bool active;

};


/**
 * Binary login token. Just a vanilla token made out
 * of random bits.
 */
struct TALER_MERCHANTDB_LoginTokenP
{
  /**
   * 32 bytes of entropy.
   */
  uint64_t data[32 / 8];
};

/**
 * Authentication settings for an instance.
 */
struct TALER_MERCHANTDB_InstanceAuthSettings
{
  /**
   * Hash used for authentication.  All zero if authentication is off.
   */
  struct TALER_MerchantAuthenticationHashP auth_hash;

  /**
   * Salt used to hash the "Authentication" header, the result must then
   * match the @e auth_hash.
   */
  struct TALER_MerchantAuthenticationSaltP auth_salt;
};

/**
 * General settings for an instance.
 */
struct TALER_MERCHANTDB_InstanceSettings
{
  /**
   * prefix for the instance under "/instances/"
   */
  char *id;

  /**
   * legal name of the instance
   */
  char *name;

  /**
   * merchant's site url
   */
  char *website;

  /**
   * email contact for password reset / possibly admin / customers
   */
  char *email;

  /**
   * phone contact for password reset / possibly admin / customers
   */
  char *phone;

  /**
   * merchant's logo data uri
   */
  char *logo;

  /**
   * Address of the business
   */
  json_t *address;

  /**
   * jurisdiction of the business
   */
  json_t *jurisdiction;

  /**
   * Use STEFAN curves to determine acceptable
   * fees by default (otherwise: accept no fees by default).
   */
  bool use_stefan;

  /**
   * True of @e phone was validated.
   */
  bool phone_validated;

  /**
   * True of @e email was validated.
   */
  bool email_validated;

  /**
   * If the frontend does NOT specify an execution date, how long should
   * we tell the exchange to wait to aggregate transactions before
   * executing the wire transfer?  This delay is added to the current
   * time when we generate the advisory execution time for the exchange.
   */
  struct GNUNET_TIME_Relative default_wire_transfer_delay;

  /**
   * If the frontend does NOT specify a payment deadline, how long should
   * offers we make be valid by default?
   */
  struct GNUNET_TIME_Relative default_pay_delay;

  /**
   * If the frontend does NOT specify a refund deadline, how long should
   * refunds be possible?
   */
  struct GNUNET_TIME_Relative default_refund_delay;

  /**
   * How much should we round up the wire transfer deadline computed by
   * adding the @e default_wire_transfer_delay to the refund deadline.
   */
  enum GNUNET_TIME_RounderInterval default_wire_transfer_rounding_interval;

};


/**
 * Typically called by `lookup_instances`.
 *
 * @param cls closure
 * @param merchant_pub public key of the instance
 * @param merchant_priv private key of the instance, NULL if not available
 * @param is general instance settings
 * @param ias instance authentication settings
 */
typedef void
(*TALER_MERCHANTDB_InstanceCallback)(
  void *cls,
  const struct TALER_MerchantPublicKeyP *merchant_pub,
  const struct TALER_MerchantPrivateKeyP *merchant_priv,
  const struct TALER_MERCHANTDB_InstanceSettings *is,
  const struct TALER_MERCHANTDB_InstanceAuthSettings *ias);


/**
 * Callback invoked with information about a bank account.
 *
 * @param cls closure
 * @param merchant_priv private key of the merchant instance
 * @param ad details about the account
 */
typedef void
(*TALER_MERCHANTDB_AccountCallback)(
  void *cls,
  const struct TALER_MerchantPrivateKeyP *merchant_priv,
  const struct TALER_MERCHANTDB_AccountDetails *ad);


/**
 * Determines the maximum @a amount for a particular
 * type of operation for a given @a exchange_url.
 *
 * @param cls closure
 * @param exchange_url base URL of the exchange to get
 *   the limit for
 * @param[in,out] amount lowered to the maximum amount
 *   allowed at the exchange
 */
typedef void
(*TALER_MERCHANTDB_OperationLimitCallback)(
  void *cls,
  const char *exchange_url,
  struct TALER_Amount *amount);


/**
 * Typically called by `lookup_products`.
 *
 * @param cls a `json_t *` JSON array to build
 * @param product_serial row ID of the product
 * @param product_id ID of the product
 */
typedef void
(*TALER_MERCHANTDB_ProductsCallback)(
  void *cls,
  uint64_t product_serial,
  const char *product_id);


/**
 * Details about a product.
 */
struct TALER_MERCHANTDB_ProductDetails
{
  /**
   * Name of the product.
   */
  char *product_name;

  /**
   * Description of the product.
   */
  char *description;

  /**
   * Internationalized description.
   */
  json_t *description_i18n;

  /**
   * Unit in which the product is sold.
   */
  char *unit;

  /**
   * Price per unit of the product.  Zero to imply that the
   * product is not sold separately or that the price is not fixed.
   */
  struct TALER_Amount price;

  /**
   * Optional list of per-unit prices. When NULL or empty, @e price
   * must be used as the canonical single price.
   */
  struct TALER_Amount *price_array;

  /**
   * Number of entries in @e price_array.
   */
  size_t price_array_length;

  /**
   * Base64-encoded product image, or an empty string.
   */
  char *image;

  /**
   * List of taxes the merchant pays for this product. Never NULL,
   * but can be an empty array.
   */
  json_t *taxes;

  /**
   * Number of units of the product in stock in sum in total, including all
   * existing sales and lost product, in product-specific units. UINT64_MAX
   * indicates "infinite".
   */
  uint64_t total_stock;

  /**
   * Fractional part of stock in units of 1/1000000 of the base value.
   */
  uint32_t total_stock_frac;

  /**
   * Honor fractional stock if TRUE, else only integer stock.
   */
  bool allow_fractional_quantity;

  /**
   * Precision level (number of decimal places) to apply when
   * fractional quantities are enabled.
   */
  uint32_t fractional_precision_level;

  /**
   * Number of units of the product in sold, in product-specific units.
   */
  uint64_t total_sold;

  /**
   * Fractional part of units sold in units of 1/1000000 of the base value.
   */
  uint32_t total_sold_frac;

  /**
   * Number of units of stock lost.
   */
  uint64_t total_lost;

  /**
   * Fractional part of lost units in units of 1/1000000 of the base value.
   */
  uint32_t total_lost_frac;

  /**
   * Identifies where the product is in stock, possibly an empty map.
   */
  json_t *address;

  /**
   * Identifies when the product will be restocked. 0 for unknown,
   * #GNUNET_TIME_UNIT_FOREVER_ABS for never.
   */
  struct GNUNET_TIME_Timestamp next_restock;

  /**
   * Minimum required age for consumers buying this product.
   * Default is 0. Only enforced of an exchange supports age
   * restrictions.
   */
  uint32_t minimum_age;
};


/**
 * Details about an inventory measurement unit.
 */
struct TALER_MERCHANTDB_UnitDetails
{

  /**
   * Database serial.
   */
  uint64_t unit_serial;

  /**
   * Backend identifier used in product payloads.
   */
  char *unit;

  /**
   * Default long label (fallback string).
   */
  char *unit_name_long;

  /**
   * Default short label (fallback string).
   */
  char *unit_name_short;

  /**
   * Internationalised long labels.
   */
  json_t *unit_name_long_i18n;

  /**
   * Internationalised short labels.
   */
  json_t *unit_name_short_i18n;

  /**
   * Whether fractional quantities are enabled by default.
   */
  bool unit_allow_fraction;

  /**
   * Maximum number of fractional digits honoured by default.
   */
  uint32_t unit_precision_level;

  /**
   * Hidden from selectors when false.
   */
  bool unit_active;

  /**
   * Built-in units cannot be deleted.
   */
  bool unit_builtin;
};


/**
 * Typically called by `lookup_all_products`.
 *
 * @param cls a `json_t *` JSON array to build
 * @param product_serial row ID of the product
 * @param product_id ID of the product
 * @param pd full product details
 * @param num_categories length of @a categories array
 * @param categories array of categories the
 *   product is in
 */
typedef void
(*TALER_MERCHANTDB_ProductCallback)(
  void *cls,
  uint64_t product_serial,
  const char *product_id,
  const struct TALER_MERCHANTDB_ProductDetails *pd,
  size_t num_categories,
  const uint64_t *categories);


/**
 * Typically called by `lookup_login_tokens`.
 *
 * @param cls a `json_t *` JSON array to build
 * @param creation_time creation time of the token
 * @param expiration_time expiration time of the token
 * @param scope validity scope of the token
 * @param description description of the token
 * @param serial serial number of the token
 */
typedef void
(*TALER_MERCHANTDB_LoginTokensCallback)(
  void *cls,
  struct GNUNET_TIME_Timestamp creation_time,
  struct GNUNET_TIME_Timestamp expiration_time,
  uint32_t scope,
  const char *description,
  uint64_t serial);


/**
 * Typically called by `lookup_templates`.
 *
 * @param cls closure
 * @param template_id ID of the template
 * @param template_description description of the template
 */
typedef void
(*TALER_MERCHANTDB_TemplatesCallback)(
  void *cls,
  const char *template_id,
  const char *template_description);


/**
 * Typically called by `lookup_otp_devices`.
 *
 * @param cls closure
 * @param otp_id ID of the OTP device
 * @param otp_description description of the OTP device
 */
typedef void
(*TALER_MERCHANTDB_OtpDeviceCallback)(
  void *cls,
  const char *otp_id,
  const char *otp_description);


/**
 * Details about a template.
 */
struct TALER_MERCHANTDB_TemplateDetails
{
  /**
   * Description of the template.
   */
  char *template_description;

  /**
   * In this template contract, we can have additional information.
   */
  json_t *template_contract;

  /**
   * ID of the OTP device linked to the template, or NULL.
   */
  char *otp_id;

  /**
   * Editable default values for fields not specified
   * in the @e template_contract. NULL if the user
   * cannot edit anything.
   */
  json_t *editable_defaults;

};


/**
 * Details about an OTP device.
 */
struct TALER_MERCHANTDB_OtpDeviceDetails
{

  /**
   * Description of the device.
   */
  char *otp_description;

  /**
   * Current usage counter value.
   */
  uint64_t otp_ctr;

  /**
   * Base64-encoded key.
   */
  char *otp_key;

  /**
   * Algorithm used to compute purchase confirmations.
   */
  enum TALER_MerchantConfirmationAlgorithm otp_algorithm;
};


/**
 * Typically called by `lookup_categories`.
 *
 * @param cls closure
 * @param category_id ID of the category
 * @param category_name name of the category
 * @param category_name_i18n translations of the @a category_name
 * @param product_count number of products in the category
 */
typedef void
(*TALER_MERCHANTDB_CategoriesCallback)(
  void *cls,
  uint64_t category_id,
  const char *category_name,
  const json_t *category_name_i18n,
  uint64_t product_count);


/**
 * Typically called by `lookup_units`.
 *
 * @param cls closure
 * @param unit_serial database identifier
 * @param ud measurement unit details (borrowed)
 */
typedef void
(*TALER_MERCHANTDB_UnitsCallback)(
  void *cls,
  uint64_t unit_serial,
  const struct TALER_MERCHANTDB_UnitDetails *ud);


/**
 * Details about a product category.
 */
struct TALER_MERCHANTDB_CategoryDetails
{

  /**
   * Name of the category.
   */
  char *category_name;

  /**
   * Translations of the name of the category.
   */
  json_t *category_name_i18n;

};


/**
 * Typically called by `lookup_webhooks`.
 *
 * @param cls a `json_t *` JSON array to build
 * @param webhook_id ID of the webhook
 * @param event_type event of the webhook
 */
typedef void
(*TALER_MERCHANTDB_WebhooksCallback)(
  void *cls,
  const char *webhook_id,
  const char *event_type);


/**
 * Details about a webhook.
 */
struct TALER_MERCHANTDB_WebhookDetails
{

  /**
   * event of the webhook.
   */
  char *event_type;

  /**
   * URL of the webhook. The customer will be redirected on this url.
   */
  char *url;

  /**
   * Http method used by the webhook.
   */
  char *http_method;

  /**
   * Header template of the webhook.
   */
  char *header_template;

  /**
   * Body template of the webhook.
   */
  char *body_template;

};


/**
 * Typically called by `lookup_webhook_by_event`.
 *
 * @param cls a `json_t *` JSON array to build
 * @param webhook_serial reference to the configured webhook template.
 * @param event_type which type of event triggers this type of webhook
 * @param url the HTTP URL to make the webhook request to
 * @param http_method HTTP method use for the webhook
 * @param header_template template for the header of the webhook
 * @param body_template template for the body of the webhook
 */
typedef void
(*TALER_MERCHANTDB_WebhookDetailCallback)(
  void *cls,
  uint64_t webhook_serial,
  const char *event_type,
  const char *url,
  const char *http_method,
  const char *header_template,
  const char *body_template);


/**
 * Typically called by `lookup_pending_webhooks`.
 *
 * @param cls a `json_t *` JSON array to build
 * @param webhook_pending_serial reference to the configured webhook template.
 * @param next_attempt is the time we should make the next request to the webhook.
 * @param retries how often have we tried this request to the webhook.
 * @param url to make request to
 * @param http_method use for the webhook
 * @param header of the webhook
 * @param body of the webhook
 */
typedef void
(*TALER_MERCHANTDB_PendingWebhooksCallback)(
  void *cls,
  uint64_t webhook_pending_serial,
  struct GNUNET_TIME_Absolute
  next_attempt,
  uint32_t retries,
  const char *url,
  const char *http_method,
  const char *header,
  const char *body);


/**
 * Details about the pending webhook.
 */
struct TALER_MERCHANTDB_PendingWebhookDetails
{

  /**
   * Identifies when we should make the next request to the webhook. 0 for unknown,
   * #GNUNET_TIME_UNIT_FOREVER_ABS for never.
   */
  struct GNUNET_TIME_Absolute next_attempt;

  /**
   * How often have we tried this request so far.
   */
  uint32_t retries;

  /**
   * URL of the webhook. The customer will be redirected on this url.
   */
  char *url;

  /**
   * Http method used for the webhook.
   */
  char *http_method;

  /**
   * Header of the webhook.
   */
  char *header;

  /**
   * Body of the webhook.
   */
  char *body;

};


/**
 * Filter preferences.
 */
struct TALER_MERCHANTDB_OrderFilter
{
  /**
   * Filter orders by this fulfillment URL.
   */
  const char *fulfillment_url;

  /**
   * Filter orders by this session ID.
   */
  const char *session_id;

  /**
   * Filter by payment status.
   */
  enum TALER_EXCHANGE_YesNoAll paid;

  /**
   * Filter by refund status.
   */
  enum TALER_EXCHANGE_YesNoAll refunded;

  /**
   * Filter by wire transfer status.
   */
  enum TALER_EXCHANGE_YesNoAll wired;

  /**
   * Filter orders by date, exact meaning depends on @e delta.
   */
  struct GNUNET_TIME_Timestamp date;

  /**
   * Filter orders by order serial number, exact meaning depends on @e delta.
   */
  uint64_t start_row;

  /**
   * takes value of the form N (-N), so that at most N values strictly older
   * (younger) than start and date are returned.
   */
  int64_t delta;

  /**
   * Timeout for long-polling.
   */
  struct GNUNET_TIME_Relative timeout;

  /**
   * Filter to apply on the summary of the order.
   */
  const char *summary_filter;

};


/**
 * Typically called by `lookup_orders`.
 *
 * @param cls a `json_t *` JSON array to build
 * @param order_id ID of the order
 * @param order_serial row of the order in the database
 * @param timestamp creation time of the order in the database
 */
typedef void
(*TALER_MERCHANTDB_OrdersCallback)(void *cls,
                                   const char *order_id,
                                   uint64_t order_serial,
                                   struct GNUNET_TIME_Timestamp timestamp);


/**
 * Typically called by `select_order_blinded_sigs`
 *
 * @param cls closure
 * @param hash hash of the token
 * @param blinded_sig blinded signature for the token
 */
typedef void
(*TALER_MERCHANTDB_BlindedSigCallback)(
  void *cls,
  struct GNUNET_HashCode *hash,
  struct GNUNET_CRYPTO_BlindedSignature *blinded_sig);

/**
 * Function called with information about a coin that was deposited.
 *
 * @param cls closure
 * @param exchange_url exchange where @a coin_pub was deposited
 * @param coin_pub public key of the coin
 * @param amount_with_fee amount the exchange will deposit for this coin
 * @param deposit_fee fee the exchange will charge for this coin
 * @param refund_fee fee the exchange will charge for refunding this coin
 */
typedef void
(*TALER_MERCHANTDB_DepositsCallback)(
  void *cls,
  const char *exchange_url,
  const struct TALER_CoinSpendPublicKeyP *coin_pub,
  const struct TALER_Amount *amount_with_fee,
  const struct TALER_Amount *deposit_fee,
  const struct TALER_Amount *refund_fee);


/**
 * Function called with information about a refund.
 *
 * @param cls closure
 * @param coin_pub public coin from which the refund comes from
 * @param refund_amount refund amount which is being taken from @a coin_pub
 */
typedef void
(*TALER_MERCHANTDB_RefundCallback)(
  void *cls,
  const struct TALER_CoinSpendPublicKeyP *coin_pub,
  const struct TALER_Amount *refund_amount);


/**
 * Typically called by `lookup_transfer_details_by_order`.
 *
 * @param cls closure
 * @param wtid wire transfer subject of the wire transfer for the coin
 * @param exchange_url base URL of the exchange that made the payment
 * @param execution_time when was the payment made
 * @param deposit_value contribution of the coin to the total wire transfer value
 * @param deposit_fee deposit fee charged by the exchange for the coin
 * @param transfer_confirmed did the merchant confirm that a wire transfer with
 *        @a wtid over the total amount happened?
 */
typedef void
(*TALER_MERCHANTDB_OrderTransferDetailsCallback)(
  void *cls,
  const struct TALER_WireTransferIdentifierRawP *wtid,
  const char *exchange_url,
  struct GNUNET_TIME_Timestamp execution_time,
  const struct TALER_Amount *deposit_value,
  const struct TALER_Amount *deposit_fee,
  bool transfer_confirmed);


/**
 * Function called with detailed information about a refund.
 *
 * @param cls closure
 * @param refund_serial unique serial number of the refund
 * @param timestamp time of the refund (for grouping of refunds in the wallet UI)
 * @param coin_pub public coin from which the refund comes from
 * @param exchange_url URL of the exchange that issued @a coin_pub
 * @param rtransaction_id identificator of the refund
 * @param reason human-readable explanation of the refund
 * @param refund_amount refund amount which is being taken from @a coin_pub
 * @param pending true if the this refund was not yet processed by the wallet/exchange
 */
typedef void
(*TALER_MERCHANTDB_RefundDetailCallback)(
  void *cls,
  uint64_t refund_serial,
  struct GNUNET_TIME_Timestamp timestamp,
  const struct TALER_CoinSpendPublicKeyP *coin_pub,
  const char *exchange_url,
  uint64_t rtransaction_id,
  const char *reason,
  const struct TALER_Amount *refund_amount,
  bool pending);


/**
 * Function called from ``account_kyc_get_status``
 * with KYC status information for this merchant.
 *
 * @param cls closure
 * @param h_wire hash of the wire account
 * @param payto_uri payto:// URI of the merchant's bank account
 * @param exchange_url base URL of the exchange for which this is a status
 * @param last_check when did we last get an update on our KYC status from the exchange
 * @param kyc_ok true if we satisfied the KYC requirements
 * @param access_token access token for the KYC SPA, NULL if we cannot access it yet (need KYC auth wire transfer)
 * @param last_http_status last HTTP status from /kyc-check
 * @param last_ec last Taler error code from /kyc-check
 * @param in_aml_review true if the account is pending review
 * @param jlimits JSON array of applicable AccountLimits, or NULL if unknown (like defaults apply)
 */
typedef void
(*TALER_MERCHANTDB_KycCallback)(
  void *cls,
  const struct TALER_MerchantWireHashP *h_wire,
  struct TALER_FullPayto payto_uri,
  const char *exchange_url,
  struct GNUNET_TIME_Timestamp last_check,
  bool kyc_ok,
  const struct TALER_AccountAccessTokenP *access_token,
  unsigned int last_http_status,
  enum TALER_ErrorCode last_ec,
  bool in_aml_review,
  const json_t *jlimits);


/**
 * Results from trying to increase a refund.
 */
enum TALER_MERCHANTDB_RefundStatus
{

  /**
   * Refund amount exceeds legal exchange limits.
   */
  TALER_MERCHANTDB_RS_LEGAL_FAILURE = -5,

  /**
   * Refund amount currency does not match original payment.
   */
  TALER_MERCHANTDB_RS_BAD_CURRENCY = -4,

  /**
   * Refund amount exceeds original payment.
   */
  TALER_MERCHANTDB_RS_TOO_HIGH = -3,

  /**
   * Hard database failure.
   */
  TALER_MERCHANTDB_RS_HARD_ERROR = -2,

  /**
   * Soft database failure.
   */
  TALER_MERCHANTDB_RS_SOFT_ERROR = -1,

  /**
   * Order not found.
   */
  TALER_MERCHANTDB_RS_NO_SUCH_ORDER = 0,

  /**
   * Refund is now at or above the requested amount.
   */
  TALER_MERCHANTDB_RS_SUCCESS = 1

};


/**
 * Function called with information about a wire transfer identifier.
 *
 * @param cls closure
 * @param order_id the order to which the deposits belong
 * @param deposit_value the amount deposited under @a order_id
 * @param deposit_fee the fee charged for @a deposit_value
 */
typedef void
(*TALER_MERCHANTDB_TransferSummaryCallback)(
  void *cls,
  const char *order_id,
  const struct TALER_Amount *deposit_value,
  const struct TALER_Amount *deposit_fee);


/**
 * Function called with information about wire transfers
 * that taler-merchant-exchange still needs to process.
 *
 * @param cls closure
 * @param rowid row of the transfer in the merchant database
 * @param instance_id instance that received the transfer
 * @param exchange_url URL of the exchange that is making the deposit
 * @param payto_uri account of the merchant that received the transfer
 * @param wtid wire transfer subject identifying the aggregation
 * @param next_attempt when should we next try to interact with the exchange
 */
typedef void
(*TALER_MERCHANTDB_OpenTransferCallback)(
  void *cls,
  uint64_t rowid,
  const char *instance_id,
  const char *exchange_url,
  struct TALER_FullPayto payto_uri,
  const struct TALER_WireTransferIdentifierRawP *wtid,
  struct GNUNET_TIME_Absolute next_attempt);


/**
 * Callback for results from `lookup_pending_deposits`.
 *
 * @param cls NULL
 * @param deposit_serial identifies the deposit operation
 * @param wire_deadline when is the wire due
 * @param retry_time when to next try the exchange again
 * @param h_contract_terms hash of the contract terms
 * @param merchant_priv private key of the merchant
 * @param instance_id name of the instance
 * @param h_wire hash of the merchant's wire account into
 * @param amount_with_fee amount the exchange will deposit for this coin
 * @param deposit_fee fee the exchange will charge for this coin which the deposit was made
 * @param coin_pub public key of the deposited coin
 */
typedef void
(*TALER_MERCHANTDB_PendingDepositsCallback) (
  void *cls,
  uint64_t deposit_serial,
  struct GNUNET_TIME_Absolute wire_deadline,
  struct GNUNET_TIME_Absolute retry_time,
  const struct TALER_PrivateContractHashP *h_contract_terms,
  const struct TALER_MerchantPrivateKeyP *merchant_priv,
  const char *instance_id,
  const struct TALER_MerchantWireHashP *h_wire,
  const struct TALER_Amount *amount_with_fee,
  const struct TALER_Amount *deposit_fee,
  const struct TALER_CoinSpendPublicKeyP *coin_pub);


/**
 * Function called with detailed information about a wire transfer and
 * the underlying deposits that are being aggregated.
 *
 * @param cls closure
 * @param current_offset offset in the exchange reply we are at
 * @param ttd details about the transfer at @a current_offset
 */
typedef void
(*TALER_MERCHANTDB_TransferDetailsCallback)(
  void *cls,
  unsigned int current_offset,
  const struct TALER_TrackTransferDetails *ttd);


/**
 * Function called with information about a accounts
 * the wirewatcher should monitor.
 *
 * @param cls closure
 * @param instance instance that owns the account
 * @param payto_uri account URI
 * @param credit_facade_url URL for the credit facade
 * @param credit_facade_credentials account access credentials
 * @param last_serial last transaction serial (inclusive) we have seen from this account
 */
typedef void
(*TALER_MERCHANTDB_WirewatchWorkCallback)(
  void *cls,
  const char *instance,
  struct TALER_FullPayto payto_uri,
  const char *credit_facade_url,
  const json_t *credit_facade_credentials,
  uint64_t last_serial);


/**
 * Function called with information about a wire transfer.
 *
 * @param cls closure with a `json_t *` array to build up the response
 * @param expected_credit_amount how we expect to see wired to the merchant (minus fees), NULL if unknown
 * @param wtid wire transfer identifier
 * @param payto_uri target account that received the wire transfer
 * @param exchange_url base URL of the exchange that made the wire transfer
 * @param expected_transfer_serial_id serial number identifying the expected transfer in the backend
 * @param execution_time when did the exchange make the transfer, #GNUNET_TIME_UNIT_FOREVER_ABS
 *           if it did not yet happen
 * @param confirmed true if the merchant confirmed this wire transfer
 *                 false if it is so far only claimed to have been made by the exchange
 */
typedef void
(*TALER_MERCHANTDB_TransferCallback)(
  void *cls,
  const struct TALER_Amount *expected_credit_amount,
  const struct TALER_WireTransferIdentifierRawP *wtid,
  struct TALER_FullPayto payto_uri,
  const char *exchange_url,
  uint64_t expected_transfer_serial_id,
  struct GNUNET_TIME_Absolute execution_time,
  bool confirmed);


/**
 * Function called with information about expected incoming wire transfers.
 *
 * @param cls closure with a `json_t *` array to build up the response
 * @param expected_credit_amount how we expect to see wired to the merchant (minus fees), NULL if unknown
 * @param wtid wire transfer identifier
 * @param payto_uri target account that received the wire transfer
 * @param exchange_url base URL of the exchange that made the wire transfer
 * @param expected_transfer_serial_id serial number identifying the expected transfer in the backend
 * @param execution_time when did the exchange claim to have made the transfer
 * @param confirmed true if the merchant confirmed this wire transfer
 *                 false if it is so far only claimed to have been made by the exchange
 * @param validated true if the reconciliation succeeded
 * @param last_http_status HTTP status of our last request to the exchange for this transfer
 * @param last_ec last error code we got back (otherwise #TALER_EC_NONE)
 * @param last_error_detail last detail we got back (or NULL for none)
 */
typedef void
(*TALER_MERCHANTDB_IncomingCallback)(
  void *cls,
  const struct TALER_Amount *expected_credit_amount,
  const struct TALER_WireTransferIdentifierRawP *wtid,
  struct TALER_FullPayto payto_uri,
  const char *exchange_url,
  uint64_t expected_transfer_serial_id,
  struct GNUNET_TIME_Timestamp execution_time,
  bool confirmed,
  bool validated,
  unsigned int last_http_status,
  enum TALER_ErrorCode last_ec,
  const char *last_error_detail);


/**
 * If the given account is feasible, add it to the array
 * of accounts we return.
 *
 * @param cls closure
 * @param payto_uri URI of the account
 * @param conversion_url URL of a conversion service
 * @param debit_restrictions restrictions for debits from account
 * @param credit_restrictions restrictions for credits to account
 * @param master_sig signature affirming the account
 */
typedef void
(*TALER_MERCHANTDB_ExchangeAccountCallback) (
  void *cls,
  struct TALER_FullPayto payto_uri,
  const char *conversion_url,
  const json_t *debit_restrictions,
  const json_t *credit_restrictions,
  const struct TALER_MasterSignatureP *master_sig);


/**
 * Function called with information about a coin that was deposited.
 *
 * @param cls closure
 * @param deposit_serial which deposit operation is this about
 * @param exchange_url URL of the exchange that issued the coin
 * @param h_wire hash of merchant's wire details
 * @param deposit_timestamp when was the deposit made
 * @param amount_with_fee amount the exchange will deposit for this coin
 * @param deposit_fee fee the exchange will charge for this coin
 * @param coin_pub public key of the coin
 */
typedef void
(*TALER_MERCHANTDB_DepositedCoinsCallback)(
  void *cls,
  uint64_t deposit_serial,
  const char *exchange_url,
  const struct TALER_MerchantWireHashP *h_wire,
  struct GNUNET_TIME_Timestamp deposit_timestamp,
  const struct TALER_Amount *amount_with_fee,
  const struct TALER_Amount *deposit_fee,
  const struct TALER_CoinSpendPublicKeyP *coin_pub);


/**
 * Function called with information about a coin that was deposited.
 *
 * @param cls closure
 * @param exchange_url URL of the exchange that issued the coin
 * @param amount_with_fee amount the exchange will deposit for this coin
 * @param deposit_fee fee the exchange will charge for this coin
 * @param refund_fee fee the exchange will charge for refunding this coin
 * @param wire_fee wire fee the exchange charges
 * @param h_wire hash of merchant's wire details
 * @param deposit_timestamp when did the exchange receive the deposit
 * @param refund_deadline until when are refunds allowed
 * @param exchange_sig signature by the exchange
 * @param exchange_pub exchange signing key used for @a exchange_sig
 */
typedef void
(*TALER_MERCHANTDB_CoinDepositCallback)(
  void *cls,
  const char *exchange_url,
  const struct TALER_Amount *amount_with_fee,
  const struct TALER_Amount *deposit_fee,
  const struct TALER_Amount *refund_fee,
  const struct TALER_Amount *wire_fee,
  const struct TALER_MerchantWireHashP *h_wire,
  struct GNUNET_TIME_Timestamp deposit_timestamp,
  struct GNUNET_TIME_Timestamp refund_deadline,
  const struct TALER_ExchangeSignatureP *exchange_sig,
  const struct TALER_ExchangePublicKeyP *exchange_pub);


/**
 * Possible token family kinds.
 */
enum TALER_MERCHANTDB_TokenFamilyKind
{

  /**
   * Token family representing a discount token
   */
  TALER_MERCHANTDB_TFK_Discount = 0,

  /**
   * Token family representing a subscription token
   */
  TALER_MERCHANTDB_TFK_Subscription = 1,

};


/**
 * Typically called by `lookup_token_families`.
 *
 * @param cls a `json_t *` JSON array to build
 * @param slug slug of the token family
 * @param name name of the token family
 * @param description description of the token family
 * @param description_i18n Internationalized token family description.
 * @param start_time start time of the token family's validity period
 * @param expiration end time of the token family's validity period
 * @param kind kind of the token family
 */
typedef void
(*TALER_MERCHANTDB_TokenFamiliesCallback)(
  void *cls,
  const char *slug,
  const char *name,
  const char *description,
  const json_t *description_i18n,
  struct GNUNET_TIME_Timestamp start_time,
  struct GNUNET_TIME_Timestamp expiration,
  const char *kind);


/**
 * Details about a token family.
 */
struct TALER_MERCHANTDB_TokenFamilyDetails
{
  /**
   * Token family slug used for identification.
   */
  char *slug;

  /**
   * User readable name of the token family.
   */
  char *name;

  /**
   * Description of the token family.
   */
  char *description;

  /**
   * Internationalized token family description.
   */
  json_t *description_i18n;

  /**
   * Meta-data associated with the token family.
   * Includes information like "trusted_domains" or
   * "expected_domains", if set.
   */
  json_t *extra_data;

  /**
   * Cipher that should be used for this token family.  Note: We do not expose
   * this over the API and do not let clients set it. NULL for default (when
   * calling database).
   */
  char *cipher_spec;

  /**
   * Start time of the token family duration.
   */
  struct GNUNET_TIME_Timestamp valid_after;

  /**
   * End time of the token family duration.
   */
  struct GNUNET_TIME_Timestamp valid_before;

  /**
   * Validity duration of the token family. Must be larger or
   * equal to @a rounding plus @a start_offset_s.
   */
  struct GNUNET_TIME_Relative duration;

  /**
   * Rounding duration of the token family.
   */
  struct GNUNET_TIME_Relative validity_granularity;

  /**
   * Offset (in seconds) to subtract from the rounded
   * validity start period.
   */
  struct GNUNET_TIME_Relative start_offset;

  /**
   * Token family kind.
   */
  enum TALER_MERCHANTDB_TokenFamilyKind kind;

  /**
   * Counter for each issued token of this family.
   */
  uint64_t issued;

  /**
   * Counter for each used token of this family.
   */
  uint64_t used;
};


/**
 * Details about a token key.
 */
struct TALER_MERCHANTDB_TokenFamilyKeyDetails
{
  /**
   * Tokens signed with this key are valid from this date on.
   * This is the time the key was created.
   */
  struct GNUNET_TIME_Timestamp signature_validity_start; // valid_after;

  /**
   * Tokens signed with this key are valid until this date.
   */
  struct GNUNET_TIME_Timestamp signature_validity_end; // valid_before;

  /**
   * Private key expires for use at this time. Signatures can
   * only be created until this point.
   */
  struct GNUNET_TIME_Timestamp private_key_deleted_at;

  /**
   * Token family public key.
   */
  struct TALER_TokenIssuePublicKey pub;

  /**
   * Token family private key.
   */
  struct TALER_TokenIssuePrivateKey priv;

  /**
   * Details about the token family this key belongs to.
   */
  struct TALER_MERCHANTDB_TokenFamilyDetails token_family;
};


/**
 * Function called with applicable token keys.
 *
 * @param cls closure
 * @param details details about an applicable key
 */
typedef void
(*TALER_MERCHANTDB_TokenKeyCallback) (
  void *cls,
  const struct TALER_MERCHANTDB_TokenFamilyKeyDetails *details);


/**
 * Details about a spent token.
 */
struct TALER_MERCHANTDB_SpentTokenDetails
{
  /**
   * Public key of the spent token.
   */
  struct TALER_TokenUsePublicKeyP pub;

  /**
   * Signature that this token was spent on the specified order.
   */
  struct TALER_TokenUseSignatureP sig;

  /**
   * Blind signature for the spent token to prove validity of it.
   */
  struct TALER_BlindedTokenIssueSignature blind_sig;
};


/**
 * Function called with information about a token that was used.
 *
 * @param cls closure
 * @param spent_token_serial which used token is this about
 * @param h_contract_terms hash of the contract terms this token was used on
 * @param h_issue_pub hash of the token issue public key
 * @param use_pub token use public key
 * @param use_sig token use signature
 * @param issue_sig unblinded token issue signature
 */
typedef void
(*TALER_MERCHANTDB_UsedTokensCallback)(
  void *cls,
  uint64_t spent_token_serial,
  const struct TALER_PrivateContractHashP *h_contract_terms,
  const struct TALER_TokenIssuePublicKeyHashP *h_issue_pub,
  const struct TALER_TokenUsePublicKeyP *use_pub,
  const struct TALER_TokenUseSignatureP *use_sig,
  const struct TALER_TokenIssueSignature *issue_sig);


/**
 * Returns amount-valued statistics by bucket.
 * Called by `lookup_statistics_amount_by_bucket`.
 *
 * @param cls closure
 * @param description description of the statistic
 * @param bucket_start start time of the bucket
 * @param bucket_end end time of the bucket
 * @param bucket_range range of the bucket
 * @param cumulative_amounts_len the length of @a cumulative_amounts
 * @param cumulative_amounts the cumulative amounts array
 */
typedef void
(*TALER_MERCHANTDB_AmountByBucketStatisticsCallback)(
  void *cls,
  const char *description,
  struct GNUNET_TIME_Timestamp bucket_start,
  struct GNUNET_TIME_Timestamp bucket_end,
  const char *bucket_range,
  unsigned int cumulative_amounts_len,
  const struct TALER_Amount cumulative_amounts[static cumulative_amounts_len]);


/**
 * Returns amount-valued statistics over a particular time interval.
 * Called by `lookup_statistics_amount_by_interval`.
 *
 * @param cls closure
 * @param description description of the statistic
 * @param interval_start start time of the bucket
 * @param cumulative_amounts_len the length of @a cumulative_amounts
 * @param cumulative_amounts the cumulative amounts array
 */
typedef void
(*TALER_MERCHANTDB_AmountByIntervalStatisticsCallback)(
  void *cls,
  const char *description,
  struct GNUNET_TIME_Timestamp interval_start,
  unsigned int cumulative_amounts_len,
  const struct TALER_Amount cumulative_amounts[static cumulative_amounts_len]);


/**
 * Function returning integer-valued statistics for a bucket.
 * Called by `lookup_statistics_counter_by_bucket`.
 *
 * @param cls closure
 * @param description description of the statistic
 * @param bucket_start start time of the bucket
 * @param bucket_end end time of the bucket
 * @param bucket_range range of the bucket
 * @param cumulative_counter counter value
 */
typedef void
(*TALER_MERCHANTDB_CounterByBucketStatisticsCallback)(
  void *cls,
  const char *description,
  struct GNUNET_TIME_Timestamp bucket_start,
  struct GNUNET_TIME_Timestamp bucket_end,
  const char *bucket_range,
  uint64_t cumulative_counter);

/**
 * Details about a statistic with counter.
 */
struct TALER_MERCHANTDB_StatisticsCounterByBucketDetails
{
  /**
   * Start time of the bucket (inclusive).
   */
  struct GNUNET_TIME_Timestamp start_time;

  /**
   * End time of the bucket (exclusive).
   */
  struct GNUNET_TIME_Timestamp end_time;

  /**
   * Description of the statistic
   */
  char*description;

  /**
   * Range of the bucket
   */
  char *range;

  /**
   * Sum of all counters falling under the given
   * SLUG within this timeframe
   */
  uint64_t cumulative_number;
};

/**
 * Details about a statistic with counter.
 */
struct TALER_MERCHANTDB_StatisticsCounterByIntervalDetails
{
  /**
   * Start time of the interval.
   * The interval always ends at the response generation time.
   */
  struct GNUNET_TIME_Timestamp start_time;

  /**
   * Sum of all counters falling under the given
   * SLUG within this timeframe
   */
  uint64_t cumulative_counter;
};


/**
 * Function returning integer-valued statistics for a time interval.
 * Called by `lookup_statistics_counter_by_interval`.
 *
 * @param cls closure
 * @param description description of the statistic
 * @param interval_start start time of the interval
 * @param cumulative_counter counter value
 */
typedef void
(*TALER_MERCHANTDB_CounterByIntervalStatisticsCallback)(
  void *cls,
  const char *description,
  struct GNUNET_TIME_Timestamp interval_start,
  uint64_t cumulative_counter);


/**
 * Handle to interact with the database.
 *
 * Functions ending with "_TR" run their OWN transaction scope
 * and MUST NOT be called from within a transaction setup by the
 * caller.  Functions ending with "_NT" require the caller to
 * setup a transaction scope.  Functions without a suffix are
 * simple, single SQL queries that MAY be used either way.
 */
struct TALER_MERCHANTDB_Plugin
{

  /**
   * Closure for all callbacks.
   */
  void *cls;

  /**
   * Name of the library which generated this plugin.  Set by the
   * plugin loader.
   */
  char *library_name;

  /**
   * Connect to the database.
   *
   * @param cls closure
   */
  enum GNUNET_GenericReturnValue
    (*connect)(void *cls);

  /**
   * Drop merchant tables. Used for testcases and to reset the DB.
   *
   * @param cls closure
   * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
   */
  enum GNUNET_GenericReturnValue
    (*drop_tables)(void *cls);

  /**
   * Garbage collect database. Removes unnecessary data.
   *
   * @param cls closure
   * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
   */
  enum GNUNET_GenericReturnValue
    (*gc)(void *cls);

  /**
   * Initialize merchant tables
   *
   * @param cls closure
   * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
   */
  enum GNUNET_GenericReturnValue
    (*create_tables)(void *cls);

  /**
   * Register callback to be invoked on events of type @a es.
   *
   * @param cls database context to use
   * @param es specification of the event to listen for
   * @param timeout how long to wait for the event
   * @param cb function to call when the event happens, possibly
   *         multiple times (until cancel is invoked)
   * @param cb_cls closure for @a cb
   * @return handle useful to cancel the listener
   */
  struct GNUNET_DB_EventHandler *
  (*event_listen)(void *cls,
                  const struct GNUNET_DB_EventHeaderP *es,
                  struct GNUNET_TIME_Relative timeout,
                  GNUNET_DB_EventCallback cb,
                  void *cb_cls);

  /**
   * Stop notifications.
   *
   * @param eh handle to unregister.
   */
  void
  (*event_listen_cancel)(struct GNUNET_DB_EventHandler *eh);


  /**
   * Notify all that listen on @a es of an event.
   *
   * @param cls database context to use
   * @param es specification of the event to generate
   * @param extra additional event data provided
   * @param extra_size number of bytes in @a extra
   */
  void
  (*event_notify)(void *cls,
                  const struct GNUNET_DB_EventHeaderP *es,
                  const void *extra,
                  size_t extra_size);


  /**
   * Do a pre-flight check that we are not in an uncommitted transaction.  If
   * we are, die.  Does not return anything, as we will continue regardless of
   * the outcome.
   *
   * @param cls the `struct PostgresClosure` with the plugin-specific state
   */
  void
  (*preflight) (void *cls);

  /**
   * Start a transaction.
   *
   * @param cls the `struct PostgresClosure` with the plugin-specific state
   * @param name unique name identifying the transaction (for debugging),
   *             must point to a constant
   * @return #GNUNET_OK on success
   */
  enum GNUNET_GenericReturnValue
    (*start)(void *cls,
             const char *name);

  /**
   * Start a transaction with isolation level 'read committed'.
   *
   * @param cls the `struct PostgresClosure` with the plugin-specific state
   * @param name unique name identifying the transaction (for debugging),
   *             must point to a constant
   * @return #GNUNET_OK on success
   */
  enum GNUNET_GenericReturnValue
    (*start_read_committed)(void *cls,
                            const char *name);

  /**
   * Roll back the current transaction of a database connection.
   *
   * @param cls the `struct PostgresClosure` with the plugin-specific state
   */
  void
  (*rollback) (void *cls);

  /**
   * Commit the current transaction of a database connection.
   *
   * @param cls the `struct PostgresClosure` with the plugin-specific state
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*commit)(void *cls);

  /**
   * Lookup all of the instances this backend has configured.
   *
   * @param cls closure
   * @param active_only only find 'active' instances
   * @param cb function to call on all instances found
   * @param cb_cls closure for @a cb
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_instances)(void *cls,
                        bool active_only,
                        TALER_MERCHANTDB_InstanceCallback cb,
                        void *cb_cls);

  /**
   * Lookup one of the instances this backend has configured.
   *
   * @param cls closure
   * @param id ID of instance to look up
   * @param active_only only find 'active' instances
   * @param cb function to call on all instances found
   * @param cb_cls closure for @a cb
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_instance)(void *cls,
                       const char *id,
                       bool active_only,
                       TALER_MERCHANTDB_InstanceCallback cb,
                       void *cb_cls);

  /**
   * Lookup authentication data of an instance.
   *
   * @param cls closure
   * @param instance_id instance to query
   * @param[out] ias where to store the auth data
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_instance_auth)(void *cls,
                            const char *instance_id,
                            struct TALER_MERCHANTDB_InstanceAuthSettings *ias);


  /**
   * Insert information about an instance into our database.
   *
   * @param cls closure
   * @param merchant_pub public key of the instance
   * @param merchant_priv private key of the instance
   * @param is details about the instance
   * @param validation_needed true if validation is
   *        required before the instance can be used
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*insert_instance)(void *cls,
                       const struct TALER_MerchantPublicKeyP *merchant_pub,
                       const struct TALER_MerchantPrivateKeyP *merchant_priv,
                       const struct TALER_MERCHANTDB_InstanceSettings *is,
                       const struct TALER_MERCHANTDB_InstanceAuthSettings *ias,
                       bool validation_needed);


  /**
   * Insert information about an instance's account into our database.
   *
   * @param cls closure
   * @param account_details details about the account
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*insert_account)(
    void *cls,
    const struct TALER_MERCHANTDB_AccountDetails *account_details);


  /**
   * Insert instance login token into our database.
   *
   * @param cls closure
   * @param id identifier of the instance
   * @param token value of the token
   * @param creation_time the current time
   * @param expiration_time when does the token expire
   * @param validity_scope scope of the token
   * @param description description of the token
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*insert_login_token)(
    void *cls,
    const char *id,
    const struct TALER_MERCHANTDB_LoginTokenP *token,
    struct GNUNET_TIME_Timestamp creation_time,
    struct GNUNET_TIME_Timestamp expiration_time,
    uint32_t validity_scope,
    const char *description);


  /**
   * Lookup information about a login token from database.
   *
   * @param cls closure
   * @param id identifier of the instance
   * @param token value of the token
   * @param[out] expiration_time set to expiration time
   * @param[out] validity_scope set to scope of the token
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*select_login_token)(
    void *cls,
    const char *id,
    const struct TALER_MERCHANTDB_LoginTokenP *token,
    struct GNUNET_TIME_Timestamp *expiration_time,
    uint32_t *validity_scope);

  /**
   * Lookup login tokens for instance.
   *
   * @param cls closure
   * @param instance_id instance to lookup tokens for
   * @param offset transfer_serial number of the transfer we want to offset from
   * @param limit number of entries to return, negative for descending,
   *                positive for ascending
   * @param cb function to call on all products found
   * @param cb_cls closure for @a cb
   * @return database result code
    */
  enum GNUNET_DB_QueryStatus
    (*lookup_login_tokens)(void *cls,
                           const char *instance_id,
                           uint64_t offset,
                           int64_t limit,
                           TALER_MERCHANTDB_LoginTokensCallback cb,
                           void *cb_cls);

  /**
   * Delete login token from database.
   *
   * @param cls closure
   * @param id identifier of the instance
   * @param token value of the token
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*delete_login_token)(
    void *cls,
    const char *id,
    const struct TALER_MERCHANTDB_LoginTokenP *token);

  /**
   * Delete login token from database by serial.
   *
   * @param cls closure
   * @param id identifier of the instance
   * @param serial serial of the token
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*delete_login_token_serial)(
    void *cls,
    const char *id,
    uint64_t serial);


  /**
   * Update information about an instance's account into our database.
   *
   * @param cls closure
   * @param id identifier of the instance
   * @param h_wire which account to update
   * @param credit_facade_url new facade URL, can be NULL
   * @param credit_facade_credentials new credentials, can be NULL
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*update_account)(
    void *cls,
    const char *id,
    const struct TALER_MerchantWireHashP *h_wire,
    const char *credit_facade_url,
    const json_t *credit_facade_credentials);


  /**
   * Obtain information about an instance's accounts.
   *
   * @param cls closure
   * @param id identifier of the instance
   * @param cb function to call on each account
   * @param cb_cls closure for @a cb
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*select_accounts)(
    void *cls,
    const char *id,
    TALER_MERCHANTDB_AccountCallback cb,
    void *cb_cls);


  /**
   * Obtain detailed information about an instance's account.
   *
   * @param cls closure
   * @param id identifier of the instance
   * @param h_wire wire hash of the account
   * @param[out] ad account details returned
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*select_account)(
    void *cls,
    const char *id,
    const struct TALER_MerchantWireHashP *h_wire,
    struct TALER_MERCHANTDB_AccountDetails *ad);


  /**
 * Obtain detailed information about an instance's account.
 *
 * @param cls closure
 * @param id identifier of the instance
 * @param payto_uri URI of the account
 * @param[out] ad account details returned
 * @return database result code
 */
  enum GNUNET_DB_QueryStatus
    (*select_account_by_uri)(
    void *cls,
    const char *id,
    struct TALER_FullPayto payto_uri,
    struct TALER_MERCHANTDB_AccountDetails *ad);


  /**
   * Delete private key of an instance from our database.
   *
   * @param cls closure
   * @param merchant_id identifier of the instance
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*delete_instance_private_key)(
    void *cls,
    const char *merchant_id);

  /**
   * Purge an instance and all associated information from our database.
   * Highly likely to cause undesired data loss. Use with caution.
   *
   * @param cls closure
   * @param merchant_id identifier of the instance
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*purge_instance)(void *cls,
                      const char *merchant_id);

  /**
   * Update information about an instance into our database.
   *
   * @param cls closure
   * @param is details about the instance
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*update_instance)(void *cls,
                       const struct TALER_MERCHANTDB_InstanceSettings *is);

  /**
   * Update information about an instance's authentication settings
   * into our database.
   *
   * @param cls closure
   * @param merchant_id merchant backend instance ID
   * @param ias instance auth settings
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*update_instance_auth)(
    void *cls,
    const char *merchant_id,
    const struct TALER_MERCHANTDB_InstanceAuthSettings *ias);

  /**
   * Set an instance's account in our database to "inactive".
   *
   * @param cls closure
   * @param merchant_id merchant backend instance ID
   * @param h_wire hash of the wire account to set to inactive
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*inactivate_account)(void *cls,
                          const char *merchant_id,
                          const struct TALER_MerchantWireHashP *h_wire);


  /**
   * Set an instance's account in our database to "active".
   *
   * @param cls closure
   * @param merchant_id merchant backend instance ID
   * @param h_wire hash of the wire account to set to active
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*activate_account)(void *cls,
                        const char *merchant_id,
                        const struct TALER_MerchantWireHashP *h_wire);


  /**
   * Check an instance's account's KYC status.
   *
   * @param cls closure
   * @param merchant_id merchant backend instance ID
   * @param h_wire hash of the wire account to check,
   *        NULL to check all accounts of the merchant
   * @param exchange_url base URL of the exchange to check,
   *        NULL to check all exchanges
   * @param kyc_cb KYC status callback to invoke
   * @param kyc_cb_cls closure for @a kyc_cb
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*account_kyc_get_status)(
    void *cls,
    const char *merchant_id,
    const struct TALER_MerchantWireHashP *h_wire,
    const char *exchange_url,
    TALER_MERCHANTDB_KycCallback kyc_cb,
    void *kyc_cb_cls);

  /**
   * Check an account's KYC status at an exchange.
   *
   * @param cls closure
   * @param merchant_payto_uri  merchant backend instance ID
   * @param instance_id the instance for which to check
   * @param exchange_url base URL of the exchange
   * @param[out] auth_ok true if @a access_token was set
   * @param[out] access_token set to access token for /kyc-info
   * @param[out] kyc_ok true if no urgent KYC work must be done for this account
   * @param[out] last_http_status set to last HTTP status from exchange on /kyc-check
   * @param[out] last_ec set to last Taler error code from exchange on /kyc-check
   * @param[out] rule_gen set to decision row at the exchange, 0 if no
   *    known decision of the exchange exists for this record; used
   *    for long-polling for changes to exchange decisions
   * @param[out] last_kyc_check set to time of last KYC check
   * @param[out] aml_review set to true if the account is under AML review (if this exposed)
   * @param[out] jlimits set to JSON array with AccountLimits, NULL if unknown (and likely defaults apply or KYC auth is urgently needed, see @a auth_ok)
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*get_kyc_status)(
    void *cls,
    struct TALER_FullPayto merchant_account_uri,
    const char *instance_id,
    const char *exchange_url,
    bool *auth_ok,
    struct TALER_AccountAccessTokenP *access_token,
    bool *kyc_ok,
    unsigned int *last_http_status,
    enum TALER_ErrorCode *last_ec,
    uint64_t *rule_gen,
    struct GNUNET_TIME_Timestamp *last_kyc_check,
    bool *aml_review,
    json_t **jlimits);


  /**
   * Check an account's KYC limits at an exchange.
   *
   * @param cls closure
   * @param merchant_payto_uri  merchant backend instance ID
   * @param instance_id the instance for which to check
   * @param exchange_url base URL of the exchange
   * @param[out] kyc_ok true if no urgent KYC work must be done for this account
   * @param[out] no_access_token true if we do not have a valid KYC access token (KYC auth missing)
   * @param[out] jlimits set to JSON array with AccountLimits, NULL if unknown (and likely defaults apply or KYC auth is urgently needed, see @a auth_ok)
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*get_kyc_limits)(
    void *cls,
    struct TALER_FullPayto merchant_account_uri,
    const char *instance_id,
    const char *exchange_url,
    bool *kyc_ok,
    bool *no_access_token,
    json_t **jlimits);


  /**
   * Update an instance's account's KYC status.
   *
   * @param cls closure
   * @param merchant_id merchant backend instance ID
   * @param h_wire hash of the wire account to check
   * @param exchange_url base URL of the exchange to check
   * @param timestamp timestamp to store
   * @param exchange_http_status HTTP status code returned last by the exchange
   * @param exchange_ec_code Taler error code returned last by the exchange
   * @param rule_gen generation of the rule in the exchange database
   *      (useful for long-polling to wait for rule changes)
   * @param access_token access token for the KYC process, NULL for none
   * @param jlimits JSON array with AccountLimits returned by the exchange
   * @param in_aml_review true if the exchange says the account is under review
   * @param kyc_ok current KYC status (true for satisfied)
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*account_kyc_set_status)(
    void *cls,
    const char *merchant_id,
    const struct TALER_MerchantWireHashP *h_wire,
    const char *exchange_url,
    struct GNUNET_TIME_Timestamp timestamp,
    unsigned int exchange_http_status,
    enum TALER_ErrorCode exchange_ec_code,
    uint64_t rule_gen,
    const struct TALER_AccountAccessTokenP *access_token,
    const json_t *jlimits,
    bool in_aml_review,
    bool kyc_ok);


  /**
   * Set an instance's account's KYC status to failed.
   *
   * @param cls closure
   * @param merchant_id merchant backend instance ID
   * @param h_wire hash of the wire account to check
   * @param exchange_url base URL of the exchange to check
   * @param timestamp timestamp to store
   * @param exchange_http_status HTTP status code returned last by the exchange
   * @param kyc_ok current KYC status (should be false)
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*account_kyc_set_failed)(
    void *cls,
    const char *merchant_id,
    const struct TALER_MerchantWireHashP *h_wire,
    const char *exchange_url,
    struct GNUNET_TIME_Timestamp timestamp,
    unsigned int exchange_http_status,
    bool kyc_ok);


  /**
   * Lookup all of the products the given instance has configured.
   *
   * @param cls closure
   * @param instance_id instance to lookup products for
   * @param offset transfer_serial number of the transfer we want to offset from
   * @param limit number of entries to return, negative for descending,
   *                positive for ascending
   * @param category_filter filter products by category, NULL to not filter;
   *                uses the Postgresql "LIKE" pattern matcher, so
   *                "%" stands for any sequence of zero or more characters,
   *                "_" stands for any single character;
   *                use "\%" and "\_" to exactly match "%" or "_".
   *                We will always use case-insensitive searches, for case-sensitive
   *                matching the client should filter the result set.
   * @param name_filter filter products by name, NULL to not filter
   *                uses the Postgresql "LIKE" pattern matcher, so
   *                "%" stands for any sequence of zero or more characters,
   *                "_" stands for any single character
   *                use "\%" and "\_" to exactly match "%" or "_".
   *                We will always use case-insensitive searches, for case-sensitive
   *                matching the client should filter the result set.
   * @param description_filter filter products by description, NULL to not filter
   *                uses the Postgresql "LIKE" pattern matcher, so
   *                "%" stands for any sequence of zero or more characters,
   *                "_" stands for any single character
   *                use "\%" and "\_" to exactly match "%" or "_".
   *                We will always use case-insensitive searches, for case-sensitive
   *                matching the client should filter the result set.
   * @param cb function to call on all products found
   * @param cb_cls closure for @a cb
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_products)(void *cls,
                       const char *instance_id,
                       uint64_t offset,
                       int64_t limit,
                       const char *category_filter,
                       const char *name_filter,
                       const char *description_filter,
                       TALER_MERCHANTDB_ProductsCallback cb,
                       void *cb_cls);


  /**
   * Lookup full details of all of the products the given instance has configured (expensive).
   *
   * @param cls closure
   * @param instance_id instance to lookup products for
   * @param cb function to call on all products found
   * @param cb_cls closure for @a cb
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_all_products)(void *cls,
                           const char *instance_id,
                           TALER_MERCHANTDB_ProductCallback cb,
                           void *cb_cls);

  /**
   * Lookup details about a particular product.
   *
   * @param cls closure
   * @param instance_id instance to lookup products for
   * @param product_id product to lookup
   * @param[out] pd set to the product details on success, can be NULL
   *             (in that case we only want to check if the product exists)
   * @param[out] num_categories set to length of @a categories array
   * @param[out] categories set to array of categories the
   *   product is in, caller must free() it.
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_product)(void *cls,
                      const char *instance_id,
                      const char *product_id,
                      struct TALER_MERCHANTDB_ProductDetails *pd,
                      size_t *num_categories,
                      uint64_t **categories);
  /**
   * Lookup product image by its hash.
   *
   * @param cls closure
   * @param instance_id instance to lookup products for
   * @param image_hash lowercase hexadecimal representation of the SHA256 hash
   * @param[out] image set to base64-encoded data URL on success, caller must free()
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_product_image_by_hash)(void *cls,
                                    const char *instance_id,
                                    const char *image_hash,
                                    char **image);

  /**
   * Delete information about a product. Note that the transaction must
   * enforce that no stocks are currently locked.
   *
   * @param cls closure
   * @param instance_id instance to delete product of
   * @param product_id product to delete
   * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
   *           if locks prevent deletion OR product unknown
   */
  enum GNUNET_DB_QueryStatus
    (*delete_product)(void *cls,
                      const char *instance_id,
                      const char *product_id);

  /**
   * Insert details about a particular product.
   *
   * @param cls closure
   * @param instance_id instance to insert product for
   * @param product_id product identifier of product to insert
   * @param pd the product details to insert
   * @param num_cats length of @a cats array
   * @param cats array of categories the product is in
   * @param[out] no_instance set to true if @a instance_id is unknown
   * @param[out] conflict set to true if a conflicting
   *        product already exists in the database
   * @param[out] no_cat set to index of non-existing category from @a cats, or -1 if all @a cats were found
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*insert_product)(void *cls,
                      const char *instance_id,
                      const char *product_id,
                      const struct TALER_MERCHANTDB_ProductDetails *pd,
                      size_t num_cats,
                      const uint64_t *cats,
                      bool *no_instance,
                      bool *conflict,
                      ssize_t *no_cat);

  /**
   * Update details about a particular product. Note that the
   * transaction must enforce that the sold/stocked/lost counters
   * are not reduced (i.e. by expanding the WHERE clause on the existing
   * values).
   *
   * @param cls closure
   * @param instance_id instance to lookup products for
   * @param product_id product to lookup
   * @param pd product details with updated values
   * @param num_cats length of @a cats array
   * @param cats number of categories the product is in
   * @param[out] no_instance the update failed as the instance is unknown
   * @param[out] no_cat set to -1 on success, otherwise the update failed and this is set
   *                to the index of a category in @a cats that is unknown
   * @param[out] no_product the @a product_id is unknown
   * @param[out] lost_reduced the update failed as the counter of units lost would have been lowered
   * @param[out] sold_reduced the update failed as the counter of units sold would have been lowered
   * @param[out] stocked_reduced the update failed as the counter of units stocked would have been lowered
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*update_product)(void *cls,
                      const char *instance_id,
                      const char *product_id,
                      const struct TALER_MERCHANTDB_ProductDetails *pd,
                      size_t num_cats,
                      const uint64_t *cats,
                      bool *no_instance,
                      ssize_t *no_cat,
                      bool *no_product,
                      bool *lost_reduced,
                      bool *sold_reduced,
                      bool *stocked_reduced);

  /**
   * Lock stocks of a particular product. Note that the transaction must
   * enforce that the "stocked-sold-lost >= locked" constraint holds.
   *
   * @param cls closure
   * @param instance_id instance to lookup products for
   * @param product_id product to lookup
   * @param uuid the UUID that holds the lock
   * @param quantity how many units should be locked
   * @param quantity_frac fractional component of units to lock, in units of
   *        1/1000000 of the base value
   * @param expiration_time when should the lock expire
   * @return database result code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the
   *         product is unknown OR if there insufficient stocks remaining
   */
  enum GNUNET_DB_QueryStatus
    (*lock_product)(void *cls,
                    const char *instance_id,
                    const char *product_id,
                    const struct GNUNET_Uuid *uuid,
                    uint64_t quantity,
                    uint32_t quantity_frac,
                    struct GNUNET_TIME_Timestamp expiration_time);


  /**
   * Release all expired product locks, including
   * those from expired offers -- across all
   * instances.
   *
   * @param cls closure
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*expire_locks)(void *cls);


  /**
   * Delete information about an order. Note that the transaction must
   * enforce that the order is not awaiting payment anymore.
   *
   * @param cls closure
   * @param instance_id instance to delete order of
   * @param order_id order to delete
   * @param force force deletion of claimed but unpaid orders
   * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
   *           if locks prevent deletion OR order unknown
   */
  enum GNUNET_DB_QueryStatus
    (*delete_order)(void *cls,
                    const char *instance_id,
                    const char *order_id,
                    bool force);


  /**
   * Retrieve order given its @a order_id and the @a instance_id.
   *
   * @param cls closure
   * @param instance_id instance to obtain order of
   * @param order_id order id used to perform the lookup
   * @param[out] claim_token the claim token generated for the order,
   *             NULL to only test if the order exists
   * @param[out] h_post_data set to the hash of the POST data that created the order
   * @param[out] contract_terms where to store the retrieved contract terms,
   *             NULL to only test if the order exists
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_order)(void *cls,
                    const char *instance_id,
                    const char *order_id,
                    struct TALER_ClaimTokenP *claim_token,
                    struct TALER_MerchantPostDataHashP *h_post_data,
                    json_t **contract_terms);


  /**
   * Retrieve order summary given its @a order_id and the @a instance_id.
   *
   * @param cls closure
   * @param instance_id instance to obtain order of
   * @param order_id order id used to perform the lookup
   * @param[out] timestamp when was the order created
   * @param[out] order_serial under which serial do we keep this order
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_order_summary)(void *cls,
                            const char *instance_id,
                            const char *order_id,
                            struct GNUNET_TIME_Timestamp *timestamp,
                            uint64_t *order_serial);


  /**
   * Retrieve orders given the @a instance_id.
   *
   * @param cls closure
   * @param instance_id instance to obtain order of
   * @param of filter to apply when looking up orders
   * @param[out] contract_terms where to store the retrieved contract terms,
   *             NULL to only test if the order exists
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_orders)(void *cls,
                     const char *instance_id,
                     const struct TALER_MERCHANTDB_OrderFilter *of,
                     TALER_MERCHANTDB_OrdersCallback cb,
                     void *cb_cls);


  /**
   * Insert order into db.
   *
   * @param cls closure
   * @param instance_id identifies the instance responsible for the order
   * @param order_id alphanumeric string that uniquely identifies the order
   * @param session_id session ID for the order
   * @param h_post_data hash of the POST data for idempotency checks
   * @param pay_deadline how long does the customer have to pay for the order
   * @param claim_token token to use for access control
   * @param contract_terms proposal data to store
   * @param pos_key encoded key for payment verification
   * @param pos_algorithm algorithm to compute the payment verification
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*insert_order)(void *cls,
                    const char *instance_id,
                    const char *order_id,
                    const char *session_id,
                    const struct TALER_MerchantPostDataHashP *h_post_data,
                    struct GNUNET_TIME_Timestamp pay_deadline,
                    const struct TALER_ClaimTokenP *claim_token,
                    const json_t *contract_terms,
                    const char *pos_key,
                    enum TALER_MerchantConfirmationAlgorithm pos_algorithm);


  /**
   * Insert blinded signatures for an order.
   *
   * @param cls closure
   * @param order_id order ID to insert blinded signatures for
   * @param i index of the blinded signature in the output array
   * @param hash hash of the token
   * @param blinded_sigs JSON array of blinded signatures
   */
  enum GNUNET_DB_QueryStatus
    (*insert_order_blinded_sigs)(
    void *cls,
    const char *order_id,
    uint32_t i,
    const struct GNUNET_HashCode *hash,
    const struct GNUNET_CRYPTO_BlindedSignature *blind_sig);


  /**
   * Release an inventory lock by UUID. Releases ALL stocks locked under
   * the given UUID.
   *
   * @param cls closure
   * @param uuid the UUID to release locks for
   * @return transaction status,
   *   #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS means there are no locks under @a uuid
   *   #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT indicates success
   */
  enum GNUNET_DB_QueryStatus
    (*unlock_inventory)(void *cls,
                        const struct GNUNET_Uuid *uuid);


  /**
   * Lock inventory stock to a particular order.
   *
   * @param cls closure
   * @param instance_id identifies the instance responsible for the order
   * @param order_id alphanumeric string that uniquely identifies the order
   * @param product_id uniquely identifies the product to be locked
   * @param quantity how many units should be locked to the @a order_id
   * @param quantity_frac fractional component of the quantity to be locked,
   *        in units of 1/1000000 of the base value
   * @return transaction status,
   *   #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS means there are insufficient stocks
   *   #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT indicates success
   */
  enum GNUNET_DB_QueryStatus
    (*insert_order_lock)(void *cls,
                         const char *instance_id,
                         const char *order_id,
                         const char *product_id,
                         uint64_t quantity,
                         uint32_t quantity_frac);


  /**
   * Select blinded signatures for an order.
   *
   * @param cls closure
   * @param order_id order ID to select blinded signatures for
   * @param cb callback to call for each blinded signature found
   * @param cb_cls closure for @a cb
   */
  enum GNUNET_DB_QueryStatus
    (*select_order_blinded_sigs)(
    void *cls,
    const char *order_id,
    TALER_MERCHANTDB_BlindedSigCallback cb,
    void *cb_cls);


  /**
   * Retrieve contract terms given its @a order_id
   *
   * @param cls closure
   * @param instance_id instance's identifier
   * @param order_id order_id used to lookup.
   * @param[out] contract_terms where to store the result, NULL to only check for existence
   * @param[out] order_serial set to the order's serial number
   * @param[out] paid set to true if the order is fully paid
   * @param[out] claim_token set to the claim token, NULL to only check for existence
   * @param[out] pos_key encoded key for payment verification
   * @param[out] pos_algorithm set to algorithm to compute the payment verification
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_contract_terms2)(
    void *cls,
    const char *instance_id,
    const char *order_id,
    json_t **contract_terms,
    uint64_t *order_serial,
    bool *paid,
    struct TALER_ClaimTokenP *claim_token,
    char **pos_key,
    enum TALER_MerchantConfirmationAlgorithm *pricing_algorithm);


  /**
   * Retrieve contract terms given its @a order_id
   *
   * @param cls closure
   * @param instance_id instance's identifier
   * @param order_id order_id used to lookup
   * @param session_id session_id to compare, can be NULL
   * @param[out] contract_terms where to store the result, NULL to only check for existence
   * @param[out] order_serial set to the order's serial number
   * @param[out] paid set to true if the order is fully paid
   * @param[out] wired set to true if the exchange wired the funds
   * @param[out] session_matches set to true if @a session_id matches session stored for this contract
   * @param[out] claim_token set to the claim token, NULL to only check for existence
   * @param[out] choice_index set to the choice index, -1 if not set
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_contract_terms3)(
    void *cls,
    const char *instance_id,
    const char *order_id,
    const char *session_id,
    json_t **contract_terms,
    uint64_t *order_serial,
    bool *paid,
    bool *wired,
    bool *session_matches,
    struct TALER_ClaimTokenP *claim_token,
    int16_t *choice_index);


  /**
   * Retrieve contract terms given its @a order_id
   *
   * @param cls closure
   * @param instance_id instance's identifier
   * @param order_id order_id used to lookup.
   * @param[out] contract_terms where to store the result, NULL to only check for existence
   * @param[out] order_serial set to the order's serial number
   * @param[out] claim_token set to the claim token, NULL to only check for existence
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_contract_terms)(
    void *cls,
    const char *instance_id,
    const char *order_id,
    json_t **contract_terms,
    uint64_t *order_serial,
    struct TALER_ClaimTokenP *claim_token);


  /**
   * Store contract terms given its @a order_id. Note that some attributes are
   * expected to be calculated inside of the function, like the hash of the
   * contract terms (to be hashed), the creation_time and pay_deadline (to be
   * obtained from the merchant_orders table). The "session_id" should be
   * initially set to the empty string.  The "fulfillment_url" and "refund_deadline"
   * must be extracted from @a contract_terms.
   *
   * @param cls closure
   * @param instance_id instance's identifier
   * @param order_id order_id used to store
   * @param claim_token the token belonging to the order
   * @param[out] order_serial set to the serial of the order
   * @return transaction status, #GNUNET_DB_STATUS_HARD_ERROR if @a contract_terms
   *          is malformed
   */
  enum GNUNET_DB_QueryStatus
    (*insert_contract_terms)(
    void *cls,
    const char *instance_id,
    const char *order_id,
    json_t *contract_terms,
    uint64_t *order_serial);


  /**
   * Update the contract terms stored for @a order_id. Note that some attributes are
   * expected to be calculated inside of the function, like the hash of the
   * contract terms (to be hashed), the creation_time and pay_deadline (to be
   * obtained from the merchant_orders table). The "session_id" should be
   * initially set to the empty string.  The "fulfillment_url" and "refund_deadline"
   * must be extracted from @a contract_terms.
   *
   * @param cls closure
   * @param instance_id instance's identifier
   * @param order_id order_id used to store
   * @param contract_terms contract to store
   * @return transaction status, #GNUNET_DB_STATUS_HARD_ERROR if @a contract_terms
   *          is malformed
   */
  enum GNUNET_DB_QueryStatus
    (*update_contract_terms)(void *cls,
                             const char *instance_id,
                             const char *order_id,
                             json_t *contract_terms);


  /**
   * Delete information about a contract. Note that the transaction must
   * enforce that the contract is not awaiting payment anymore AND was not
   * paid, or is past the legal expiration.
   *
   * @param cls closure
   * @param instance_id instance to delete order of
   * @param order_id order to delete
   * @param legal_expiration how long do we need to keep (paid) contracts on
   *          file for legal reasons (i.e. taxation)
   * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
   *           if locks prevent deletion OR order unknown
   */
  enum GNUNET_DB_QueryStatus
    (*delete_contract_terms)(void *cls,
                             const char *instance_id,
                             const char *order_id,
                             struct GNUNET_TIME_Relative legal_expiration);


  /**
   * Lookup information about coins that were successfully deposited for a
   * given contract.
   *
   * @param cls closure
   * @param instance_id instance to lookup deposits for
   * @param h_contract_terms proposal data's hashcode
   * @param cb function to call with payment data
   * @param cb_cls closure for @a cb
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_deposits)(void *cls,
                       const char *instance_id,
                       const struct TALER_PrivateContractHashP *h_contract_terms
                       ,
                       TALER_MERCHANTDB_DepositsCallback cb,
                       void *cb_cls);


  /**
   * Insert an exchange signing key into our database.
   *
   * @param cls closure
   * @param master_pub exchange master public key used for @a master_sig
   * @param exchange_pub exchange signing key to insert
   * @param start_date when does the signing key become valid
   * @param expire_date when does the signing key stop being used
   * @param end_date when does the signing key become void as proof
   * @param master_sig signature of @a master_pub over the @a exchange_pub and the dates
   */
  enum GNUNET_DB_QueryStatus
    (*insert_exchange_signkey)(
    void *cls,
    const struct TALER_MasterPublicKeyP *master_pub,
    const struct TALER_ExchangePublicKeyP *exchange_pub,
    struct GNUNET_TIME_Timestamp start_date,
    struct GNUNET_TIME_Timestamp expire_date,
    struct GNUNET_TIME_Timestamp end_date,
    const struct TALER_MasterSignatureP *master_sig);


  /**
   * Insert deposit confirmation from the exchange into the database.
   *
   * @param cls closure
   * @param instance_id instance to lookup deposits for
   * @param deposit_timestamp time when the exchange generated the deposit confirmation
   * @param h_contract_terms proposal data's hashcode
   * @param exchange_url URL of the exchange that issued @a coin_pub
   * @param wire_transfer_deadline when do we expect the wire transfer from the exchange
   * @param total_without_fees deposited total in the batch without fees
   * @param wire_fee wire fee the exchange charges
   * @param h_wire hash of the wire details of the target account of the merchant
   * @param exchange_sig signature from exchange that coin was accepted
   * @param exchange_pub signing key that was used for @a exchange_sig
   * @param[out] batch_deposit_serial_id set to the table row
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*insert_deposit_confirmation)(
    void *cls,
    const char *instance_id,
    struct GNUNET_TIME_Timestamp deposit_timestamp,
    const struct TALER_PrivateContractHashP *h_contract_terms,
    const char *exchange_url,
    struct GNUNET_TIME_Timestamp wire_transfer_deadline,
    const struct TALER_Amount *total_without_fees,
    const struct TALER_Amount *wire_fee,
    const struct TALER_MerchantWireHashP *h_wire,
    const struct TALER_ExchangeSignatureP *exchange_sig,
    const struct TALER_ExchangePublicKeyP *exchange_pub,
    uint64_t *batch_deposit_serial_id);


  /**
   * Insert information about coin deposited as part of
   * a batch into the database.
   *
   * @param cls closure
   * @param offset offset of the coin in the batch
   * @param deposit_confirmation_serial_id deposit confirmation for the batch the coin is part of
   * @param coin_pub public key of the coin
   * @param coin_sig deposit signature of the coin
   * @param amount_with_fee amount the exchange will deposit for this coin
   * @param deposit_fee fee the exchange will charge for this coin
   * @param refund_fee fee the exchange will charge for refunds of coin
   * @param check_time at what time should we check the deposit status
   *        with the exchange (for settlement)
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*insert_deposit)(
    void *cls,
    uint32_t offset,
    uint64_t deposit_confirmation_serial_id,
    const struct TALER_CoinSpendPublicKeyP *coin_pub,
    const struct TALER_CoinSpendSignatureP *coin_sig,
    const struct TALER_Amount *amount_with_fee,
    const struct TALER_Amount *deposit_fee,
    const struct TALER_Amount *refund_fee,
    struct GNUNET_TIME_Absolute check_time);


  /**
   * Obtain refunds associated with a contract.
   *
   * @param cls closure, typically a connection to the db
   * @param instance_id instance to lookup refunds for
   * @param h_contract_terms hash code of the contract
   * @param rc function to call for each coin on which there is a refund
   * @param rc_cls closure for @a rc
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_refunds)(void *cls,
                      const char *instance_id,
                      const struct TALER_PrivateContractHashP *h_contract_terms,
                      TALER_MERCHANTDB_RefundCallback rc,
                      void *rc_cls);


  /**
   * Retrieve details about tokens that were used for an order.
   *
   * @param cls closure
   * @param order_serial identifies the order
   * @param cb function to call for each used token
   * @param cb_cls closure for @a cb
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_spent_tokens_by_order)(void *cls,
                                    uint64_t order_serial,
                                    TALER_MERCHANTDB_UsedTokensCallback cb,
                                    void *cb_cls);


  /**
   * Mark contract as paid and store the current @a session_id
   * for which the contract was paid. Deletes the underlying order
   * and marks the locked stocks of the order as sold.
   *
   * @param cls closure
   * @param instance_id instance to mark contract as paid for
   * @param h_contract_terms hash of the contract that is now paid
   * @param session_id the session that paid the contract
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*mark_contract_paid)(
    void *cls,
    const char *instance_id,
    const struct TALER_PrivateContractHashP *h_contract_terms,
    const char *session_id,
    int16_t choice_index);


  /**
   * Update session associated with a contract and return
   * the fulfillment URL and the refund status.
   *
   * @param cls closure
   * @param instance_id instance to mark contract as paid for
   * @param h_contract_terms hash of the contract that is now paid
   * @param session_id the session that paid the contract
   * @param[out] fulfillment_url set to the fulfillment URL (possibly NULL)
   * @param[out] refunded set to true if the order was refunded
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*update_contract_session)(
    void *cls,
    const char *instance_id,
    const struct TALER_PrivateContractHashP *h_contract_terms,
    const char *session_id,
    char **fulfillment_url,
    bool *refunded);


  /**
   * Function called during aborts to refund a coin. Marks the
   * respective coin as refunded.
   *
   * @param cls closure
   * @param instance_id instance to refund payment for
   * @param h_contract_terms hash of the contract to refund coin for
   * @param refund_timestamp timestamp of when the coin was refunded
   * @param coin_pub public key of the coin to refund (fully)
   * @param reason text justifying the refund
   * @return transaction status
   *        #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if @a coin_pub is unknown to us;
   *        #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if the request is valid,
   *        regardless of whether it actually increased the refund
   */
  enum GNUNET_DB_QueryStatus
    (*refund_coin)(void *cls,
                   const char *instance_id,
                   const struct TALER_PrivateContractHashP *h_contract_terms,
                   struct GNUNET_TIME_Timestamp refund_timestamp,
                   const struct TALER_CoinSpendPublicKeyP *coin_pub,
                   const char *reason);


  /**
   * Retrieve contract terms given its @a order_id
   *
   * @param cls closure
   * @param instance_id instance's identifier
   * @param order_id order to lookup contract for
   * @param[out] h_contract_terms set to the hash of the contract.
   * @param[out] paid set to the payment status of the contract
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_order_status)(void *cls,
                           const char *instance_id,
                           const char *order_id,
                           struct TALER_PrivateContractHashP *h_contract_terms,
                           bool *paid);

  /**
   * Retrieve contract terms given its @a order_serial
   *
   * @param cls closure
   * @param instance_id instance's identifier
   * @param order_serial serial ID of the order to look up
   * @param[out] order_id set to ID of the order
   * @param[out] h_contract_terms set to the hash of the contract.
   * @param[out] paid set to the payment status of the contract
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_order_status_by_serial)(void *cls,
                                     const char *instance_id,
                                     uint64_t order_serial,
                                     char **order_id,
                                     struct TALER_PrivateContractHashP *
                                     h_contract_terms,
                                     bool *paid);


  /**
   * Retrieve details about coins that were deposited for an order.
   *
   * @param cls closure
   * @param order_serial identifies the order
   * @param cb function to call for each deposited coin
   * @param cb_cls closure for @a cb
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_deposits_by_order)(void *cls,
                                uint64_t order_serial,
                                TALER_MERCHANTDB_DepositedCoinsCallback cb,
                                void *cb_cls);


  /**
   * Retrieve wire transfer details for all deposits associated with
   * a given @a order_serial.
   *
   * @param cls closure
   * @param order_serial identifies the order
   * @param cb function called with the wire transfer details
   * @param cb_cls closure for @a cb
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_transfer_details_by_order)(
    void *cls,
    uint64_t order_serial,
    TALER_MERCHANTDB_OrderTransferDetailsCallback cb,
    void *cb_cls);


  /**
   * Update transfer status.
   *
   * @param cls closure
   * @param exchange_url the exchange that made the transfer
   * @param wtid wire transfer subject
   * @param next_attempt when should we try again (if ever)
   * @param http_status last HTTP status code from the server, 0 for timeout
   * @param ec current error state of checking the transfer
   * @param detail last error detail from the server, possibly NULL
   * @param needs_retry true if we should retry the request
   * @return database transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*update_transfer_status)(
    void *cls,
    const char *exchange_url,
    const struct TALER_WireTransferIdentifierRawP *wtid,
    struct GNUNET_TIME_Absolute next_attempt,
    unsigned int http_status,
    enum TALER_ErrorCode ec,
    const char *detail,
    bool needs_retry);


  /**
   * Finalize transfer status with success.
   *
   * @param cls closure
   * @param exchange_url the exchange that made the transfer
   * @param wtid wire transfer subject
   * @param h_details hash over all of the aggregated deposits
   * @param total_amount total amount exchange claimed to have transferred
   * @param wire_fee wire fee charged by the exchange
   * @param exchange_pub key used to make @e exchange_sig
   * @param exchange_sig signature of the exchange over reconciliation data
   * @return database transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*finalize_transfer_status)(
    void *cls,
    const char *exchange_url,
    const struct TALER_WireTransferIdentifierRawP *wtid,
    const struct GNUNET_HashCode *h_details,
    const struct TALER_Amount *total_amount,
    const struct TALER_Amount *wire_fee,
    const struct TALER_ExchangePublicKeyP *exchange_pub,
    const struct TALER_ExchangeSignatureP *exchange_sig);


  /**
   * Retrieve wire transfer details of wire details
   * that taler-merchant-exchange still needs to
   * investigate.
   *
   * @param cls closure
   * @param limit maximum number of results to return
   * @param cb function called with the wire transfer data
   * @param cb_cls closure for @a cb
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*select_open_transfers)(
    void *cls,
    uint64_t limit,
    TALER_MERCHANTDB_OpenTransferCallback cb,
    void *cb_cls);


  /**
   * Insert wire transfer details for a deposit.
   *
   * @param cls closure
   * @param deposit_serial serial number of the deposit
   * @param h_wire hash of the merchant's account that should receive the deposit
   * @param exchange_url URL of the exchange that is making the deposit
   * @param dd deposit transfer data from the exchange to store
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*insert_deposit_to_transfer)(void *cls,
                                  uint64_t deposit_serial,
                                  const struct TALER_MerchantWireHashP *h_wire,
                                  const char *exchange_url,
                                  const struct TALER_EXCHANGE_DepositData *dd);


  /**
   * Set 'wired' status for an order to 'true'.
   *
   * @param cls closure
   * @param order_serial serial number of the order
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*mark_order_wired)(void *cls,
                        uint64_t order_serial);


  /**
   * Function called when some backoffice staff decides to award or
   * increase the refund on an existing contract.  This function
   * MUST be called from within a transaction scope setup by the
   * caller as it executes multiple SQL statements.
   *
   * @param cls closure
   * @param instance_id instance identifier
   * @param order_id the order to increase the refund for
   * @param refund maximum refund to return to the customer for this contract
   * @param olc function to call to obtain legal refund
   *    limits per exchange, NULL for no limits
   * @param olc_cls closure for @a olc
   * @param reason 0-terminated UTF-8 string giving the reason why the customer
   *               got a refund (free form, business-specific)
   * @return transaction status
   *        #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if @a refund is ABOVE the amount we
   *        were originally paid and thus the transaction failed;
   *        #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if the request is valid,
   *        regardless of whether it actually increased the refund beyond
   *        what was already refunded (idempotency!)
   */
  enum TALER_MERCHANTDB_RefundStatus
    (*increase_refund)(
    void *cls,
    const char *instance_id,
    const char *order_id,
    const struct TALER_Amount *refund,
    TALER_MERCHANTDB_OperationLimitCallback olc,
    void *olc_cls,
    const char *reason);


  /**
   * Obtain detailed refund data associated with a contract.
   *
   * @param cls closure, typically a connection to the db
   * @param instance_id instance to lookup refunds for
   * @param h_contract_terms hash code of the contract
   * @param rc function to call for each coin on which there is a refund
   * @param rc_cls closure for @a rc
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_refunds_detailed)(
    void *cls,
    const char *instance_id,
    const struct TALER_PrivateContractHashP *h_contract_terms,
    TALER_MERCHANTDB_RefundDetailCallback rc,
    void *rc_cls);

  /**
   * Insert refund proof data from the exchange into the database.
   *
   * @param cls closure
   * @param refund_serial serial number of the refund
   * @param exchange_sig signature from exchange that coin was refunded
   * @param exchange_pub signing key that was used for @a exchange_sig
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*insert_refund_proof)(
    void *cls,
    uint64_t refund_serial,
    const struct TALER_ExchangeSignatureP *exchange_sig,
    const struct TALER_ExchangePublicKeyP *exchange_pub);


  /**
   * Insert used token into the database.
   *
   * @param cls closure
   * @param h_contract_terms hash of the contract the token was used for
   * @param h_issue_pub hash of the token issue public key
   * @param use_pub token use public key
   * @param use_sig token use signature
   * @param issue_sig token issue signature
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*insert_spent_token)(
    void *cls,
    const struct TALER_PrivateContractHashP *
    h_contract_terms,
    const struct TALER_TokenIssuePublicKeyHashP *h_issue_pub,
    const struct TALER_TokenUsePublicKeyP *use_pub,
    const struct TALER_TokenUseSignatureP *use_sig,
    const struct TALER_TokenIssueSignature *issue_sig);


  /**
   * Insert issued token into the database.
   *
   * @param cls closure
   * @param h_contract_terms hash of the contract the token was issued for
   * @param h_issue_pub hash of the token issue public key used to sign the issued token
   * @param blind_sig resulting blind token issue signature
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*insert_issued_token)(
    void *cls,
    const struct TALER_PrivateContractHashP *h_contract_terms,
    const struct TALER_TokenIssuePublicKeyHashP *h_issue_pub,
    const struct TALER_BlindedTokenIssueSignature *blind_sig);


  /**
   * Lookup refund proof data.
   *
   * @param cls closure
   * @param refund_serial serial number of the refund
   * @param[out] exchange_sig set to signature from exchange
   * @param[out] exchange_pub signing key that was used for @a exchange_sig
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_refund_proof)(
    void *cls,
    uint64_t refund_serial,
    struct TALER_ExchangeSignatureP *exchange_sig,
    struct TALER_ExchangePublicKeyP *exchange_pub);


  /**
   * Retrieve the order ID that was used to pay for a resource within a session.
   *
   * @param cls closure
   * @param instance_id instance to lookup the order from
   * @param fulfillment_url URL that canonically identifies the resource
   *        being paid for
   * @param session_id session id
   * @param allow_refunded_for_repurchase true to include refunded orders in repurchase detection
   * @param[out] order_id location to store the order ID that was used when
   *             paying for the resource URL
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_order_by_fulfillment)(
    void *cls,
    const char *instance_id,
    const char *fulfillment_url,
    const char *session_id,
    bool allow_refunded_for_repurchase,
    char **order_id);

  /**
   * Update information about progress made by taler-merchant-wirewatch.
   *
   * @param cls closure
   * @param instance which instance does the account belong to
   * @param payto_uri which account is this about
   * @param last_serial last serial imported from the bank
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*update_wirewatch_progress)(
    void *cls,
    const char *instance,
    struct TALER_FullPayto payto_uri,
    uint64_t last_serial);


  /**
   * Select information about accounts which taler-merchant-wirewatch should work on.
   *
   * @param cls closure
   * @param cb function to call with results
   * @param cb_cls closure for @a cb
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*select_wirewatch_accounts)(
    void *cls,
    TALER_MERCHANTDB_WirewatchWorkCallback cb,
    void *cb_cls);


  /**
   * Insert information about a wire transfer the merchant has received.
   *
   * @param cls closure
   * @param instance_id instance to lookup the order from
   * @param exchange_url which exchange made the transfer
   * @param wtid identifier of the wire transfer
   * @param credit_amount how much did we receive
   * @param payto_uri what is the merchant's bank account that received the transfer
   * @param bank_serial_id bank serial transfer ID, 0 for none (use NULL in DB!)
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*insert_transfer)(
    void *cls,
    const char *instance_id,
    const char *exchange_url,
    const struct TALER_WireTransferIdentifierRawP *wtid,
    const struct TALER_Amount *credit_amount,
    struct TALER_FullPayto payto_uri,
    uint64_t bank_serial_id);


  /**
   * Delete information about a transfer. Note that transfers
   * confirmed by the exchange cannot be deleted anymore.
   *
   * @param cls closure
   * @param instance_id instance to delete transfer of
   * @param transfer_serial_id transfer to delete
   * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
   *           if deletion is prohibited OR transfer is unknown
   */
  enum GNUNET_DB_QueryStatus
    (*delete_transfer)(void *cls,
                       const char *instance_id,
                       uint64_t transfer_serial_id);


  /**
   * Check if information about a transfer exists with the
   * backend.  Returns no data, only the query status.
   *
   * @param cls closure
   * @param instance_id instance to delete transfer of
   * @param transfer_serial_id transfer to delete
   * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT
   *           if the transfer record exists
   */
  enum GNUNET_DB_QueryStatus
    (*check_transfer_exists)(void *cls,
                             const char *instance_id,
                             uint64_t transfer_serial_id);


  /**
   * Lookup account serial by payto URI.
   *
   * @param cls closure
   * @param instance_id instance to lookup the account from
   * @param payto_uri what is the merchant's bank account to lookup
   * @param[out] account_serial serial number of the account
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_account)(void *cls,
                      const char *instance_id,
                      struct TALER_FullPayto payto_uri,
                      uint64_t *account_serial);


  /**
   * Insert information about a wire transfer the merchant has received.
   *
   * @param cls closure
   * @param instance_id instance to provide transfer details for
   * @param exchange_url which exchange made the transfer
   * @param payto_uri what is the merchant's bank account that received the transfer
   * @param wtid identifier of the wire transfer
   * @param td transfer details to store
   * @return transaction status,
   *   #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the @a wtid and @a exchange_uri are not known for this @a instance_id
   *   #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT on success
   */
  enum GNUNET_DB_QueryStatus
    (*insert_transfer_details)(
    void *cls,
    const char *instance_id,
    const char *exchange_url,
    struct TALER_FullPayto payto_uri,
    const struct TALER_WireTransferIdentifierRawP *wtid,
    const struct TALER_EXCHANGE_TransferData *td);


  /**
   * Obtain information about wire fees charged by an exchange,
   * including signature (so we have proof).
   *
   * @param cls closure
   * @param master_pub master public key of the exchange
   * @param h_wire_method hash of wire method
   * @param contract_date date of the contract to use for the lookup
   * @param[out] fees set to wire fees charged
   * @param[out] start_date start of fee being used
   * @param[out] end_date end of fee being used
   * @param[out] master_sig signature of exchange over fee structure
   * @return transaction status code
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_wire_fee)(
    void *cls,
    const struct TALER_MasterPublicKeyP *master_pub,
    const char *wire_method,
    struct GNUNET_TIME_Timestamp contract_date,
    struct TALER_WireFeeSet *fees,
    struct GNUNET_TIME_Timestamp *start_date,
    struct GNUNET_TIME_Timestamp *end_date,
    struct TALER_MasterSignatureP *master_sig);


  /**
   * Lookup information about coin payments by @a h_contract_terms and
   * @a coin_pub.
   *
   * @param cls closure
   * @param instance_id instance to lookup payments for
   * @param h_contract_terms proposal data's hashcode
   * @param coin_pub public key to use for the search
   * @param cb function to call with payment data
   * @param cb_cls closure for @a cb
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_deposits_by_contract_and_coin)(
    void *cls,
    const char *instance_id,
    const struct TALER_PrivateContractHashP *h_contract_terms,
    const struct TALER_CoinSpendPublicKeyP *coin_pub,
    TALER_MERCHANTDB_CoinDepositCallback cb,
    void *cb_cls);


  /**
   * Lookup transfer summary (used if we already verified the details).
   *
   * @param cls closure
   * @param exchange_url the exchange that made the transfer
   * @param wtid wire transfer subject
   * @param cb function to call with detailed transfer data
   * @param cb_cls closure for @a cb
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_transfer_summary)(
    void *cls,
    const char *exchange_url,
    const struct TALER_WireTransferIdentifierRawP *wtid,
    TALER_MERCHANTDB_TransferSummaryCallback cb,
    void *cb_cls);


  /**
   * Lookup transfer details. Used if we still need to verify the details.
   *
   * @param cls closure
   * @param exchange_url the exchange that made the transfer
   * @param wtid wire transfer subject
   * @param cb function to call with detailed transfer data
   * @param cb_cls closure for @a cb
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_transfer_details)(
    void *cls,
    const char *exchange_url,
    const struct TALER_WireTransferIdentifierRawP *wtid,
    TALER_MERCHANTDB_TransferDetailsCallback cb,
    void *cb_cls);


  /**
   * Lookup transfers.
   *
   * @param cls closure
   * @param instance_id instance to lookup payments for
   * @param payto_uri account that we are interested in transfers to
   * @param before timestamp for the earliest transfer we care about
   * @param after timestamp for the last transfer we care about
   * @param limit number of entries to return, negative for descending in execution time,
   *                positive for ascending in execution time
   * @param offset transfer_serial number of the transfer we want to offset from
   * @param expected filter for transfers that were expected
   * @param cb function to call with detailed transfer data
   * @param cb_cls closure for @a cb
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_transfers)(
    void *cls,
    const char *instance_id,
    struct TALER_FullPayto payto_uri,
    struct GNUNET_TIME_Timestamp before,
    struct GNUNET_TIME_Timestamp after,
    int64_t limit,
    uint64_t offset,
    enum TALER_EXCHANGE_YesNoAll expected,
    TALER_MERCHANTDB_TransferCallback cb,
    void *cb_cls);


  /**
   * Lookup expected incoming transfers.
   *
   * @param cls closure
   * @param instance_id instance to lookup payments for
   * @param payto_uri account that we are interested in transfers to
   * @param before timestamp for the earliest transfer we care about
   * @param after timestamp for the last transfer we care about
   * @param limit number of entries to return, negative for descending in execution time,
   *                positive for ascending in execution time
   * @param offset expected_transfer_serial number of the transfer we want to offset from
   * @param confirmed filter by confirmation status
   * @param verified filter by verification status
   * @param cb function to call with detailed transfer data
   * @param cb_cls closure for @a cb
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_expected_transfers)(
    void *cls,
    const char *instance_id,
    struct TALER_FullPayto payto_uri,
    struct GNUNET_TIME_Timestamp before,
    struct GNUNET_TIME_Timestamp after,
    int64_t limit,
    uint64_t offset,
    enum TALER_EXCHANGE_YesNoAll confirmed,
    enum TALER_EXCHANGE_YesNoAll verified,
    TALER_MERCHANTDB_IncomingCallback cb,
    void *cb_cls);


  /**
   * Store information about wire fees charged by an exchange,
   * including signature (so we have proof).
   *
   * @param cls closure
   * @param master_pub master public key of the exchange
   * @param h_wire_method hash of wire method
   * @param fees wire fees charged
   * @param start_date start of fee being used
   * @param end_date end of fee being used
   * @param master_sig signature of exchange over fee structure
   * @return transaction status code
   */
  enum GNUNET_DB_QueryStatus
    (*store_wire_fee_by_exchange)(
    void *cls,
    const struct TALER_MasterPublicKeyP *master_pub,
    const struct GNUNET_HashCode *h_wire_method,
    const struct TALER_WireFeeSet *fees,
    struct GNUNET_TIME_Timestamp start_date,
    struct GNUNET_TIME_Timestamp end_date,
    const struct TALER_MasterSignatureP *master_sig);


  /**
   * Delete information about wire accounts of an exchange. (Used when we got new account data.)
   *
   * @param cls closure
   * @param master_pub public key of the exchange
   * @return transaction status code
   */
  enum GNUNET_DB_QueryStatus
    (*delete_exchange_accounts)(
    void *cls,
    const struct TALER_MasterPublicKeyP *master_pub);


  /**
   * Return information about wire accounts of an exchange.
   *
   * @param cls closure
   * @param master_pub public key of the exchange
   * @param cb function to call on each account
   * @param cb_cls closure for @a cb
   * @return transaction status code
   */
  enum GNUNET_DB_QueryStatus
    (*select_accounts_by_exchange)(
    void *cls,
    const struct TALER_MasterPublicKeyP *master_pub,
    TALER_MERCHANTDB_ExchangeAccountCallback cb,
    void *cb_cls);


  /**
   * Insert information about a wire account of an exchange.
   *
   * @param cls closure
   * @param master_pub public key of the exchange
   * @param payto_uri URI of the bank account
   * @param conversion_url conversion service, NULL if there is no conversion required
   * @param debit_restrictions JSON array of debit restrictions on the account
   * @param credit_restrictions JSON array of debit restrictions on the account
   * @param master_sig signature affirming the account of the exchange
   * @return transaction status code
   */
  enum GNUNET_DB_QueryStatus
    (*insert_exchange_account)(
    void *cls,
    const struct TALER_MasterPublicKeyP *master_pub,
    const struct TALER_FullPayto payto_uri,
    const char *conversion_url,
    const json_t *debit_restrictions,
    const json_t *credit_restrictions,
    const struct TALER_MasterSignatureP *master_sig);


  /**
   * Lookup all of the templates the given instance has configured.
   *
   * @param cls closure
   * @param instance_id instance to lookup template for
   * @param cb function to call on all template found
   * @param cb_cls closure for @a cb
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_templates)(void *cls,
                        const char *instance_id,
                        TALER_MERCHANTDB_TemplatesCallback cb,
                        void *cb_cls);


  /**
   * Lookup details about a particular template.
   *
   * @param cls closure
   * @param instance_id instance to lookup template for
   * @param template_id template to lookup
   * @param[out] td set to the template details on success, can be NULL
   *             (in that case we only want to check if the template exists)
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_template)(void *cls,
                       const char *instance_id,
                       const char *template_id,
                       struct TALER_MERCHANTDB_TemplateDetails *td);

  /**
   * Delete information about a template.
   *
   * @param cls closure
   * @param instance_id instance to delete template of
   * @param template_id template to delete
   * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
   *           if template unknown.
   */
  enum GNUNET_DB_QueryStatus
    (*delete_template)(void *cls,
                       const char *instance_id,
                       const char *template_id);


  /**
   * Insert details about a particular template.
   *
   * @param cls closure
   * @param instance_id instance to insert template for
   * @param template_id template identifier of template to insert
   * @param otp_serial_id 0 if no OTP device is associated
   * @param td the template details to insert
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*insert_template)(void *cls,
                       const char *instance_id,
                       const char *template_id,
                       uint64_t otp_serial_id,
                       const struct TALER_MERCHANTDB_TemplateDetails *td);


  /**
   * Update details about a particular template.
   *
   * @param cls closure
   * @param instance_id instance to update template for
   * @param template_id template to update
   * @param td update to the template details on success, can be NULL
   *             (in that case we only want to check if the template exists)
   * @return database result code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the template
   *         does not yet exist.
   */
  enum GNUNET_DB_QueryStatus
    (*update_template)(void *cls,
                       const char *instance_id,
                       const char *template_id,
                       const struct TALER_MERCHANTDB_TemplateDetails *td);


  /**
   * Delete information about an OTP device.
   *
   * @param cls closure
   * @param instance_id instance to delete OTP device of
   * @param otp_id otp device to delete
   * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
   *           if template unknown.
   */
  enum GNUNET_DB_QueryStatus
    (*delete_otp)(void *cls,
                  const char *instance_id,
                  const char *otp_id);

  /**
   * Insert details about a particular OTP device.
   *
   * @param cls closure
   * @param instance_id instance to insert OTP device for
   * @param otp_id otp identifier of OTP device to insert
   * @param td the OTP device details to insert
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*insert_otp)(void *cls,
                  const char *instance_id,
                  const char *otp_id,
                  const struct TALER_MERCHANTDB_OtpDeviceDetails *td);


  /**
   * Update details about a particular OTP device.
   *
   * @param cls closure
   * @param instance_id instance to update OTP device for
   * @param otp_id OTP device to update
   * @param td update to the OTP device details on success, can be NULL
   *             (in that case we only want to check if the template exists)
   * @return database result code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the template
   *         does not yet exist.
   */
  enum GNUNET_DB_QueryStatus
    (*update_otp)(void *cls,
                  const char *instance_id,
                  const char *otp_id,
                  const struct TALER_MERCHANTDB_OtpDeviceDetails *td);

  /**
   * Lookup all of the OTP devices the given instance has configured.
   *
   * @param cls closure
   * @param instance_id instance to lookup OTP devices for
   * @param cb function to call on all OTP devices found
   * @param cb_cls closure for @a cb
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_otp_devices)(void *cls,
                          const char *instance_id,
                          TALER_MERCHANTDB_OtpDeviceCallback cb,
                          void *cb_cls);


  /**
   * Lookup details about an OTP device.
   *
   * @param cls closure
   * @param instance_id instance to lookup template for
   * @param otp_id OTP device to lookup
   * @param[out] td set to the OTP device details on success, can be NULL
   *             (in that case we only want to check if the template exists)
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*select_otp)(void *cls,
                  const char *instance_id,
                  const char *otp_id,
                  struct TALER_MERCHANTDB_OtpDeviceDetails *td);


  /**
   * Lookup serial number of an OTP device.
   *
   * @param cls closure
   * @param instance_id instance to lookup template for
   * @param otp_id OTP device to lookup
   * @param[out] serial set to the OTP device serial number   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*select_otp_serial)(void *cls,
                         const char *instance_id,
                         const char *otp_id,
                         uint64_t *serial);

  /**
   * Delete information about a measurement unit.
   *
   * @param cls closure
   * @param instance_id instance to delete unit from
   * @param unit_id symbolic identifier of the unit
   * @param[out] no_instance set to true if @a instance_id is unknown
   * @param[out] no_unit set to true if the unit does not exist
   * @param[out] builtin_conflict set to true if the unit is builtin and may not be deleted
   * @return DB status code
   */
  enum GNUNET_DB_QueryStatus
    (*delete_unit)(void *cls,
                   const char *instance_id,
                   const char *unit_id,
                   bool *no_instance,
                   bool *no_unit,
                   bool *builtin_conflict);

  /**
   * Insert a measurement unit definition.
   *
   * @param cls closure
   * @param instance_id instance to insert unit for
   * @param ud unit details to store (unit_serial ignored)
   * @param[out] no_instance set to true if @a instance_id is unknown
   * @param[out] conflict set to true if a conflicting unit already exists
   * @param[out] unit_serial set to the inserted serial on success
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*insert_unit)(void *cls,
                   const char *instance_id,
                   const struct TALER_MERCHANTDB_UnitDetails *ud,
                   bool *no_instance,
                   bool *conflict,
                   uint64_t *unit_serial);

  /**
   * Update a measurement unit definition.
   *
   * @param cls closure
   * @param instance_id instance owning the unit
   * @param unit_id symbolic identifier of the unit
   * @param unit_name_long optional new long label (NULL to keep current)
   * @param unit_name_long_i18n optional new long-label translations (NULL to keep current)
   * @param unit_name_short optional new short label (NULL to keep current)
   * @param unit_name_short_i18n optional new short-label translations (NULL to keep current)
   * @param unit_allow_fraction optional new fractional toggle (NULL to keep current)
   * @param unit_precision_level optional new fractional precision (NULL to keep current)
   * @param unit_active optional new visibility flag (NULL to keep current)
   * @param[out] no_instance set if instance unknown
   * @param[out] no_unit set if unit unknown
   * @param[out] builtin_conflict set if immutable builtin fields touched
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*update_unit)(void *cls,
                   const char *instance_id,
                   const char *unit_id,
                   const char *unit_name_long,
                   const json_t *unit_name_long_i18n,
                   const char *unit_name_short,
                   const json_t *unit_name_short_i18n,
                   const bool *unit_allow_fraction,
                   const uint32_t *unit_precision_level,
                   const bool *unit_active,
                   bool *no_instance,
                   bool *no_unit,
                   bool *builtin_conflict);

  /**
   * Lookup all measurement units of an instance.
   *
   * @param cls closure
   * @param instance_id instance to fetch units for
   * @param cb function to call per unit
   * @param cb_cls closure for @a cb
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_units)(void *cls,
                    const char *instance_id,
                    TALER_MERCHANTDB_UnitsCallback cb,
                    void *cb_cls);

  /**
   * Lookup a single measurement unit.
   *
   * @param cls closure
   * @param instance_id instance to fetch unit for
   * @param unit_id symbolic identifier
   * @param[out] ud unit details on success; may be NULL to test existence
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*select_unit)(void *cls,
                   const char *instance_id,
                   const char *unit_id,
                   struct TALER_MERCHANTDB_UnitDetails *ud);


  /**
   * Delete information about a product category.
   *
   * @param cls closure
   * @param instance_id instance to delete category of
   * @param category_id identifies the category to delete
   * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
   *           if template unknown.
   */
  enum GNUNET_DB_QueryStatus
    (*delete_category)(void *cls,
                       const char *instance_id,
                       uint64_t category_id);

  /**
   * Insert new product category.
   *
   * @param cls closure
   * @param instance_id instance to insert OTP device for
   * @param category_name name of the category
   * @param category_name_i18n translations of the category name
   * @param[out] category_id set to the category id on success
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*insert_category)(void *cls,
                       const char *instance_id,
                       const char *category_name,
                       const json_t *category_name_i18n,
                       uint64_t *category_id);


  /**
   * Update descriptions of a product category.
   *
   * @param cls closure
   * @param instance_id instance to update OTP device for
   * @param category_id category to update
   * @param category_name name of the category
   * @param category_name_i18n translations of the category name
   * @return database result code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the template
   *         does not yet exist.
   */
  enum GNUNET_DB_QueryStatus
    (*update_category)(void *cls,
                       const char *instance_id,
                       uint64_t category_id,
                       const char *category_name,
                       const json_t *category_name_i18n);

  /**
   * Lookup all of the product categories the given instance has configured.
   *
   * @param cls closure
   * @param instance_id instance to lookup OTP devices for
   * @param cb function to call on all categories found
   * @param cb_cls closure for @a cb
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_categories)(void *cls,
                         const char *instance_id,
                         TALER_MERCHANTDB_CategoriesCallback cb,
                         void *cb_cls);


  /**
   * Lookup details about product category.
   *
   * @param cls closure
   * @param instance_id instance to lookup template for
   * @param category_id category to update
   * @param[out] cd set to the category details on success, can be NULL
   *             (in that case we only want to check if the category exists)
   * @param[out] num_products set to length of @a products array
   * @param[out] products set to buffer with @a num_products 0-terminated strings with the product IDs, caller must free() it.
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*select_category)(void *cls,
                       const char *instance_id,
                       uint64_t category_id,
                       struct TALER_MERCHANTDB_CategoryDetails *cd,
                       size_t *num_products,
                       char **products);


  /**
   * Lookup details about product category by name.
   *
   * @param cls closure
   * @param instance_id instance to lookup template for
   * @param category_name category name to look for
   * @param[out] name_i18n category name translation
   * @param[out] category_id category ID
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*select_category_by_name)(void *cls,
                               const char *instance_id,
                               const char *category_name,
                               json_t **name_i18n,
                               uint64_t *category_id);


  /**
   * Lookup all of the webhooks the given instance has configured.
   *
   * @param cls closure
   * @param instance_id instance to lookup webhook for
   * @param cb function to call on all webhook found
   * @param cb_cls closure for @a cb
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_webhooks)(void *cls,
                       const char *instance_id,
                       TALER_MERCHANTDB_WebhooksCallback cb,
                       void *cb_cls);


  /**
   * Lookup details about a particular webhook.
   *
   * @param cls closure
   * @param instance_id instance to lookup webhook for
   * @param webhook_id webhook to lookup
   * @param[out] wb set to the webhook details on success, can be NULL
   *             (in that case we only want to check if the webhook exists)
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_webhook)(void *cls,
                      const char *instance_id,
                      const char *webhook_id,
                      struct TALER_MERCHANTDB_WebhookDetails *wb);

  /**
   * Delete information about a webhook.
   *
   * @param cls closure
   * @param instance_id instance to delete webhook of
   * @param webhook_id webhook to delete
   * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
   *           if webhook unknown.
   */
  enum GNUNET_DB_QueryStatus
    (*delete_webhook)(void *cls,
                      const char *instance_id,
                      const char *webhook_id);


  /**
   * Insert details about a particular webhook.
   *
   * @param cls closure
   * @param instance_id instance to insert webhook for
   * @param webhook_id webhook identifier of webhook to insert
   * @param wb the webhook details to insert
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*insert_webhook)(void *cls,
                      const char *instance_id,
                      const char *webhook_id,
                      const struct TALER_MERCHANTDB_WebhookDetails *wb);


  /**
   * Update details about a particular webhook.
   *
   * @param cls closure
   * @param instance_id instance to update webhook for
   * @param webhook_id webhook to update
   * @param wb update to the webhook details on success, can be NULL
   *             (in that case we only want to check if the webhook exists)
   * @return database result code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the webhook
   *         does not yet exist.
   */
  enum GNUNET_DB_QueryStatus
    (*update_webhook)(void *cls,
                      const char *instance_id,
                      const char *webhook_id,
                      const struct TALER_MERCHANTDB_WebhookDetails *wb);

  /**
   * Lookup webhook by event
   *
   * @param cls closure
   * @param instance_id instance to lookup webhook for
   * @param event_type event that we need to put in the pending webhook
   * @param[out] cb set to the webhook details on success
   * @param cb_cls callback closure
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_webhook_by_event)(void *cls,
                               const char *instance_id,
                               const char *event_type,
                               TALER_MERCHANTDB_WebhookDetailCallback cb,
                               void *cb_cls);

  /**
   * Insert webhook in the pending webhook.
   *
   * @param cls closure
   * @param instance_id instance to insert webhook for
   * @param webhook_serial webhook to insert in the pending webhook
   * @param url to make the request to
   * @param http_method for the webhook
   * @param header of the webhook
   * @param body of the webhook
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*insert_pending_webhook)(void *cls,
                              const char *instance_id,
                              uint64_t webhook_serial,
                              const char *url,
                              const char *http_method,
                              const char *header,
                              const char *body);
  /**
   * Lookup the webhook that need to be send in priority. These webhooks are not successfully
   * send.
   *
   * @param cls closure
   * @param cb pending webhook callback
   * @param cb_cls callback closure
   */
  // WHERE next_attempt <= now ORDER BY next_attempt ASC
  enum GNUNET_DB_QueryStatus
    (*lookup_pending_webhooks)(void *cls,
                               TALER_MERCHANTDB_PendingWebhooksCallback cb,
                               void *cb_cls);

  /**
   * Lookup future webhook in the pending webhook that need to be send.
   * With that we can know how long the system can 'sleep'.
   *
   * @param cls closure
   * @param cb pending webhook callback
   * @param cb_cls callback closure
   */
  // ORDER BY next_attempt ASC LIMIT 1
  enum GNUNET_DB_QueryStatus
    (*lookup_future_webhook)(void *cls,
                             TALER_MERCHANTDB_PendingWebhooksCallback cb,
                             void *cb_cls);

  /**
   * Lookup all the webhooks in the pending webhook.
   * Use by the administrator
   *
   * @param cls closure
   * @param instance_id to lookup webhooks for this instance particularly
   * @param min_row to see the list of the pending webhook that it is started with this minimum row.
   * @param max_results to see the list of the pending webhook that it is end with this max results.
   * @param cb pending webhook callback
   * @param cb_cls callback closure
   */
  // WHERE webhook_pending_serial > min_row ORDER BY webhook_pending_serial ASC LIMIT max_results
  enum GNUNET_DB_QueryStatus
    (*lookup_all_webhooks)(void *cls,
                           const char *instance_id,
                           uint64_t min_row,
                           uint32_t max_results,
                           TALER_MERCHANTDB_PendingWebhooksCallback cb,
                           void *cb_cls);


  /**
   * Update the pending webhook. It is use if the webhook can't be send.
   *
   * @param cls closure
   * @param webhook_serial webhook that need to be update
   * @param next_attempt when we should make the next request to the webhook
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*update_pending_webhook)(void *cls,
                              uint64_t webhook_pending_serial,
                              struct GNUNET_TIME_Absolute next_attempt);
  // maybe add: http status of failure?


  /**
   * Delete a webhook in the pending webhook after the
   * webhook was completed successfully.
   *
   * @param cls closure
   * @param webhook_serial webhook that need to be delete in the pending webhook
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*delete_pending_webhook)(void *cls,
                              uint64_t webhook_pending_serial);


  /**
   * Retrieve exchange's keys from the database.
   *
   * @param cls plugin closure
   * @param exchange_url base URL of the exchange
   * @param[out] first_retry set to earliest we may retry fetching the keys
   * @param[out] keys set to the keys of the exchange
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*select_exchange_keys)(void *cls,
                            const char *exchange_url,
                            struct GNUNET_TIME_Absolute *first_retry,
                            struct TALER_EXCHANGE_Keys **keys);


  /**
   * Insert or update @a keys into the database.
   *
   * @param cls plugin closure
   * @param keys data to store
   * @param first_retry earliest we may retry fetching the keys
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*insert_exchange_keys)(void *cls,
                            const struct TALER_EXCHANGE_Keys *keys,
                            struct GNUNET_TIME_Absolute first_retry);


  /**
   * Lookup all of the token families the given instance has configured.
   *
   * @param cls closure
   * @param instance_id instance to lookup token families for
   * @param cb function to call on all token families found
   * @param cb_cls closure for @a cb
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_token_families)(void *cls,
                             const char *instance_id,
                             TALER_MERCHANTDB_TokenFamiliesCallback cb,
                             void *cb_cls);

  /**
   * Lookup details about a particular token family.
   *
   * @param cls closure
   * @param instance_id instance to lookup token family for
   * @param token_family_slug token family to lookup
   * @param[out] details set to the token family details on success, can be NULL
   *             (in that case we only want to check if the token family exists)
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_token_family)(void *cls,
                           const char *instance_id,
                           const char *token_family_slug,
                           struct TALER_MERCHANTDB_TokenFamilyDetails *details);

  /**
   * Delete information about a token family.
   *
   * @param cls closure
   * @param instance_id instance to delete token family of
   * @param token_family_slug slug of token family to delete
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*delete_token_family)(void *cls,
                           const char *instance_id,
                           const char *token_family_slug);

  /**
   * Update details about a particular token family.
   *
   * @param cls closure
   * @param instance_id instance to update token family for
   * @param token_family_slug slug of token family to update
   * @param details set to the updated token family on success, can be NULL
   *        (in that case we only want to check if the token family exists)
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*update_token_family)(
    void *cls,
    const char *instance_id,
    const char *token_family_slug,
    const struct TALER_MERCHANTDB_TokenFamilyDetails *details);


  /**
   * Insert details about a particular token family.
   *
   * @param cls closure
   * @param instance_id instance to insert token family for
   * @param token_family_slug slug of token family to insert
   * @param details the token family details to insert
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*insert_token_family)(
    void *cls,
    const char *instance_id,
    const char *token_family_slug,
    const struct TALER_MERCHANTDB_TokenFamilyDetails *details);


  /**
  * Lookup details about a particular token family key.
  *
  * @param cls closure
  * @param instance_id instance to lookup token family key for
  * @param token_family_slug slug of token family to lookup
  * @param valid_at find a key with a validity period that includes this time
  * @param sign_until find a private key that can sign until this time
  * @param[out] details set to the token family key details on success, can be NULL
  *             (in that case we only want to check if the token family key exists)
  * @return database result code
  */
  enum GNUNET_DB_QueryStatus
    (*lookup_token_family_key)(
    void *cls,
    const char *instance_id,
    const char *token_family_slug,
    struct GNUNET_TIME_Timestamp valid_at,
    struct GNUNET_TIME_Timestamp sign_until,
    struct TALER_MERCHANTDB_TokenFamilyKeyDetails *details);


  /**
   * Lookup token family keys that may be used for a payment.
   *
   * @param cls closure
   * @param instance_id instance to lookup token family key for
   * @param token_family_slug slug of token family to lookup
   * @param start_time signature validity start the keys must fall into
   * @param end_time signature validity end the keys must fall into
   * @param cb function to call with each matching key
   * @param cb_cls closure for @a cb
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_token_family_keys)(
    void *cls,
    const char *instance_id,
    const char *token_family_slug,
    struct GNUNET_TIME_Timestamp start_time,
    struct GNUNET_TIME_Timestamp end_time,
    TALER_MERCHANTDB_TokenKeyCallback cb,
    void *cb_cls);


  /**
   * Insert details a key pair for a token family.
   *
   * @param cls closure
   * @param merchant_id instance name
   * @param token_family_slug slug of token family to insert the key pair for
   * @param pub token family public key
   * @param priv token family private key
   * @param key_expires when does the private key expire (because
   *     the validity period of the next token family key starts)
   * @param valid_after start of validity period for signatures with this key
   * @param valid_before end of validity period for signatures with this key
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*insert_token_family_key)(
    void *cls,
    const char *merchant_id,
    const char *token_family_slug,
    const struct TALER_TokenIssuePublicKey *pub,
    const struct TALER_TokenIssuePrivateKey *priv,
    struct GNUNET_TIME_Timestamp key_expires,
    struct GNUNET_TIME_Timestamp valid_after,
    struct GNUNET_TIME_Timestamp valid_before);

  /**
   * Lookup deposits that are finished and awaiting a wire transfer.
   *
   * @param cls closure
   * @param exchange_url exchange to filter deposits by
   * @param limit maximum number of deposits to return
   * @param allow_future true to allow deposits with wire deadline in the future
   * @param cb function to call with deposit data
   * @param cb_cls closure for @a cb
   * @return transaction status
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_pending_deposits)(
    void *cls,
    const char *exchange_url,
    uint64_t limit,
    bool allow_future,
    TALER_MERCHANTDB_PendingDepositsCallback cb,
    void *cb_cls);


  /**
   * Update the deposit confirmation status associated with
   * the given @a deposit_serial.
   *
   * @param cls closure
   * @param deposit_serial deposit to update status for
   * @param retry_needed true if the HTTP request should be retried
   * @param retry_time when should we ask the exchange again
   * @param last_http_status HTTP status code of the last reply
   * @param last_ec Taler error code of the last reply
   * @param last_detail detail from error message to record, possibly NULL
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*update_deposit_confirmation_status)(
    void *cls,
    uint64_t deposit_serial,
    bool retry_needed,
    struct GNUNET_TIME_Timestamp retry_time,
    uint32_t last_http_status,
    enum TALER_ErrorCode last_ec,
    const char *last_detail);


  /**
   * Update the amount of receipts for a Donau instance.
   *
   * @param cls closure
   * @param donau_instances_serial serial number of the Donau instance
   * @param new_amount new receipts_to_date amount
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*update_donau_instance_receipts_amount)(
    void *cls,
    uint64_t *donau_instances_serial,
    const struct TALER_Amount *new_amount
    );


  /**
   * Check if a new matching multi-factor authorization (MFA) challenge
   * exists in the database.
   *
   * @param cls closure
   * @param challenge_id set to the ID of the challenge
   * @param h_body hash of the request body
   * @param[out] salt salt used to compute @a h_body
   * @param[out] required address set to where the challenge is to be send
   * @param[out] op operation that triggered the MFA request
   * @param[out] confirmation_date when was the challenge solved,
   *             set to "GNUNET_TIME_ABSOLUTE_NEVER" if unsolved
   * @param[out] retransmission_date set to when a fresh challenge
   *             may be transmitted
   * @param[out] retry_counter set to the number of attempts that remain
   *             for solving the challenge (after this time)
   * @param[out] tan_channel which channel was used
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_mfa_challenge)(
    void *cls,
    uint64_t challenge_id,
    const struct TALER_MERCHANT_MFA_BodyHash *h_body,
    struct TALER_MERCHANT_MFA_BodySalt *salt,
    char **required_address,
    enum TALER_MERCHANT_MFA_CriticalOperation *op,
    struct GNUNET_TIME_Absolute *confirmation_date,
    struct GNUNET_TIME_Absolute *retransmission_date,
    uint32_t *retry_counter,
    enum TALER_MERCHANT_MFA_Channel *tan_channel);


  /**
   * Attempt to solve new multi-factor authorization (MFA) challenge.
   * Checks the solution against the code in the database and updates
   * the solution state and (on failure) retry counter depending on
   * the result.
   *
   * @param cls closure
   * @param challenge_id challenge ID to be solved
   * @param h_body body of the operation the challenge authorizes
   * @param solution proposed solution to be checked against the actual code
   * @param[out] solved set to true if the challenge was solved by
   *             @a solution
   * @param[out] retry_counter set to the number of attempts that remain
   *             for solving the challenge (after this time)
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*solve_mfa_challenge)(
    void *cls,
    uint64_t challenge_id,
    const struct TALER_MERCHANT_MFA_BodyHash *h_body,
    const char *solution,
    bool *solved,
    uint32_t *retry_counter);


  /**
   * Update the state of an MFA challenge as we have now
   * retransmitted the challenge code.
   *
   * @param cls closure
   * @param challenge_id challenge ID to be solved
   * @param code new challenge code
   * @param retry_counter number of attempts that remain
   *             for solving the challenge
   * @param expiration_date when should the challenge expire
   * @param retransmission_date set to when a fresh challenge
   *             may be transmitted next
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*update_mfa_challenge)(
    void *cls,
    uint64_t challenge_id,
    const char *code,
    uint32_t retry_counter,
    struct GNUNET_TIME_Absolute expiration_date,
    struct GNUNET_TIME_Absolute retransmission_date);


  /**
   * Create new multi-factor authorization (MFA) challenge in the database.
   *
   * @param cls closure
   * @param op operation that triggered the MFA request
   * @param h_body hash of the request body
   * @param salt salt used to compute @a h_body
   * @param code challenge code sent to the user
   * @param expiration_date when should the challenge expire
   * @param retansmission_date when do we next allow retransmission
   *        of the challenge
   * @param tan_channel which channel was used
   * @param required_address address
   *        where the challenge is to be sent
   * @param[out] challenge_id set to the ID of the new challenge
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*create_mfa_challenge)(
    void *cls,
    enum TALER_MERCHANT_MFA_CriticalOperation op,
    const struct TALER_MERCHANT_MFA_BodyHash *h_body,
    const struct TALER_MERCHANT_MFA_BodySalt *salt,
    const char *code,
    struct GNUNET_TIME_Absolute expiration_date,
    struct GNUNET_TIME_Absolute retransmission_date,
    enum TALER_MERCHANT_MFA_Channel tan_channel,
    const char *required_address,
    uint64_t *challenge_id);


#ifdef HAVE_DONAU_DONAU_SERVICE_H
  /**
   * Insert information about a Donau instance.
   *
   * @param cls closure
   * @param donau_url URL of the Donau instance
   * @param charity details of the charity
   * @param charity_id charity ID of the Donau instance
   */
  enum GNUNET_DB_QueryStatus
    (*insert_donau_instance)(
    void *cls,
    const char *donau_url,
    const struct DONAU_Charity *charity,
    uint64_t charity_id
    );


  /**
   * Check if information about a Donau instance exists.
   *
   * @param cls closure
   * @param merchant_pub public key of the instance
   * @param donau_url URL of the Donau instance
   * @param charity_id charity ID of the Donau instance
   */
  enum GNUNET_DB_QueryStatus
    (*check_donau_instance)(
    void *cls,
    const struct TALER_MerchantPublicKeyP *merchant_pub,
    const char *donau_url,
    uint64_t charity_id
    );

  /**
   * Select donau instance by serial number.
   *
   * @param cls closure
   * @param serial serial number of the Donau instance in DB
   * @param[out] donau_url set to the URL of the Donau instance
   * @param[out] charity_id set to the charity ID of the Donau instance
   */
  enum GNUNET_DB_QueryStatus
    (*select_donau_instance_by_serial)(
    void *cls,
    uint64_t serial,
    char **donau_url,
    uint64_t *charity_id);

  /**
   * Select all Donau instances. Note that this callback only
   * returns Donau instances for which we have successfully
   * retrieved /keys.
   *
   * @param cls closure
   * @param id instance to restrict to
   * @param cb function to call on all Donau instances found
   * @param cb_cls closure for @a cb
   */
  enum GNUNET_DB_QueryStatus
    (*select_donau_instances)(
    void *cls,
    const char *id,
    TALER_MERCHANTDB_DonauInstanceCallback cb,
    void *cb_cls);


  /**
   * Select all Donau instances, regardless of instance and also
   * regardless of whether we got a /keys response.
   *
   * @param cls closure
   * @param cb function to call on all Donau instances found
   * @param cb_cls closure for @a cb
   */
  enum GNUNET_DB_QueryStatus
    (*select_all_donau_instances)(
    void *cls,
    TALER_MERCHANTDB_DonauInstanceCallback cb,
    void *cb_cls);


  /**
   * Select all Donau instances, but only the donau_url
   * and charity_max_per_year.
   *
   * @param cls closure
   * @param cb function to call on all Donau instances found
   * @param cb_cls closure for @a cb
   */
  enum GNUNET_DB_QueryStatus
    (*select_donau_instances_filtered)(
    void *cls,
    const char *currency,
    TALER_MERCHANTDB_DonauInstanceFilteredCallback cb,
    void *cb_cls);

  /**
   * Lookup Donau keys by URL.
   *
   * @param cls closure
   * @param donau_url URL of the Donau instance
   * @param[out] keys set to the Donau keys on success
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_donau_keys)(
    void *cls,
    const char *donau_url,
    struct GNUNET_TIME_Absolute *first_retry,
    struct DONAU_Keys **keys
    );

  /**
   * Lookup a Donau instance by its instance ID and URL.
   *
   * @param cls closure
   * @param instance_id instance ID of the Donau instance
   * @param donau_url URL of the Donau instance
   * @param charity_id set to the charity ID of the Donau instance
   * @param charity_priv set to the private key of the charity
   * @param charity_max_per_year set to the maximum amount
   *          the charity can receive per year
   * @param charity_receipts_to_date set to the total amount
   *         the charity has received to date
   * @param donau_keys_json set to the JSON representation of the
   *        Donau keys
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_order_charity)(
    void *cls,
    const char *instance_id,
    const char *donau_url,
    uint64_t *charity_id,
    struct DONAU_CharityPrivateKeyP *charity_priv,
    struct TALER_Amount *charity_max_per_year,
    struct TALER_Amount *charity_receipts_to_date,
    json_t **donau_keys_json,
    uint64_t *donau_instance_serial
    );

  /**
   * Upsert Donau keys into the database.
   *
   * @param cls closure
   * @param keys Donau keys to insert or update
   */
  enum GNUNET_DB_QueryStatus
    (*upsert_donau_keys)(
    void *cls,
    const struct DONAU_Keys *keys,
    struct GNUNET_TIME_Absolute first_retry
    );

  /**
   * Update information about a Donau instance.
   *
   * @param cls closure
   * @param donau_url URL of the Donau instance
   * @param charity details of the charity
   * @param charity_id charity ID of the Donau instance
   */
  enum GNUNET_DB_QueryStatus
    (*update_donau_instance)(
    void *cls,
    const char *donau_url,
    const struct DONAU_Charity *charity,
    uint64_t charity_id
    );

#endif

  /**
   * Delete information about a Donau instance.
   *
   * @param cls closure
   * @param charity_id charity ID of the Donau instance to delete
   */
  enum GNUNET_DB_QueryStatus
    (*delete_donau_instance)(
    void *cls,
    const char *id,
    uint64_t charity_id
    );

  /**
   * Lookup amount statistics for instance and slug by bucket.
   *
   * @param cls closure
   * @param instance_id instance to lookup statistics for
   * @param slug instance to lookup statistics for
   * @param cb function to call on all token families found
   * @param cb_cls closure for @a cb
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_statistics_amount_by_bucket)(
    void *cls,
    const char *instance_id,
    const char *slug,
    TALER_MERCHANTDB_AmountByBucketStatisticsCallback cb,
    void *cb_cls);


  /**
   * Lookup counter statistics for instance and slug by bucket.
   *
   * @param cls closure
   * @param instance_id instance to lookup statistics for
   * @param slug instance to lookup statistics for
   * @param cb function to call on all token families found
   * @param cb_cls closure for @a cb
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_statistics_counter_by_bucket)(
    void *cls,
    const char *instance_id,
    const char *slug,
    TALER_MERCHANTDB_CounterByBucketStatisticsCallback cb,
    void *cb_cls);

  /**
   * Lookup amount statistics for instance and slug by interval.
   *
   * @param cls closure
   * @param instance_id instance to lookup statistics for
   * @param slug instance to lookup statistics for
   * @param cb function to call on all token families found
   * @param cb_cls closure for @a cb
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_statistics_amount_by_interval)(
    void *cls,
    const char *instance_id,
    const char *slug,
    TALER_MERCHANTDB_AmountByIntervalStatisticsCallback cb,
    void *cb_cls);
  /**
   * Lookup counter statistics for instance and slug by interval.
   *
   * @param cls closure
   * @param instance_id instance to lookup statistics for
   * @param slug instance to lookup statistics for
   * @param cb function to call on all token families found
   * @param cb_cls closure for @a cb
   * @return database result code
   */
  enum GNUNET_DB_QueryStatus
    (*lookup_statistics_counter_by_interval)(void *cls,
                                             const char *instance_id,
                                             const char *slug,
                                             TALER_MERCHANTDB_CounterByIntervalStatisticsCallback
                                             cb,
                                             void *cb_cls);
};

#endif
