summaryrefslogtreecommitdiff
path: root/core/api-wire.rst
blob: c471cbf872c3cc87582764cf557997979ba4faa9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
..
  This file is part of GNU TALER.
  Copyright (C) 2019-2020 Taler Systems SA

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

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

  You should have received a copy of the GNU Affero General Public License along with
  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>

===========================
Taler Wire Gateway HTTP API
===========================

This section describes the API offered by the Taler wire gateway. The API is
used by the exchange to trigger transactions and query incoming transactions, as
well as by the auditor to query incoming and outgoing transactions.

This API is currently implemented by the Taler Demo Bank, as well as by
LibEuFin (work in progress).


--------------
Authentication
--------------

The bank library authenticates requests to the wire gateway via
`HTTP basic auth <https://tools.ietf.org/html/rfc7617>`_.

-------------------
Making Transactions
-------------------

.. http:post:: ${BASE_URL}/transfer

  This API allows the exchange to make a transaction, typically to a merchant.  The bank account
  of the exchange is not included in the request, but instead derived from the user name in the
  authentication header and/or the request base URL.

  To make the API idempotent, the client must include a nonce.  Requests with the same nonce
  are rejected unless the request is the same.

  **Request:** The body of this request must have the format of a `TransferRequest`.

  **Response:**

  :http:statuscode:`200 OK`:
    The request has been correctly handled, so the funds have been transferred to
    the recipient's account.  The body is a `TransferResponse`.
  :http:statuscode:`400 Bad request`:
    Request malformed. The bank replies with an `ErrorDetail` object.
  :http:statuscode:`401 Unauthorized`:
    Authentication failed, likely the credentials are wrong.
  :http:statuscode:`404 Not found`:
    The endpoint is wrong or the user name is unknown. The bank replies with an `ErrorDetail` object.
  :http:statuscode:`409 Conflict`:
    A transaction with the same ``transaction_uid`` but different transaction details
    has been submitted before.

  **Details:**

  .. ts:def:: TransferResponse

    interface TransferResponse {

      // Timestamp that indicates when the wire transfer will be executed.
      // In cases where the wire transfer gateway is unable to know when
      // the wire transfer will be executed, the time at which the request
      // has been received and stored will be returned.
      // The purpose of this field is for debugging (humans trying to find
      // the transaction) as well as for taxation (determining which
      // time period a transaction belongs to).
      timestamp: Timestamp;

      // Opaque ID of the transaction that the bank has made.
      row_id: SafeUint64;
    }


  .. ts:def:: TransferRequest

    interface TransferRequest {
      // Nonce to make the request idempotent.  Requests with the same
      // ``transaction_uid`` that differ in any of the other fields
      // are rejected.
      request_uid: HashCode;

      // Amount to transfer.
      amount: Amount;

      // Base URL of the exchange.  Shall be included by the bank gateway
      // in the appropriate section of the wire transfer details.
      exchange_base_url: string;

      // Wire transfer identifier chosen by the exchange,
      // used by the merchant to identify the Taler order(s)
      // associated with this wire transfer.
      wtid: ShortHashCode;

      // The recipient's account identifier as a payto URI.
      credit_account: string;
    }


--------------------------------
Querying the transaction history
--------------------------------


.. http:get:: ${BASE_URL}/history/incoming

  Return a list of transactions made from or to the exchange.

  Incoming transactions must contain a valid reserve public key.  If a bank
  transaction does not conform to the right syntax, the wire gateway must not
  report it to the exchange, and send funds back to the sender if possible.

  The bank account of the exchange is determined via the base URL and/or the
  user name in the ``Authorization`` header.  In fact the transaction history
  might come from a "virtual" account, where multiple real bank accounts are
  merged into one history.

  Transactions are identified by an opaque numeric identifier, referred to here
  as *row ID*.  The semantics of the row ID (including its sorting order) are
  determined by the bank server and completely opaque to the client.

  The list of returned transactions is determined by a row ID *starting point*
  and a signed non-zero integer *delta*:

  * If *delta* is positive, return a list of up to *delta* transactions (all matching
    the filter criteria) strictly **after** the starting point.  The transactions are sorted
    in **ascending** order of the row ID.
  * If *delta* is negative, return a list of up to *-delta* transactions (all matching
    the filter criteria) strictly **before** the starting point.  The transactions are sorted
    in **descending** order of the row ID.

  If *starting point* is not explicitly given, it defaults to:

  * A value that is **smaller** than all other row IDs if *delta* is **positive**.
  * A value that is **larger** than all other row IDs if *delta* is **negative**.

  **Request**

  :query start: *Optional.*
    Row identifier to explicitly set the *starting point* of the query.
  :query delta:
    The *delta* value that determines the range of the query.
  :query long_poll_ms: *Optional.*  If this parameter is specified and the
    result of the query would be empty, the bank will wait up to ``long_poll_ms``
    milliseconds for new transactions that match the query to arrive and only
    then send the HTTP response.  A client must never rely on this behavior, as
    the bank may return a response immediately or after waiting only a fraction
    of ``long_poll_ms``.

  **Response**

  :http:statuscode:`200 OK`: JSON object of type `IncomingHistory`.
  :http:statuscode:`400 Bad request`: Request malformed. The bank replies with an `ErrorDetail` object.
  :http:statuscode:`401 Unauthorized`: Authentication failed, likely the credentials are wrong.
  :http:statuscode:`404 Not found`: The endpoint is wrong or the user name is unknown. The bank replies with an `ErrorDetail` object.

  .. ts:def:: IncomingHistory

    interface IncomingHistory {

      // Array of incoming transactions.
      incoming_transactions : IncomingBankTransaction[];

    }

  .. ts:def:: IncomingBankTransaction

    // Union discriminated by the "type" field.
    type IncomingBankTransaction =
    | IncomingReserveTransaction
    | IncomingWadTransaction;

  .. ts:def:: IncomingReserveTransaction

    interface IncomingReserveTransaction {
      type: "RESERVE";

      // Opaque identifier of the returned record.
      row_id: SafeUint64;

      // Date of the transaction.
      date: Timestamp;

      // Amount transferred.
      amount: Amount;

      // Payto URI to identify the receiver of funds.
      // This must be one of the exchange's bank accounts.
      credit_account: string;

      // Payto URI to identify the sender of funds.
      debit_account: string;

      // The reserve public key extracted from the transaction details.
      reserve_pub: EddsaPublicKey;

    }

  .. ts:def:: IncomingWadTransaction

    interface IncomingWadTransaction {
      type: "WAD";

      // Opaque identifier of the returned record.
      row_id: SafeUint64;

      // Date of the transaction.
      date: Timestamp;

      // Amount transferred.
      amount: Amount;

      // Payto URI to identify the receiver of funds.
      // This must be one of the exchange's bank accounts.
      credit_account: string;

      // Payto URI to identify the sender of funds.
      debit_account: string;

      // Base URL of the exchange that originated the wad.
      origin_exchange_url: string;

      // The reserve public key extracted from the transaction details.
      wad_id: WadId;
    }


.. http:get:: ${BASE_URL}/history/outgoing

  Return a list of transactions made by the exchange, typically to a merchant.

  The bank account of the exchange is determined via the base URL and/or the
  user name in the ``Authorization`` header.  In fact the transaction history
  might come from a "virtual" account, where multiple real bank accounts are
  merged into one history.

  Transactions are identified by an opaque integer, referred to here as *row
  ID*.  The semantics of the row ID (including its sorting order) are
  determined by the bank server and completely opaque to the client.

  The list of returned transactions is determined by a row ID *starting point*
  and a signed non-zero integer *delta*:

  * If *delta* is positive, return a list of up to *delta* transactions (all matching
    the filter criteria) strictly **after** the starting point.  The transactions are sorted
    in **ascending** order of the row ID.
  * If *delta* is negative, return a list of up to *-delta* transactions (all matching
    the filter criteria) strictly **before** the starting point.  The transactions are sorted
    in **descending** order of the row ID.

  If *starting point* is not explicitly given, it defaults to:

  * A value that is **smaller** than all other row IDs if *delta* is **positive**.
  * A value that is **larger** than all other row IDs if *delta* is **negative**.

  **Request**

  :query start: *Optional.*
    Row identifier to explicitly set the *starting point* of the query.
  :query delta:
    The *delta* value that determines the range of the query.
  :query long_poll_ms: *Optional.*  If this parameter is specified and the
    result of the query would be empty, the bank will wait up to ``long_poll_ms``
    milliseconds for new transactions that match the query to arrive and only
    then send the HTTP response.  A client must never rely on this behavior, as
    the bank may return a response immediately or after waiting only a fraction
    of ``long_poll_ms``.

  **Response**

  :http:statuscode:`200 OK`: JSON object of type `OutgoingHistory`.
  :http:statuscode:`400 Bad request`: Request malformed. The bank replies with an `ErrorDetail` object.
  :http:statuscode:`401 Unauthorized`: Authentication failed, likely the credentials are wrong.
  :http:statuscode:`404 Not found`: The endpoint is wrong or the user name is unknown. The bank replies with an `ErrorDetail` object.

  .. ts:def:: OutgoingHistory

    interface OutgoingHistory {

      // Array of outgoing transactions.
      outgoing_transactions : OutgoingBankTransaction[];

    }

  .. ts:def:: OutgoingBankTransaction

    interface OutgoingBankTransaction {

      // Opaque identifier of the returned record.
      row_id: SafeUint64;

      // Date of the transaction.
      date: Timestamp;

      // Amount transferred.
      amount: Amount;

      // Payto URI to identify the receiver of funds.
      credit_account: string;

      // Payto URI to identify the sender of funds.
      // This must be one of the exchange's bank accounts.
      debit_account: string;

      // The wire transfer ID in the outgoing transaction.
      wtid: ShortHashCode;

      // Base URL of the exchange.
      exchange_base_url: string;
    }


-----------------------
Wire Transfer Test APIs
-----------------------

Endpoints in this section are only used for integration tests and never
exposed by bank gateways in production.

.. http:post:: ${BASE_URL}/admin/add-incoming

  Simulate a transfer from a customer to the exchange.  This API is *not*
  idempotent since it's only used in testing.

  **Request:** The body of this request must have the format of a `AddIncomingRequest`.

  **Response:**

  :http:statuscode:`200 OK`:
    The request has been correctly handled, so the funds have been transferred to
    the recipient's account.  The body is a `AddIncomingResponse`.
  :http:statuscode:`400 Bad request`:
    The request is malformed. The bank replies with an `ErrorDetail` object.
  :http:statuscode:`401 Unauthorized`:
    Authentication failed, likely the credentials are wrong.
  :http:statuscode:`404 Not found`:
    The endpoint is wrong or the user name is unknown. The bank replies with an `ErrorDetail` object.
  :http:statuscode:`409 Conflict`:
    The 'reserve_pub' argument was used previously in another transfer, and the specification mandates that reserve public keys must not be reused.

  .. ts:def:: AddIncomingRequest

    interface AddIncomingRequest {
      // Amount to transfer.
      amount: Amount;

      // Reserve public key that is included in the wire transfer details
      // to identify the reserve that is being topped up.
      reserve_pub: EddsaPublicKey;

      // Account (as payto URI) that makes the wire transfer to the exchange.
      // Usually this account must be created by the test harness before this API is
      // used.  An exception is the "exchange-fakebank", where any debit account can be
      // specified, as it is automatically created.
      debit_account: string;
    }


  .. ts:def:: AddIncomingResponse

    interface AddIncomingResponse {

      // Timestamp that indicates when the wire transfer will be executed.
      // In cases where the wire transfer gateway is unable to know when
      // the wire transfer will be executed, the time at which the request
      // has been received and stored will be returned.
      // The purpose of this field is for debugging (humans trying to find
      // the transaction) as well as for taxation (determining which
      // time period a transaction belongs to).
      timestamp: Timestamp;

      // Opaque ID of the transaction that the bank has made.
      row_id: SafeUint64;
    }