# Introduction

**Testbank** is a HTTPS JSON REST API, compliant to [the JSON:API specification](https://jsonapi.org/format/), that lets you simulate bank accounts & transactions **without** interacting with real money.

This is ideal for software that interacts with real-world banks - you can build a generic "*testbank*" integration alongside your other "real" lenders & only expose real lenders when you're ready.

***

This API offers endpoints for you to:

* CRUD operations on [**Accounts**](https://www.testbank.dev/accounts).
* List & create [**Transactions**](https://www.testbank.dev/transactions) between **Accounts**.

<details>

<summary>Coming soon...</summary>

We're working on bringing you the best features to test a variety of banking integrations, including:

* **Rate-limits:** Protect uptime for all **Testbank** users with sensible rate-limits.
* **Webhooks:** Receive real-time notifications when funds land/leave your accounts.
* **Statements:** Build & download PDFs of transactions in a window
  * e.g. PDFs of last month's transactions
* **Loans:** Disburse & repay loans with a test lender.
* **Audit logs:** Review audit logs for your accounts.
* **Exchange rate fees:** Simulate real-world transaction fees when transferring between accounts of different exchange rates.
* **Transfer fees:** Specify a range of transaction fees to apply when creating a transaction from one of your accounts, to better simulate a real-world lender.
* **Notifications:** Receive notifications regarding your accounts & transactions.

</details>

## Requests

{% hint style="success" %}

* You must only send HTTPS requests to this API.
* This API reads & writes in JSON - no other formats are supported.
* **Authentication** is required for each request.
* You should paginate endpoints where endpoints support it.
  {% endhint %}

{% hint style="danger" %}

* Non-secure (HTTP) traffic will be dropped.
* Setting the Accept header to a value other than `application/json` will return a `406 Not Acceptable` status.
* Unauthenticated requests will return a `401 Unauthorized` status to protected resources.
* Cross-Origin Resource Sharing (CORS) is not supported.
* Requests or responses larger than 5MB will fail - please paginate endpoints to reduce the likelihood of seeing this error.
  {% endhint %}

## Authentication

You will be given a private static Authentication Token by your account manager. This token must be used in all requests you make to the Testbank API, and should be provided in the Authorization header as a Bearer token:

{% tabs %}
{% tab title="HTTP" %}

```http
GET / HTTP/1.1
Authorization: Bearer $TestbankAuthToken
Host: api.testbank.dev

HTTP/1.1 200 OK
Content-Type: application/json
{
    "meta": {
        "name": "Testbank API",
        "version": "2023.7"
    },
    "links": {
        "self": "https://api.testbank.dev/"
    }
}
```

{% endtab %}

{% tab title="CURL" %}

```sh
$ curl --request GET \
       --url https://api.testbank.dev/ \
       --header 'accept: application/json' \
       --header 'authorization: Bearer $TestbankAuthToken'
{"meta":{"name":"Testbank API","version":"2023.7"},
 "links":{"self":"https://api.testbank.dev/"}}
```

{% endtab %}

{% tab title="fetch (JS)" %}

```javascript
import fetch from 'fetch';

const res = await fetch('https://api.testbank.dev', {
    headers: {
        'Authorization': 'Bearer $TestbankAuthToken'
    },
});

const data = await res.json();
console.log(data);
// {"meta":{"name":"Testbank API","version":"2023.7"},
//  "links":{"self":"https://api.testbank.dev/"}}
```

{% endtab %}
{% endtabs %}

## Includes

[Following the JSON:API specification](https://jsonapi.org/format/#fetching-includes), you can get the response body of a request to include resources for relationship data by passing an `include` query string parameter with the appropriate comma-separated string of paths.

For example, to return the Accounts when fetching a Transaction by ID, you would use:

```json
// /transactions/{transactionId}?include=sender,recipient

{
    "data": {
        "type": "transactions",
        "id": "{transactionId}",
        "attributes": { /* Transaction attributes */ },
        "relationships": {
            "sender": {
                "data": {
                    "type": "accounts",
                    "id": "a1b2c3d4e5"
                }
            },
            "recipient": {
                "data": {
                    "type": "accounts",
                    "id": "f6g7h8i9j0"
                }
            }
        }
    },
    "included": [
        {
            "type": "accounts",
            "id": "a1b2c3d4e5",
            "attributes": { /* Sender Account attributes */ },
            "meta": { /* Sender Account metadata */ }
        },
        {
            "type": "accounts",
            "id": "f6g7h8i9j0",
            "attributes": { /* Recipient Account attributes */ },
            "meta": { /* Recipient Account metadata */ }
        }
    ]
}
```

## Pagination

Some endpoints support paginating resources. For these endpoints, you will see:

```json
{
    "meta": {
        "total": 150,
        "limit": 20
    },
    "data": [
        // List of resources in this page of results
    ],
    "links": {
        "prev": null,
        "next": "/...?page[count]=2&page[limit]=20",
        "first": "/...?page[count]=1&page[limit]=20",
        "last": "/...?page[count]=8&page[limit]=20"
    }
}
```

* By default, all endpoints that support pagination will return 20 resources, with a maximum of 100 resources.
* You can calculate the total number of pages by rounding up the value of `meta.total` ÷ `meta.limit`.
* `links.prev`/`links.next` will be `null` if there is no previous/next page, respectively.
* If you include your own pagination query (e.g. `?page[limit]=50`) in your request, the API will adjust the `links` accordingly.

{% hint style="warning" %}
For the stability of your integration, you shouldn't try to parse `links`, or try to guess/construct the format of URLs, as your integration will break if the URL format is changed in the future.
{% endhint %}

***

{% content-ref url="faqs" %}
[faqs](https://www.testbank.dev/faqs)
{% endcontent-ref %}
