Overview
API Basics
The API is a RESTful Web Services with JSON formatted messages.
Basically, it means that :
- Submitting new data is performed with HTTP POST request
- Retrieving existing data is performed with HTTP GET request
- Modifying existing data is performed with HTTP PUT request
- Removing or canceling existing data is performed with HTTP DELETE request
All requests must be sent with the HTTP header Content-Type equals to application/json and be UTF-8 encoded.
Environments
- Production environment: https://emoney-services.w-ha.com
- Test / pre-production environment: https://test-emoney-services.w-ha.com
- End-point: /api/
- Both environments use HTTPS standards with TLS 1.2.
- Details informations (certificats chain, supported cyphers list...) about our certificat can be obtained through Qualys SSL Labs website.
Authentication
All requests require to be fully authenticated through the HTTP header Authorization. The content of the header should respect the format described below.
- All the requests must be sent from your server directly to our server and not from a user's browser or application.
- For security reasons, the API Access Key and Secret Key provided by W-HA must be stored securely in your server. It should never be accessible or visible to the end-users.
- It should not be stored or packaged in any source codes accessible from end-user point of view (html/javascript from a browser or in a source code of an application for Smartphone).
- The API Keys are accessible in your Dashboard in the Partner section.
Authorization Header
Authorization:AUTH api_access_key:timestamp:version:sign
| Property | Type | Value | Description |
|---|---|---|---|
| api_access_key | string | size = 32 max | API Key (provided by W-HA) |
| timestamp | long | Should not be aged of more than 5 minutes. | Timestamp of the request in milliseconds |
| version | integer | Version number of the authentication process | |
| sign | string | HMAC-SHA256 signature See below to see how to generate the signature |
Signature computation
The sign parameter is a HMAC-SHA256 of the following parameters separated by :
api_access_keytimestampversion- request body (JSON) (could be empty in some cases).
A secret shared key (provided by W-HA) called api_secret_key is used to compute the hash.
- stringToSign = api_access_key:timestamp:version:request_body
- sign = HMAC-SHA256(StringToSign, api_secret_key)
Example with a request body
api_access_key=OLqMu27t1mylpc2Dapi_secret_key=YMy7t54-WaF9F!LOSp994p1?0x8pUptimestamp=1494862655078version=1request_body={"tag":"my_new_tag"}- stringToSign =
OLqMu27t1mylpc2D:1494862655078:1:\{"tag":"my_new_tag"\} sign=2b6cf86e9f3d5c50a5b7f79aa10c9ce6da1fcd31211bf87374347274c168cf01
HTTP Header
Authorization: AUTH OLqMu27t1mylpc2D:1494862655078:1:2b6cf86e9f3d5c50a5b7f79aa10c9ce6da1fcd31211bf87374347274c168cf01
Example with no request body
api_access_key=OLqMu27t1mylpc2Dapi_secret_key=YMy7t54-WaF9F!LOSp994p1?0x8pUptimestamp=1494862788453version=1request_body=- stringToSign =
OLqMu27t1mylpc2D:1494862788453:1: sign=1e8b319599fa2185b55e502ed962490e9e23aceb920676e17c0ac76112d5450a
HTTP Header
Authorization: AUTH OLqMu27t1mylpc2D:1494862788453:1:1e8b319599fa2185b55e502ed962490e9e23aceb920676e17c0ac76112d5450a
Simplified sample in JAVA (with RestTemplate)
private static final String HEADER_FIELD_SEPARATOR = ":";
private String getAuthHeader(String apiKey, String apiSecret, String requestBody) {
String timestamp = "" + new Date().getTime();
String version = "1";
//stringTosign
String stringToSign = apiKey + ":" + timestamp + ":" + version + ":";
if (requestBody != null) {
stringToSign += requestBody;
}
//sign
String sign = EncodingUtils.encodeHmacSha256(stringToSign, apiSecret);
//header
String authHeader = "AUTH " + apiKey + ":" + timestamp + ":" + version + ":" + sign;
return authHeader;
}
public AccountDto getAccount(String accountId) {
//headers
HttpHeaders headers = new HttpHeaders();
headers.add(HEADER_AUTHORIZATION, this.getAuthHeader(apiKey, apiSecret, null));
try {
ResponseEntity responseEntity = restTemplate.exchange(baseUrl + "/accounts/" + accountId, HttpMethod.GET, new HttpEntity<>(headers), WalletDto.class);
return responseEntity.getBody();
} catch (HttpStatusCodeException e) {
//error management
} catch (RestClientException e) {
//error management
}
}
public SimpleExternalId createStandardAccount(AccountStandardRequest request) {
//convert body to JSON for signature computation
ObjectMapper objectMapper = new MappingJackson2HttpMessageConverter().getObjectMapper();
String requestBody = objectMapper.writeValueAsString(request));
//headers
HttpHeaders headers = new HttpHeaders();
headers.add(HEADER_AUTHORIZATION, this.getAuthHeader(apiKey, apiSecret, requestBody));
try {
ResponseEntity responseEntity = restTemplate.exchange(baseUrl + "/accounts/standard", HttpMethod.POST, new HttpEntity<>(requestBody, headers), SimpleExternalId.class);
return responseEntity.getBody();
} catch (HttpStatusCodeException e) {
//error management
} catch (RestClientException e) {
//error management
}
}
Versioning
Minor API modifications that are not breaking the compatibility with the existing API should be supported transparently by the partner.
Example of non-breaking changes:
- adding new API endpoint/service
- adding some optional parameters in request header, query or body of existing API
- adding some optional new properties in the response header or body of existing API
- adding new possible values in ENUM parameters of a request
- changing the order of properties in a response
- changing human-readable strings such as error message
- changing size or format of generated ids (object identifier) but respecting the documented maximal size
Major API modifications breaking the compatibility will be managed through a new version number in the API URL.
Example of breaking changes:
- renaming or removing existing endpoint/service
- renaming or adding mandatory parameters in the request header, query or body
- renaming or removing parameters in response header or body
- restricting allowed values of an ENUM in a request
Lists Pagination Management
Some Web Services return a list of elements (i.e GET /wallets return a list of Wallets). Responses of these services are based on a pagination mechanism to control the number of returned elements. By default, the response is the first page and the maximum number of returned elements is 20. This behavior can be changed for a requests by setting the following parameters :
| URL - Parameters | Type | Value | Description |
|---|---|---|---|
| page | integer | min = 1 optional default = 1 | Requested page index |
| per_page | integer | min = 1 max = 100 optional default = 20 | Maximum of element number per page |
The response HTTP body contains the list of elements and the response HTTP header includes the following properties:
| Header - Property | Type | Description |
|---|---|---|
| x-page | integer | Requested page index (equals to the request parameter page if it is set) |
| x-page-size | integer | Capacity for a page (equals to the request parameter per_page if it is set) |
| x-total-elements | long | The overall amount of elements corresponding to the search criteria (without pagination) |
| x-total-pages | integer | The number of pages corresponding to the search criteria |
Error management
If a request failed, HTTP status code of the response is different of 200 (or associated 201, 204 ...) and the body contains an error object structuring the detailed cause of the problem.
HTTP error code
| Code | Description |
| 400 Bad request | See error code / message in response body. |
| 401 Authentication failure | Authentication failed. |
| 403 Forbidden | Authentication is OK but you are not authorized to access this method. |
| 404 Not found | Error on hostname or URI. |
| 405 Method not allowed | Wrong utilization of the method (e.g. GET instead of POST). |
| 500 The server encountered an unexpected condition | In case of internal error. |
| 501 Not Implemented | Not supported. |
| 503 Server busy and service unavailable | Service temporary unavailable. Try later. |
Error Object
| Property | Type | Value | Description |
|---|---|---|---|
| code | string | size = 4 | Error code |
| message | string | max size = 300 | Error message |
Response Sample
HTTP/1.1 400 Bad Request
{
"code": "1004",
"message": "Invalid parameter(s)"
}
List of Error codes
| Code | Message | HTTP Status Code |
|---|---|---|
| 9001 | Internal error | 500 |
| 1001 | Unknown service version | 400 |
| 1002 | Authorization error | 401 |
| 1003 | Service forbidden | 403 |
| 1005 | Invalid request JSON format | 400 |
| 1006 | Invalid request parameter(s) | 400 |
| 2001 | Unknown Wallet id | 400 |
| 2002 | Wallet invalid status | 400 |
| 2003 | Wallet invalid type | 400 |
| 2004 | Operation not permitted because balance=****** | 400 |
| 2101 | Operation not permitted. | 400 |
| 2102 | Partner not available. | 400 |
| 2150 | API Key doesn't exist | 400 |
| 2151 | API Key cannot be deleted because this key is Active | 400 |
| 2201 | Unknown Account id | 400 |
| 2202 | Account invalid status | 400 |
| 2203 | Account invalid type | 400 |
| 2204 | Account invalid kyc level | 400 |
| 2205 | Invalid Birthdate - Minimum age required is **** | 400 |
| 2206 | Account already exist | 400 |
| 2207 | Account: KYC data remove not allowed '*****' | 400 |
| 2208 | Account: KYC data update not allowed '*****' | 400 |
| 2211 | Operation not permitted because Account Validation is in progress | 400 |
| 2212 | Account information and kyc level '*****' are not consistent, infos: ***** | 400 |
| 2213 | Requested Level must be greater than current | 400 |
| 2214 | No valid Document of type '*****' | 400 |
| 2220 | Kyc Status required | 400 |
| 2231 | Unknown Document id | 400 |
| 2232 | Document invalid status | 400 |
| 2233 | Unknown Document File id | 400 |
| 2235 | Document type 'PROOF_OF_IBAN' cannot be manage independently of Bank Account | 400 |
| 2251 | Document invalid format | 400 |
| 2252 | Document unreadable | 400 |
| 2253 | Document expired | 400 |
| 2254 | Document invalid | 400 |
| 2255 | Document not compliant | 400 |
| 2256 | Document with missing page | 400 |
| 2301 | Unknown BankAccount id | 400 |
| 2302 | BankAccount invalid status | 400 |
| 2303 | IBAN not SEPA zone | 400 |
| 2304 | IBAN not authorized | 400 |
| 2305 | BIC not SEPA zone | 400 |
| 2306 | BIC not authorized | 400 |
| 2307 | IBAN already exists | 400 |
| 2308 | Maximum number of Bank Accounts reached for the Account | 400 |
| 2309 | IBAN Proof file is missing | 400 |
| 2310 | BankAccount can't be deleted as part of KYC | 400 |
| 2320 | IBAN overused | 400 |
| 2330 | BankAccount VOP check not available | 400 |
| 2331 | BankAccount VOP check IBAN invalid | 400 |
| 2332 | BankAccount VOP check not match | 400 |
| 2351 | Unknown CreditCard id | 400 |
| 2352 | CreditCard invalid status | 400 |
| 2353 | Unknown CreditCard id | 400 |
| 2354 | CreditCard invalid status | 400 |
| 2355 | CreditCard not supported | 400 |
| 2401 | Unknown Transaction id | 400 |
| 2402 | Transaction invalid status | 400 |
| 2403 | Transaction invalid type | 400 |
| 2404 | Transaction invalid payment method | 400 |
| 2405 | Invalid parameters: fees are greater than amount | 400 |
| 2406 | Invalid parameters: fees wallet id is missing | 400 |
| 2407 | Invalid parameters: sender wallet and bank account are not associated to the same account | 400 |
| 2408 | Invalid parameters: transaction partner ref invalid (must be unique) | 400 |
| 2409 | Invalid parameters: sender and receiver are equals | 400 |
| 2410 | Invalid parameters: wallets have incompatible currencies | 400 |
| 2411 | Transaction not allowed type | 400 |
| 2420 | Transaction authorization is timed-out | 400 |
| 2421 | Transaction authorization failure | 400 |
| 2422 | Transaction confirmation failure | 400 |
| 2423 | Transaction cancellation failure | 400 |
| 2424 | Transaction refund failure | 400 |
| 2425 | Transaction refund impossible as it is a REFUND transaction | 400 |
| 2426 | Transaction refund impossible : invalid requested amount or fees | 400 |
| 2427 | Transaction is fully refunded | 400 |
| 2428 | Transaction confirmation failure : the confirmation amount exceed the authorized one | 400 |
| 2429 | Transaction is timed out because payment process not initiated by user | 400 |
| 2430 | Transaction is timed out because 3ds process not completed by user or is failed on PSP side | 400 |
| 2431 | Transaction failed because the 3ds process failed by user | 400 |
| 2432 | Transaction failed (3ds process has succeeded but an error occurred during the final redirection) | 400 |
| 2433 | Transaction rejected | 400 |
| 2434 | Transaction too old to be refunded | 400 |
| 2435 | Transfer not allowed : Account has too low KYC level to transfer to an Account Standard | 400 |
| 2436 | Transfer not allowed : Account has too low KYC level to transfer to Account Business | 400 |
| 2437 | Transaction not validated by end-user | 400 |
| 2451 | Transaction amount cannot be less than '******' | 400 |
| 2452 | Wallet '******' insufficient balance. | 400 |
| 2453 | Transaction amount cannot be greater than '*****' | 400 |
| 2461 | Account has reached is BALANCE MAX limit | 400 |
| 2462 | Account has reached is CASH_IN MONTHLY MAX limit | 400 |
| 2501 | Unknown Wallet Activity id | 400 |
| 2601 | Transaction Bank Account invalid status | 400 |
| 2651 | Transaction Bankwire invalid status | 400 |
| 2652 | The transaction Bankwire payment amount is too high | 400 |
| 2653 | The transaction Bankwire payment amount is too low | 400 |
| 8001 | Invalid Currency Code | 400 |