Skip to content

Latest commit

 

History

History

http-api

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 

tbDEX HTTP API

Introduction

This specification defines a REST API that can be hosted by an individual PFI that wants to provide liquidity via tbDEX

Status

Version: Draft

Note

This specification will continue to be in a Draft state until there are two separate PFIs deployed and providing liquidity to individuals or other institutions

Table of Contents

Discoverability

PFIs can become publicly discoverable by advertising their API endpoint as a Service within their DID Document. In order to increase the likelihood of being discovered The service entry SHOULD include the following properties:

Property Value
id see DID-CORE spec
type PFI
serviceEndpoint PFI's publicly addressable API endpoint, the base URL with which tbDEX HTTP requests can be made.

Example

{
  "id": "did:example:pfi",
  "service": [{
    "id":"#my-pfi",
    "type": "PFI",
    "serviceEndpoint": "https://pfi.organization.com"
  }]
}

This example illustrates that:

  • The ID can be chosen at the discretion of the PFI, but the service entry should be of type PFI.
  • The serviceEndpoint of the PFI https://pfi.organization.com is the PFI's base URL.
    • The PFI's base URL is combined with relative paths listed below (i.e. POST /exchanges) by the client to create an tbDEX HTTP request to the PFI.

Note

Decentralized discoverability is dependent upon whether the underlying verifiable registry of the selected DID Method is crawlable

Error Responses

  • An error response is one whose status code is >= 400.
  • If present, the body of an error response will conform to the following:

Error response structure

Field Type Required Description
message String Y A human-readable explanation specific to this occurrence of the problem.
details ErrorDetail[] N Optional array of ErrorDetail objects

ErrorDetail structure

Field Type Required Description
id String N Optional server-generated request-specific ID, useful for diagnosing unexpected errors
message String N A human-readable explanation specific to this occurrence of the problem.
path String N Path where validation failed (i.e. JSON schema path)

Example

{
  "message": "Missing field: payin.amount",
  "details": [{ 
    "id": "9af2bf88-e4f4-4f81-8ba9-55eaeeb718e2",
    "message": "Payin amount must be present.",
    "path": "$.payin.amount" 
  }]
}

Query Params

Query parameters, also known as query strings, are a way to send additional information to the server as part of a URL. They allow clients to provide specific input or customize the server's response. Query parameters typically follow the main URL and start with a ? character. They consist of key-value pairs, and multiple pairs can be separated by & characters

Query params are supported by many of the GET /${resource} endpoints in the following ways

  • Simple Example: ?field=simpleValue
  • Same Field; Multiple Values: field=value&field=anotherValue

Query Param support is optional for all GET endpoints that return a list that can be filtered by parameters.

Pagination

Pagination is supported using the following query params:

Param Description Default
page[offset] Specifies the starting position from where the records should be retrieved. 0
page[limit] Specifies the maximum number of records to be retrieved. 10

Example

/?page[offset]=0&page[limit]=10

Pagination support is optional for all GET endpoints that return a list.


Idempotency

The IDs of individual tbDEX messages are used as idempotency keys. For example, in a tbDEX Order message:

{
  "metadata": {
    "from": "did:key:z6MkvUm6mZxpDsqvyPnpkeWS4fmXD2jJA3TDKq4fDkmR5BD7",
    "to": "did:ex:pfi",
    "exchangeId": "rfq_01ha83pkgnfxfv41gpa44ckkpz",
    "kind": "order",
    "id": "order_01ha83pkgsfk6t1kxg7q42s48j",
    "createdAt": "2023-09-13T20:28:40.345Z",
    "protocol": "2.0"
  },
  "data": {},
  "signature": "eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDprZXk6ejZNa3ZVbTZtWnhwRHNxdnlQbnBrZVdTNGZtWEQyakpBM1RES3E0ZkRrbVI1QkQ3I3o2TWt2VW02bVp4cERzcXZ5UG5wa2VXUzRmbVhEMmpKQTNUREtxNGZEa21SNUJENyJ9..tWyGAiuUXFuVvq318Kdz-EJJgCPCWEMO9xVMZD9amjdwPS0p12fkaLwu1PSLxHoXPKSyIbPQnGGZayI_v7tPCA"
}

The ID here that serves as idempotency key is order_01ha83pkgsfk6t1kxg7q42s48j. Each tbDEX message's idempotency key can be accessed via message.metadata.id like so:

val order = Order.create(...)
val orderId = order.metadata.id

Callbacks

Callbacks are implemented via the replyTo property on the request to create an exchange.

replyTo is a fully qualified URI which could either be a DID or a URL.

If replyTo is present, a PFI will send any/all new messages for a given exchange to the supplied URI. This makes the URI scoped to each exchange, allowing the caller to specify a different URI per exchange if they so wish.

If replyTo is not present, the caller will have to poll the PFI for the exchange in question to receive new messages.


Protected Endpoints

A protected endpoint is defined as one that requires the requester to be authenticated. These endpoints respond with resources specific to the authenticated DID e.g.

  • Messages sent by or intended for the requester only
  • Balances

Note

Each individual endpoint section in this specification will include Protected: true/false to indicate whether it is protected

Authentication

When accessing a protected endpoint, a tbdex http client MUST set the HTTP Authorization Header in order to be authenticated.

The value of the header MUST use the Bearer Authentication Scheme as defined in RFC 6750, and the access token MUST be a JWT.

Token Generation

The bearer token is a JSON Web Token (JWT) generated by the requester. It must consist of JWT header and Claims Set containing the below fields, and signed using the verification method published as the authentication verification relationship in the requester's DID document.

Header

Key Description
typ JWT. Setting typ to JWT as recommended by the JWT spec provides a means to disambiguate among different types of signatures and tokens.
kid Fully qualified VerificationMethod ID. Used to locate the DID Document verification method utilized to verify the integrity of the JWT.
alg Cryptographic algorithm used to compute the JWT signature.

Claims Set

Key Description
aud The intended PFI's DID. Incorporating the aud claim limits the risk to just one PFI in case a request token is compromised, thereby reducing the surface area for misuse.
iss The requester's DID. Included to be informative, though it is technically duplicative as the kid also includes the requester's DID.
exp Expiration timestamp. Limits the amount of time a compromised request token can be used.
iat Indicates when the JWT was created. Included to be informative.
jti Used as a nonce to prevent replay attacks. The specification text should include more detail on how to prevent these attacks.

Note

This bearer token is sufficient for authentication as it proves that the requester controls the private key associated to the DID that the requester is identifying as.

Token Verification

The receiver of the token must evaluate it to ensure its validity. A bearer token is valid if these conditions are met:

  • exp timestamp is not in the past
  • aud is the DID of the receiving PFI's DID
  • kid is resolved to be a valid DID whose DID Document verification method is used to verify the integrity of the JWT
  • jti is not a nonce that was previously used by the same requester

Offerings

The Offering resource is used to convey the currency pairs a PFI is offering. It includes information about payment methods and associated fees.

List Offerings

Description

Used to fetch offerings from a PFI

Endpoint

GET /offerings

Protected

False

Response

Status Body
200: OK { data: Offering[] }
400: Bad Request { errors: Error[] }

Exchanges

An exchange is a series of linked tbDEX messages between Alice and a PFI for a single exchange. An exchange can be created by submitting an RFQ.

Create Exchange

Description

Submits an RFQ (Request For Quote). Alice is asking the PFI to provide a Quote so she can evaluate it.

Endpoint

POST /exchanges

Protected

False

Request Body

CreateExchangeRequest

field data type required description
message object Y The request for quote (RFQ) tbDEX message
replyTo string N A string containing a valid URI where new messages from the PFI will be sent

Important

See RFQ structure here

{
  "message": {
    {
      "metadata": {
        "from": "did:key:z6Mks4N5XdrE6VieJsgH8SMSRavmTox74RqoroW7bZzBLQBi",
        "to": "did:ex:pfi",
        "kind": "rfq",
        "id": "rfq_01ha835rhefwmagsknrrhvaa0k",
        "exchangeId": "rfq_01ha835rhefwmagsknrrhvaa0k",
        "createdAt": "2023-09-13T20:19:28.430Z",
        "protocol": "2.0"
      },
      "data": {
        "offeringId": "abcd123",
        "payinMethod": {
          "kind": "DEBIT_CARD",
          "paymentDetails": "<HASH_PRIVATE_PAYIN_METHOD_PAYMENT_DETAILS>"
        },
        // ...
      }
    }
  },
  "replyTo": "https://alice.wallet.com/events"
}

Response

Status Body
202: Accepted N/A
400: Bad Request { errors: Error[] }

Errors

Status Description
400 Validation error(s)
400 Failed Signature Check
409 Exchange already exists

Submit Order/Cancel

Description

This endpoint can receive either an Order or a Cancel message. Alice can submit an Order, which indicates that she wants the PFI to execute on the Quote she received. Alice can submit a Cancel, which indicates that Alice is no longer interested in continuing with the exchange.

Endpoint

PUT /exchanges/:exchange_id

Protected

False

Request Body

Important

See Order structure here. See Cancel structure here

{
  "message": { } // order or cancel message
}

Response

Status Body
202: Accepted N/A
400: Bad Request { errors: Error[] }

Errors

Status Description
400 Failed Signature Check
404 Exchange not found
409 Order or Cancel not allowed

Get Exchange

Description

Retrieves all messages associated to a specific exchange

Endpoint

GET /exchanges/:exchange_id

Protected

True. See Authentication section for more details.

Response

Status Body
200: OK { data: TbdexMessage[] }
400: Bad Request { errors: Error[] }
401: Unauthorized { errors: Error[] }
404: Not Found N/A

List Exchanges

Description

Returns a list of exchange IDs

Endpoint

GET /exchanges

Protected

True. See Authentication section for more details.

Response

Status Body
200: OK List of exchangeIds, i.e. { data: string[] }
400: Bad Request { errors: Error[] }
401: Unauthorized { errors: Error[] }
404: Not Found N/A

List Balances

This endpoint is OPTIONAL. It is only relevant for PFIs which expose a stored balance functionality either for institutional or retail customers.

Description

Returns an array of balance resources for each currency held by the caller.

Protected

True. See Authentication section for more details.

Endpoint

GET /balances

Response

Status Body
200: OK { data: Balance[] } See Balance structure
400: Bad Request { errors: Error[] }
401: Unauthorized { errors: Error[] }
404: Not Found N/A

References