/revolut-money-transfer

Solution to Revolut backend test.

Primary LanguageKotlin

Revolut Money Transfer REST API

A thread safe RESTful API facilitating money transfers between accounts.

Getting Started

Build the program via maven with the following command:

mvn clean install

Start application:

java -jar target/money-transfer-api-1.0.0-jar-with-dependencies.jar

A postman collection for testing the API is available for download here.

Technologies used

  • Kotlin as implementation language.
  • Javalin as a web API framework.
  • Jackson for JSON serialization and deserialization.
  • JUnit and Hemcrest for unit tests.
  • Unirest.

API documentation

The following REST resources are exposed by the API:

Http method Endpoint Sample Request Body Description
POST /accounts { "accountName": "Account Name", "currency": "NGN" } This resource creates a new account.
GET /accounts/:account_id This resource gets the details of a given account.
GET /accounts This resource gets a paginated list of created accounts. 'page' and 'limit' are optional query parameters.
POST /accounts/:account_id/deposits { "amount": 10000, "currency": "NGN" } Use this resource to fund a created account.
POST /accounts/:account_id/withdrawals { "amount": 10000, "currency": "NGN" } Use this resource to withdraw funds from a created account.
POST /account/:sender_account_id/transfers/:recipient_account_id { "amount": 1, "currency": "GBP" } This resource handles money transfers between created accounts.
GET /account/:account_id/transactions Resource used to retrieve paginated list of transactions performed on a given account.

POST /accounts

Create account in the service.

Sample request:

{
	"accountName": "Ibukun Adelekan",
	"currency": "GBP"
}

Sample response:

{
    "status": "success",
    "data": {
        "accountName": "Ibukun Adelekan",
        "balance": "0.00",
        "status": "enabled",
        "id": "956aec8bd9a74cb8bb52fc6060eec009",
        "currency": {
            "name": "GBP",
            "id": "a81d51037da9485cb8850d30d3fe8913"
        }
    }
}

POST /accounts/:accountId/deposits

Deposit money to a given account.

Sample request:

{
	"amount": "25000",
	"currency": "GBP"
}

Sample response:

{
    "status": "success",
    "data": {
        "account": {
            "id": "956aec8bd9a74cb8bb52fc6060eec009",
            "accountName": "Ibukun Adelekan",
            "balance": "25000.00",
            "status": "enabled",
            "currency": {
                "id": "a81d51037da9485cb8850d30d3fe8913",
                "name": "GBP"
            }
        },
        "transaction": {
            "id": "9da7b5c7e38741049a7a2651848c3348",
            "amount": "25000.00",
            "transactionReference": "TXN-21ee860d990346beb1760ad4909b39a2",
            "sessionReference": "SESSION-39f475d1a71941ee99ae5ef854f735ef}",
            "type": "CREDIT",
            "category": "ACCOUNT_FUNDING",
            "balanceBefore": "0.00",
            "balanceAfter": "25000.00",
            "createdAt": "2019-10-15T02:13:09"
        }
    }
}

GET /accounts/:accountId

Fetch details of a specified account - including the account currency and balance.

Sample response:

{
    "status": "success",
    "data": {
        "id": "956aec8bd9a74cb8bb52fc6060eec009",
        "accountName": "Ibukun Adelekan",
        "balance": "25000.00",
        "status": "enabled",
        "currency": {
            "id": "a81d51037da9485cb8850d30d3fe8913",
            "name": "GBP"
        }
    }
}

GET /accounts

Fetch a list of all created accounts.

Query Parameters:

  • page (optional): Current page. 1 by default
  • limit (optional): Size of page. 50 by default.

Sample response:

{
    "status": "success",
    "data": [
        {
            "id": "956aec8bd9a74cb8bb52fc6060eec009",
            "accountName": "Ibukun Adelekan",
            "balance": "25000.00",
            "status": "enabled",
            "currency": {
                "id": "a81d51037da9485cb8850d30d3fe8913",
                "name": "GBP"
            }
        },
        {
            "id": "bcaa9836b0374f38b7752eeaaa9beaf8",
            "accountName": "Iyanu Adelekan",
            "balance": "0.00",
            "status": "enabled",
            "currency": {
                "id": "6aed93c40143491b80a45ff5a6f23f59",
                "name": "NGN"
            }
        }
    ]
}

POST /account/:sender_account_id/transfers/:recipient_account_id

Transfers money between accounts.

Sample request:

{
	"amount": 10000.00,
	"currency": "NGN",
	"description": "Hold this for me"
}

Sample response:

{
    "status": "success",
    "data": {
        "account": {
            "id": "956aec8bd9a74cb8bb52fc6060eec009",
            "accountName": "Ibukun Adelekan",
            "balance": "24978.00",
            "status": "enabled",
            "currency": {
                "id": "a81d51037da9485cb8850d30d3fe8913",
                "name": "GBP"
            }
        },
        "transaction": {
            "id": "054b91c478e2422dbb0b93b6194a6db0",
            "amount": "22.00",
            "recipientAccountId": "bcaa9836b0374f38b7752eeaaa9beaf8",
            "transactionReference": "TXN-0edfd47b595b4cceabf8a2afe064c75b",
            "sessionReference": "SESSION-1ee393610327405eb6abdec95f5196e1}",
            "type": "DEBIT",
            "category": "BANK_TRANSFER",
            "description": "Hold this for me",
            "balanceBefore": "25000.00",
            "balanceAfter": "24978.00",
            "createdAt": "2019-10-15T02:15:27"
        }
    }
}

POST /accounts/:accountId/withdrawals

Withdraws money to the given account.

Sample request:

{
	"amount": "10000",
	"currency": "NGN"
}

Sample response:

{
    "status": "success",
    "data": {
        "account": {
            "id": "956aec8bd9a74cb8bb52fc6060eec009",
            "accountName": "Ibukun Adelekan",
            "balance": "24968.00",
            "status": "enabled",
            "currency": {
                "id": "a81d51037da9485cb8850d30d3fe8913",
                "name": "GBP"
            }
        },
        "transaction": {
            "id": "64ac9c1454684b40b1b17aec51727d69",
            "amount": "10.00",
            "transactionReference": "TXN-fc1d832ee07e43c4a5a2f91d104100dc",
            "sessionReference": "SESSION-90583e2fc2664173a5c1b08ac4b14afa}",
            "type": "DEBIT",
            "category": "ACCOUNT_WITHDRAWAL",
            "balanceBefore": "24978.00",
            "balanceAfter": "24968.00",
            "createdAt": "2019-10-15T02:16:49"
        }
    }
}

GET /account/:account_id/transactions

Get account transactions. Transactions are sorted in descending order by date and time performed.

Query Parameters:

  • page (optional): Current page. 1 by default
  • limit (optional): Size of page. 50 by default.

Sample Response:

{
    "status": "success",
    "data": [
        {
            "id": "64ac9c1454684b40b1b17aec51727d69",
            "amount": "10.00",
            "transactionReference": "TXN-fc1d832ee07e43c4a5a2f91d104100dc",
            "sessionReference": "SESSION-90583e2fc2664173a5c1b08ac4b14afa}",
            "type": "DEBIT",
            "category": "ACCOUNT_WITHDRAWAL",
            "balanceBefore": "24978.00",
            "balanceAfter": "24968.00",
            "createdAt": "2019-10-15T02:16:49"
        },
        {
            "id": "054b91c478e2422dbb0b93b6194a6db0",
            "amount": "22.00",
            "recipientAccountId": "bcaa9836b0374f38b7752eeaaa9beaf8",
            "transactionReference": "TXN-0edfd47b595b4cceabf8a2afe064c75b",
            "sessionReference": "SESSION-1ee393610327405eb6abdec95f5196e1}",
            "type": "DEBIT",
            "category": "BANK_TRANSFER",
            "description": "Hold this for me",
            "balanceBefore": "25000.00",
            "balanceAfter": "24978.00",
            "createdAt": "2019-10-15T02:15:27"
        },
        {
            "id": "9da7b5c7e38741049a7a2651848c3348",
            "amount": "25000.00",
            "transactionReference": "TXN-21ee860d990346beb1760ad4909b39a2",
            "sessionReference": "SESSION-39f475d1a71941ee99ae5ef854f735ef}",
            "type": "CREDIT",
            "category": "ACCOUNT_FUNDING",
            "balanceBefore": "0.00",
            "balanceAfter": "25000.00",
            "createdAt": "2019-10-15T02:13:09"
        }
    ]
}

Currencies and Exchange Rates

Deposits and transfers can be made in either NGN or USD. When transactions are done with two different currencies the following exchange rates apply:

  • NGN 1 -> GBP 0.0022
  • GBP 1 -> NGN 456.66

Error Codes

The following are the error codes that can be received from the server.

Server Error Code Description
1000 The request is being made in an unsupported HTTP content type.
1001 This error code means an invalid request parameter is being sent to the server
1002 The account does not have sufficient balance to perform given the transaction.

The error codes above are distinct from and do not replace HTTP status codes.

Tests

Unit and integration tests have been written to verify the correctness of the system. Tests can be run with the following command:

mvn test

Test Results