README.md |
Revolut Card API
Base address
https://app.revolut.com/api/revolut-secure/retail
Headers
{
"authority": "app.revolut.com",
"accept": "application/json",
"content-type": "application/jso",
"origin": "chrome-extension://hdlehfdjcalidklijenibmpcdgjfmafn",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "cross-site",
"user-agent": "<chrome user agent>",
"x-browser-application": "BROWSER_EXTENSION",
"x-client-version": "100.0",
"x-device-id": "<random uid>",
"x-device-model": "<same as user agent>"
}
Authentication
POST /signin
Description
Login with phone number and passcode and get a token.
Request
{
"phone":"<+XX phone>",
"password":"<passcode>",
"channel":"APP"
}
Response
{
"tokenId":"<token uid>"
}
POST /token (issue)
Description
Once a token is obtained through the login request, the signin request has to be confirmed on the app. This request is used for polling for that authorization and then getting actual credentials.
Request
{
"phone":"<+XX phone>",
"password":"<passcode>",
"tokenId":"<token uid>"
}
Response
Case 1 - Authorization Pending
{
"message": "One should obtain consent from the user before continuing",
"code": 9035
}
Case 2 - Authorization Granted
{
"tokenExpiryDate": <expiry timestamp>,
"refreshCode": "<refresh code>",
"ownerId": "<owner id>,
"accessToken": "<access token>",
"user": {
"id": "<user id> (should be same as <owner id>)",
"state": "ACTIVE"
}
}
POST /token (refresh)
Description
The token has to be periodically refreshed.
Request
{
"userId":"<user id>"
"refreshCode":"<refresh code>"
}
Response
{
"tokenExpiryDate": <expiry date>,
"refreshCode": "<refresh code>",
"ownerId": "<owner id>",
"accessToken": "<access token>"
}
GET /user/current/picture
Description
Get user profile picture.
Headers
{
"Authorization": <owner id>:<access token>
}
Response
Profile picture raw bytes.
GET /user/current
Description
Get user details, including email, phone, full address, username, id, code.
Headers
{
"Authorization": <owner id>:<access token>
}
Response
{
"user": {
"id": "<user id>",
"individualId": "<user id>",
"createdDate": <creation date>,
"address": {
"city": "<city>",
"country": "<country code>",
"postcode": "<post code>",
"region": "<region>",
"streetLine1": "<address line 1>",
"streetLine2": "<address line 2>"
},
"birthDate": [
<year>,
<month>,
<day>
],
"firstName": "<first name>",
"lastName": "<last name>",
"phone": "<+XX phone>",
"email": "<email>",
"emailVerified": true,
"state": "ACTIVE",
"referralCode": "<code>",
"code": "<code>",
"kyc": "PASSED",
"underReview": false,
"locale": "en-GB",
"riskAssessed": false,
"username": "<username>",
"identityDetails": {
"accountPurpose": "DAILY_SPENDING",
"taxResidencies": [],
"identificationNumbers": [
{
"country": "<country code>",
"name": "genericTin",
"value": "<?>"
}
]
},
"hasProfilePicture": true,
"appMode": "FULL"
},
"wallet": {
"baseCurrency": "EUR"
}
}
GET /my-card/all
Description
Get an array of all the available cards in the account, without secret details. In a personal account, cards can be either virtual or physical. Virtual cards can also be tagged as single use (disposable). It is also known whether a card is for professional use (PRO
) or for personal use (RETAIL
).
Headers
{
"Authorization": <owner id>:<access token>
}
Response
[
{
"id": "<card id>",
"walletId": "<wallet id>",
"label": "<label>",
"state": "ACTIVE",
"virtual": true,
"disposable": false,
"credit": false,
"instalment": false,
"customised": false,
"brand": "MASTERCARD",
"design": "<design enum>",
"designGroup": "VIRTUAL",
"colour": "#<hex color>",
"lastUsedDate": <last used>,
"lastFour": "<last four digits>",
"expiryDate": <expiry date>,
"replaced": false,
"createdDate": <created date>,
"productType": "PRO",
"settings": {
"locationSecurityEnabled": false,
"magstripeDisabled": true,
"atmWithdrawalsDisabled": true,
"ecommerceDisabled": false,
"contactlessDisabled": false,
"initial": false,
"pockets": [
{
"id": "<pocket id>",
"pocketType": "MERCHANT"
},
{
"id": "<pocket id>",
"pocketType": "MERCHANT"
}
]
},
"delivery": {
"status": "NONE"
},
"usage": <?>,
"preexpired": false,
"applePayEligible": true,
"googlePayEligible": true,
"cardClickActivationEligible": false,
"panActivationEligible": false
},
{
"id": "<card id>",
"walletId": "<wallet id>",
"label": "<label>",
"state": "ACTIVE",
"virtual": true,
"disposable": false,
"credit": false,
"instalment": false,
"customised": false,
"brand": "VISA",
"design": "<design enum>",
"designGroup": "VIRTUAL",
"colour": "#<hex color>",
"lastUsedDate": <last used>,
"lastFour": <last four digits>",
"expiryDate": "<expiry date>",
"replaced": false,
"createdDate": <created date>,
"productType": "RETAIL",
"settings": {
"locationSecurityEnabled": false,
"magstripeDisabled": true,
"atmWithdrawalsDisabled": true,
"ecommerceDisabled": false,
"contactlessDisabled": false,
"initial": false,
"pockets": []
},
"delivery": {
"status": "NONE"
},
"usage": <?>,
"preexpired": false,
"applePayEligible": true,
"googlePayEligible": true,
"cardClickActivationEligible": false,
"panActivationEligible": false
}
]
GET /my-card//details
Description
Get card secret details: pan, cvv, expiration date. The pan and the cvv are encrypted using AES ECB with the first 32 ascii chars of the token as key.
Headers
{
"Authorization": <owner id>:<access token>
}
Response
{
"pan":"<base64 of AES encrypted pan>",
"cvv":"<base64 of AES encrypted cvv>",
"expiry":{"month":<month>,"year":<year>}
}
POST /my-card/issue/virtual
Description
Create a new virtual card. Design is an enum and must match the card type (there are virtual designs and disposable designs).
Headers
{
"Authorization": <owner id>:<access token>
}
Request
{
design: "<color>_VIRTUAL",
label: "<label>",
disposable: false
}
Response
Card object, same as /my-card/all
.
TODO
Support for card termination, issue, freeze, unfreeze, labeling, and creation is quite simple too.