Getting Started
Decide the payment journeys you need
We have a range of journeys to suit all your customer touchpoints. Use this page to help you understand which journey you need to implement.
Creating your account & adding your business information
To get started with Yaspa you first need to create an account.
Your account manager will be on hand to help, but here’s what you can expect: How do I setup a Yaspa account?.
Account Validation
Before you can process payments with Yaspa, we need to validate your bank account.
See Account Validation for more information.
Once you've setup your account, get in touch to start the account validation process.
Going Live
You can integrate and test in our sandbox (test) environment, which fully replicates the live environment.
Once you are happy with your integration, you can go live simply by changing API keys.
Integrating Pay-Ins
Yaspa lets you take pay-ins from customers, directly from their bank account.
The Yaspa Pay SDK is a few lines of Javascript, called from your pay-in page.
Adding the JS Pay-In SDK to your page
Javascript: Adding the JS Pay-In SDK
<script src="https://sdk.yaspa.com/v6/sdk/sdk-payin.js" data-api-key="[Your-merchant-public-api-key]"></script>
<script src="https://test-sdk.yaspa.com/v6/sdk/sdk-payin.js" data-api-key="[Your-merchant-public-api-key]"></script>
Javascript: Adding the JS Pay-In SDK programmatically
function setupCitizenSdk() {
let scriptTag = document.createElement('script');
scriptTag.src = "https://sdk.yaspa.com/v6/sdk/sdk-payin.js";
scriptTag.dataset.apiKey = "[Your-merchant-public-api-key]"
document.body.appendChild(scriptTag)
}
//Then you can call the function on which point you want to load the sdk
setupCitizenSdk()
function setupCitizenSdk() {
let scriptTag = document.createElement('script');
scriptTag.src = "https://test-sdk.yaspa.com/v6/sdk/sdk-payin.js";
scriptTag.dataset.apiKey = "[Your-merchant-public-api-key]"
document.body.appendChild(scriptTag)
}
//Then you can call the function on which point you want to load the sdk
setupCitizenSdk()
The SDK is a Javascript library that you link to from your page.
You can find your public api key in the dashboard in your merchant information page.
Checking that our SDK has been loaded and is ready to be used
Javascript: Check the readiness of the SDK
window.CITIZEN_PAYIN.ready().then(() => {
//in this point the sdk is ready to be used
})
window.CITIZEN_PAYIN.ready().then(() => {
//in this point the sdk is ready to be used
})
You are able to check if the CITIZEN_PAYIN is ready to be used calling the function .ready()
of the SDK.
This will return a promise
that will be resolved when SDK is ready to be used.
Creating the Pay-In Instruction
Java: Creating a Pay-In Session
public class CitizenTransactionDetails implements Serializable {
// This is just a Java class that represents the json object that you will need to send to the Yaspa backend.
// These are required fields.
private static final long serialVersionUID = 212345678976543210L;
private String paymentGiro; //Either FPS or SEPA
private String customerIdentifier; // The internal id you use on your systems to identity your user
private String customerEmailAddress;
private String amount;
private String currency; // has to be a valid currency ISO code e.g. USD, EUR, GBP
private String reference;
private String description;
private String customerIpAddress;
private String customerDeviceOs;
private String searchableText;
private String payload;
private boolean isPayloadEncrypted;
private List<String> supportedCountries; // has to be an array of valid country ISO codes e.g GB, NL
private String successRedirectUrl;
private String failureRedirectUrl;
private String language;
//Getters and Setters
}
@RestController
@RequestMapping(value = "my-pay-in-endpoint")
public class PayInEndpoints {
//Your backend will then make a request to the Yaspa service to create a transaction.
@RequestMapping(method = RequestMethod.POST, path = "/your-example-pay-in-endpoint")
public Callable<ResponseEntity<TextNode>> createCitizenPayInTransaction(TransactionDetails details) {
CitizenTransactionDetails citizenPayInDetails = new CitizenTransactionDetails();
citizenPayInDetails.setCustomerEmailAddress(DB.getCustomerEmail);//only needed for email journey
citizenPayInDetails.setCustomerIdentifier(DB.getCustomerId);//should be the id of the customer's account on the merchant's internal system.
citizenPayInDetails.setAmount(details.getAmount);
citizenPayInDetails.setCurrency("GBP");
citizenPayInDetails.setPaymentGiro(PaymentGiro.FPS);
citizenPayInDetails.setReference("This is my reference");
citizenPayInDetails.setDescription("This is my description");
citizenPayInDetails.setCustomerIPAddress(details.getIPAddress());
citizenPayInDetails.setCustomerDeviceOs(details.getOS());
citizenPayInDetails.setSearchableText(details.getSearchableText());
citizenPayInDetails.setPayload(details.getPayload());
citizenPayInDetails.setIsPayloadEncrypted(details.getIsPayloadEncrypted());
citizenPayInDetails.setSupportedCountries(DB.getSupportedCountries());
citizenPayInDetails.setSuccessRedirectUrl("<my-success-redirect-url>");
citizenPayInDetails.setFailureRedirectUrl("<my-failure-redirect-url>");
citizenPayInDetails.setBankSuccessRedirectUrl("<my-bank-success-redirect-url>");
citizenPayInDetails.setBankFailureRedirectUrl("<my-bank-failure-redirect-url>");
citizenPayInDetails.setLanguage(details.getLanguage());
RestTemplate restTemplate = new RestTemplate();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("AuthorizationCitizen", [YOUR_MERCHANT_PRIVATE_API_KEY]]);
ResponseEntity<TextNode> payInInitResponse = restTemplate
.exchange("https://api.yaspa.com/v2/payins/session", HttpMethod.POST,
new HttpEntity<>(citizenPayInDetails, httpHeaders), TextNode.class);
String citizenTransactionId = payInInitResponse.getBody().asText();
return ResponseEntity.ok(new TextNode(citizenTransactionId)); //Return this to your front end
}
}
public class CitizenTransactionDetails implements Serializable {
// This is just a Java class that represents the json object that you will need to send to the Yaspa backend.
// These are required fields.
private static final long serialVersionUID = 212345678976543210L;
private String paymentGiro; //Either FPS or SEPA
private String customerEmailAddress;
private String merchantEmailAddress;
private String amount;
private String currency; // has to be a valid currency ISO code e.g. USD, EUR, GBP
private String reference;
private String description;
private String customerIpAddress;
private String customerDeviceOs;
private String searchableText;
private String payload;
private boolean payloadEncrypted;
private List<String> supportedCountries; // has to be an array of valid country ISO codes e.g GB, NL
private String successRedirectUrl;
private String failureRedirectUrl;
private String language;
//Getters and Setters
}
@RestController
@RequestMapping(value = "my-pay-in-endpoint")
public class PayInEndpoints {
//Your backend will then make a request to the Yaspa service to create a transaction.
@RequestMapping(method = RequestMethod.POST, path = "/your-example-pay-in-endpoint")
public Callable<ResponseEntity<TextNode>> createCitizenPayInTransaction(TransactionDetails details) {
CitizenTransactionDetails citizenPayInDetails = new CitizenTransactionDetails();
citizenPayInDetails.setCustomerEmailAddress(DB.getCustomerEmail);//only needed for email journey
citizenPayInDetails.setCustomerIdentifier(DB.getCustomerId);//should be the id of the customer's account on the merchant's internal system.
citizenPayInDetails.setAmount(details.getAmount);
citizenPayInDetails.setCurrency("GBP");
citizenPayInDetails.setPaymentGiro(PaymentGiro.FPS);
citizenPayInDetails.setReference("This is my reference");
citizenPayInDetails.setDescription("This is my description");
citizenPayInDetails.setCustomerIPAddress(details.getIPAddress());
citizenPayInDetails.setCustomerDeviceOs(details.getOS());
citizenPayInDetails.setSearchableText(details.getSearchableText());
citizenPayInDetails.setPayload(details.getPayload());
citizenPayInDetails.setIsPayloadEncrypted(details.getIsPayloadEncrypted());
citizenPayInDetails.setSupportedCountries(DB.getSupportedCountries());
citizenPayInDetails.setSuccessRedirectUrl("<my-success-redirect-url>");
citizenPayInDetails.setFailureRedirectUrl("<my-failure-redirect-url>");
citizenPayInDetails.setBankSuccessRedirectUrl("<my-bank-success-redirect-url>");
citizenPayInDetails.setBankFailureRedirectUrl("<my-bank-failure-redirect-url>");
citizenPayInDetails.setLanguage(details.getLanguage());
RestTemplate restTemplate = new RestTemplate();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("AuthorizationCitizen", [YOUR_MERCHANT_PRIVATE_API_KEY]]);
ResponseEntity<TextNode> payInInitResponse = restTemplate
.exchange("https://testapi.yaspa.com/v2/payins/session", HttpMethod.POST,
new HttpEntity<>(citizenPayInDetails, httpHeaders), TextNode.class);
String citizenTransactionId = payInInitResponse.getBody().asText();
return ResponseEntity.ok(new TextNode(citizenTransactionId)); //Return this to your front end
}
}
Setting up a pay-in in your backend is simple, and requires a number of fields set.
Parameter | Description | Type | Required |
---|---|---|---|
customerIdentifier | The internal id you use on your systems to identity your user | string | Y |
customerEmailAddress | The email of the paying customer. Only needed for email journey | string | N |
paymentGiro | payment type (SEPA or FPS) | string | Y |
amount | decimal value of the payment | string with valid 2 decimal number format | Y |
currency | currency | string with valid ISO currency code | Y |
reference | payment reference shown to the customer. Needs to be alphanumeric and 15 chars max. This MUST be unique | string | Y |
description | description shown to the customer | string | N |
customerIpAddress | IP for the paying customer | string with valid IPv4 or IPv6 format | Y |
customerDeviceOs | OS for the paying customer | string | Y |
searchableText | searchable string | string | N |
payload | meta-data of the payment | string | N |
isPayloadEncrypted | encrypt payload field (true/false) | boolean | N |
supportedCountries | filter the bank list in bank selection page | array of string country ISO codes | N |
successRedirectUrl | Url that the user is redirected to from the modal on completion of a successful journey | string | N |
failureRedirectUrl | Url that the user is redirected to from the modal when closing the modal or on a failed payment | string | N |
successBankRedirectUrl | Url that the user is redirected to from their bank app on a successful approval | string | N |
failureBankRedirectUrl | Url that the user is redirected to from their bank app on a cancelled/failed request | string | N |
language | The language that will be used to translate the journey | string of language ISO-639-1 code. Default value 'en' | N |
Starting the Pay-In Journey
Javascript: Starting the Email Pay-In Journey
<script>
// citizenTransactionId - from the previous step
// options - an object that can contain the following fields:
// 1. customerEmailAddress - the email of the user, it used to show the user on which email the email has sent
// 2. initiatedCallback - a callback that is triggered when the background work is done and the modal is shown.
// Used mostly to handle the loading state of the host page. If non is passed, the loading state is handled from the modal
//
// e.g. const options = {
// customerEmailAddress: "yourCustomerEmail@gmail.com",
// initiatedCallback: function(){console.log("This function called when the modal is about to open")}
// }
let sendPayIn = function (citizenTransactionId, options) {
window.CITIZEN_PAYIN.startEmailPayInJourney(citizenTransactionId, options);
}
</script>
Once you have the citizenTransactionId, you can start the pay-in journey modal.
Available Parameters
Parameter | Description | Type | Required |
---|---|---|---|
citizenTransactionId | string of the transaction ID generated from previous step | String | Y |
options | Options that are used for a better user experience. Available options : 1. customerEmailAddress - the user email that used to create the session, it used to show the user in which email the link is send 2. initiatedCallback - a callback that is triggered when the modal is ready to start the journey |
Object | N |
Starting the Pay-In Journey (Direct Pay-Ins)
You may not want the user to be sent an email to begin their pay-in journey. For this, we offer a way to start the
journey on the current page.
This call will redirect the user from the current page to a consent page with the details of the journey.
Javascript: Starting the Pay-In Journey
<script>
// citizenTransactionId - from the previous step
let sendPayIn = function (citizenTransactionId) {
window.CITIZEN_PAYIN.startPayInJourney(citizenTransactionId);
}
</script>
Once you have the citizenTransactionId, you can start the pay-in journey.
Starting the QR code Pay-In Journey
You may not want the user to be sent an email to begin their pay-in journey. For this, we offer a way to show to the user
a QR code, where he will be able to scan it and continue the journey on his device.
Javascript: Starting the QR code Pay-In Journey
<script>
// citizenTransactionId - from the previous step
let sendQRCodePayIn = function (citizenTransactionId) {
window.CITIZEN_PAYIN.startQRCodePayInJourney(citizenTransactionId);
}
</script>
Once you have the citizenTransactionId, you can start the pay-in journey.
Customising the Pay-In journey
Yaspa offers a range of options to suit your own pay-in screen, and optimise for customer conversion.
Embedded
You can use our customisable widget to easily add Yaspa pay-ins directly to the pay-in page. This works best when you have a dedicated pay-ins page with space to set customer expectations (key for conversion)
Modal
This method takes the customisable widget and puts it in a modal which will open with the explanatory information when the pay button is clicked. This is best when you have less space available on your page.
Window
The new window option is best for mobile applications. This takes the pay-in experience and hosts it in a new window away from the application when they pay button is clicked. This means there is no need for separate android, iOS or web app integrations.
Custom
Of course - you can always start from scratch and build something unique to your site. We’ll always be on hand to help advise on best practices and share learnings from our own user research.
You can customise your own widget here.
Adding Pay-In component to your page
Javascript: Adding the Pay-In component
<script src="https://sdk.yaspa.com/component/v3/citizen-pay-component.js"></script>
// This is where the pay-in component javascript will be loaded.
// In case of standalone, this is where the component will be shown.
<div id="citizen-pay-component"></div>
<script src="https://test-sdk.yaspa.com/component/v3/citizen-pay-component.js"></script>
// This is where the pay-in component javascript will be loaded.
// In case of standalone, this is where the component will be shown.
<div id="citizen-pay-component"></div>
The Pay-In component is a Javascript library that you link to from your page. You will need to add a div to host the component.
Implement Pay-In Component
Javascript: Initialising pay-in component
<script>
window.citizenAsyncInit = function () {
window.CITIZEN_PAY_COMPONENT.init({
paymentDetails: {
publicApiKey: 'your merchant public api key',
amountToShow: 'amount that will shown to the button. If left blank, a text placeholder will replace it',
currencyToShow: 'currency symbol that will shown to the button. If left blank, a text placeholder will replace it',
},
theme: 'screen theme, posible values light, dark. Default value light',
paymentType: 'the type of the journey, possible values no-email, email. Default value email.',
mode: 'type of the screen. Possible values standalone, modal, windowed. Default value standalone.'
style: 'styles that are passed to style the component.'
})
};
</script>
You initialise the pay-in component with just your merchant public API key and the transaction id.
You can find your public api key the dashboard in your merchant information page and you can generate the transaction id following this step
The transaction id should be passed into the component via the startPayInJourney function. In case of modal and windowed mode, the function startPayInJourney it will open the modal, or the window that will contain the component.
Parameter | Description | Type | Required |
---|---|---|---|
publicApiKey | your merchant public api key | string | Y |
paymentType | the type of the journey, possible values no-email, email. | string | Y |
amountToShow | The amount that will shown to the button. If left blank, a text placeholder will replace it | string with valid number format | N |
currencyToShow | The currency symbol that will shown to the button. If left blank, a text placeholder will replace it | string with valid ISO currency code | N |
theme | screen theme, posible values light, dark. Default value light | string | N |
mode | type of the screen. Possible values standalone, modal and windowed. Default value standalone. | string | N |
style | styles that are passed to style the component. | object | N |
Javascript: Setting the citizenTransactionId into component.
<script>
const openPayInComponent = (citizenTransactionId, customerEmalAddress) => {
window.CITIZEN_PAY_COMPONENT.startPayInJourney(citizenTransactionId, customerEmalAddress)
}
</script>
startPayInJourney Parameters
Parameter | Description | Type | Required |
---|---|---|---|
citizenTransactionId | The transaction id is generated on this step. | string | Y |
customerEmailAddress | your customer email, this is for visual only, and it will be used only on email payment journey | string | N |
Possible style parameters
All the sections parameters can have their styles changed for attributes fontFamily, backgroundColor and color. e.g. container: { backgroundColor: "white", color: "black" fontFamily: "Roboto" }
Parameter | Description | Type |
---|---|---|
container | the container that contains all the elements | object |
title | the title that contains the text "Pay direct from your bank" | object |
description | the text that has the three ticks | object |
steps | the container of the 2 steps icons | object |
actionText | the text above the button | object |
button | the button on the bottom. | object |
Redirects from banks
Once a user has completed the authorisation of a pay-in within their banking app we allow you to customise where the customer is redirected to. You can assign unique redirects for both a successful and failure journeys.
You can set these redirect in your admin dashboard under your merchant details.
Pay-In Webhooks
You can receive real time pay-in status updates via webhooks.
Configuring the webhooks you receive can be done in your merchant dashboard.
See here for webhook JSON structure & composition.
Viewing Pay-Ins
We provide all customers with access to their own Yaspa dashboard where they can see pay-in summaries and search for pay-ins.
You also have the option of displaying this data to your own systems using our Pay-In API.
Going Live with Payments
Providing 5AMLD KYC
Yaspa is an authorised payment institute, regulated by the UK Financial Conduct Authority.
We are required to check all of our merchants under the 5AMLD before you can receive payments.
We have made this simple for you; simply follow the instructions here once you have created your entity account.
Testing Payments
You can test payments using the Yaspa test bank on our test platform.
Additionally, you can use a live bank to send a 10p donation to charity using our receiving charity bank account.
Updating your receiving bank
Once we have validated your KYC information, you will be required to validate your bank account information. You can do this in two ways:
- Calling us and providing your entity’s API key and banking information
- Granting a AHC token using the Yaspa mobile app to your admin email
In both cases we will need to see a copy bank statement which confirms your entity’s legal name prior to go-live.
Integrating Accountholder Verification
Yaspa lets you confirm bank account holder information from customers. (this is often referered to as AIS, Account Information Services, in Open Banking).
The Yaspa Accountholder Verification SDK is a few lines of Javascript, called from your customer verification/onboarding page.
Adding the JS Accountholder Verification SDK to your page
Javascript: Adding the JS Accountholder Verification SDK
<script src="https://sdk.yaspa.com/v6/sdk/sdk-account-verification.js" data-api-key="[Your-merchant-public-api-key]"></script>
<script src="https://test-sdk.yaspa.com/v6/sdk/sdk-account-verification.js" data-api-key="[Your-merchant-public-api-key]"></script>
Javascript: Adding the JS account verification SDK programmatically
function setupCitizenSdk() {
let scriptTag = document.createElement('script');
scriptTag.src = "https://sdk.yaspa.com/v6/sdk/sdk-account-verification.js";
scriptTag.dataset.apiKey = "[Your-merchant-public-api-key]"
document.body.appendChild(scriptTag)
}
//Then you can call the function on which point you want to load the sdk
setupCitizenSdk()
function setupCitizenSdk() {
let scriptTag = document.createElement('script');
scriptTag.src = "https://test-sdk.yaspa.com/v6/sdk/sdk-account-verification.js";
scriptTag.dataset.apiKey = "[Your-merchant-public-api-key]"
document.body.appendChild(scriptTag)
}
//Then you can call the function on which point you want to load the sdk
setupCitizenSdk()
The SDK is a Javascript library that you link to from your page
You can find your public api key in the dashboard in your merchant information page.
Checking that our SDK has been loaded and is ready to be used
Javascript: Check the readiness of the SDK
window.CITIZEN_ACCOUNT_VERIFICATION.ready().then(() => {
//in this point the sdk is ready to be used
})
window.CITIZEN_ACCOUNT_VERIFICATION.ready().then(() => {
//in this point the sdk is ready to be used
})
You are able to check if the CITIZEN_ACCOUNT_VERIFICATION is ready to be used calling the function .ready()
of the SDK.
This will return a promise
that will be resolved when SDK is ready to be used.
Initialising the Accountholder Verification SDK
Javascript: Initialising the JS Accountholder Verification SDK
<script>
window.citizenAsyncInit = function () {
CITIZEN_ACCOUNT_VERIFICATION.init({
publicApiKey: '[Your-entity-public-api-key]'
})
};
</script>
You initialise the Accountholder Verification SDK with your entity public API key:
You can find your public api key the dashboard in your company information page.
Creating the Accountholder Verification Instruction
Java: Creating an Accountholder Verification Session
public class AHCTransactionDetails implements Serializable {
// This is just a Java class that represents the json object that you will need to send to the Yaspa backend.
// These are required fields.
private String customerEmailAddress;
private String getScopes;
private String getMerchantId;
private String searchableText;
private String payload;
private boolean payloadEncrypted;
private List<String> supportedCountries; //(Optional) has to be an array of valid country ISO codes e.g GB, NL
private String successRedirectUrl;
private String failureRedirectUrl;
//Getters and Setters
}
@RestController
@RequestMapping(value = "my-ahc-endpoint")
public class AHCEndpoints {
//Your backend will then make a request to the Yaspa service to create a transaction.
@RequestMapping(method = RequestMethod.POST, path = "/your-example-payment-endpoint")
public Callable<ResponseEntity<TextNode>> createCitizenAHCTransaction(AHCTransactionDetails details) {
AHCTransactionDetails aisDetails = new AHCTransactionDetails();
aisDetails.setCustomerEmailAddress(DB.getCustomerEmail);//only needed for email journey
aisDetails.setCustomerIdentifier(details.getMerchantId);//should be the id of the merchants's account.
aisDetails.setScopes(details.getScopes());
aisDetails.setMerchantId(details.getMerchantId());
aisDetails.setSearchableText(details.getSearchableText());
aisDetails.setPayload(details.getPayload());
aisDetails.setPayloadEncrypted(details.getPayloadEncrypted());
aisDetails.setSupportedCountries(DB.getSupportedCountries());
aisDetails.setSuccessRedirectUrl("<my-success-redirect-url>");
aisDetails.setFailureRedirectUrl("<my-failure-redirect-url>");
aisDetails.setBankSuccessRedirectUrl("<my-bank-success-redirect-url>");
aisDetails.setBankFailureRedirectUrl("<my-bank-failure-redirect-url>");
aisDetails.setLanguage(details.getLanguage());
RestTemplate restTemplate = new RestTemplate();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("AuthorizationCitizen", [YOUR_ENTITY_API_KEY]]);
ResponseEntity<TextNode> AHCInitResponse = restTemplate
.exchange("https://api.yaspa.com/v2/account-verification/session", HttpMethod.POST,
new HttpEntity<>(aisDetails, httpHeaders), TextNode.class);
String citizenAHCTransactionId = AHCInitResponse.getBody().asText();
return ResponseEntity.ok(new TextNode(citizenAHCTransactionId)); //Return this to your front end
}
}
public class AHCTransactionDetails implements Serializable {
// This is just a Java class that represents the json object that you will need to send to the Yaspa backend.
// These are required fields.
private static final long serialVersionUID = 212345678976543210L;
private String customerEmailAddress;
private String getScopes;
private String getMerchantId;
private String searchableText;
private String payload;
private boolean payloadEncrypted;
private List<String> supportedCountries; //(Optional) has to be an array of valid country ISO codes e.g GB, NL
private String successRedirectUrl;
private String failureRedirectUrl;
//Getters and Setters
}
@RestController
@RequestMapping(value = "my-ahc-endpoint")
public class AHCEndpoints {
//Your backend will then make a request to the Yaspa service to create a transaction.
@RequestMapping(method = RequestMethod.POST, path = "/your-example-payment-endpoint")
public Callable<ResponseEntity<TextNode>> createCitizenAHCTransaction(AHCTransactionDetails details) {
AHCTransactionDetails aisDetails = new AHCTransactionDetails();
aisDetails.setCustomerEmailAddress(DB.getCustomerEmail);//only needed for email journey
aisDetails.setCustomerIdentifier(details.getMerchantId);//should be the id of the merchants's account.
aisDetails.setScopes(details.getScopes());
aisDetails.setMerchantId(details.getMerchantId());
aisDetails.setSearchableText(details.getSearchableText());
aisDetails.setPayload(details.getPayload());
aisDetails.setPayloadEncrypted(details.getPayloadEncrypted());
aisDetails.setSupportedCountries(DB.getSupportedCountries());
aisDetails.setSuccessRedirectUrl("<my-success-redirect-url>");
aisDetails.setFailureRedirectUrl("<my-failure-redirect-url>");
aisDetails.setBankSuccessRedirectUrl("<my-bank-success-redirect-url>");
aisDetails.setBankFailureRedirectUrl("<my-bank-failure-redirect-url>");
aisDetails.setLanguage(details.getLanguage());
RestTemplate restTemplate = new RestTemplate();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("AuthorizationCitizen", [YOUR_ENTITY_API_KEY]]);
ResponseEntity<TextNode> AHCInitResponse = restTemplate
.exchange("https://testapi.yaspa.com/v2/account-verification/session", HttpMethod.POST,
new HttpEntity<>(aisDetails, httpHeaders), TextNode.class);
String citizenAHCTransactionId = AHCInitResponse.getBody().asText();
return ResponseEntity.ok(new TextNode(citizenAHCTransactionId)); //Return this to your front end
}
}
You can use scopes to set what information you want from the account:
- account_details - just the account information
- transactions_details - just the transaction information
Parameter | Description | Type | Required |
---|---|---|---|
merchantId | Your merchant ID. This can be obtained from your admin dashboard | string | Y |
customerIdentifier | Used to identify the customer whose bank account details to fetch | string | Y |
customerEmailAddress | Email address if using the email journey | string | N |
scopes | the account information that the user will provide to you | array of 'account_details', 'transactions_details' values | Y |
searchableText | searchable string | string | N |
payload | meta-data of the request | string | N |
payloadEncrypted | encrypt payload field (true/false) | boolean | N |
supportedCountries | filter the bank list in bank selection page | array of string country ISO codes | N |
successRedirectUrl | Url that the user is redirected to from the modal on completion of a successful journey | string | N |
failureRedirectUrl | Url that the user is redirected to from the modal when closing the modal or on a failed request | string | N |
successBankRedirectUrl | Url that the user is redirected to from their bank app on a successful approval | string | N |
failureBankRedirectUrl | Url that the user is redirected to from their bank app on a cancelled/failed request | string | N |
language | The language that will be used to translate the journey | string of language ISO-639-1 code. Default value 'en' | N |
Starting the Accountholder Verification Journey (Direct Verification)
Javascript: Starting the Accountholder Verification Journey
<script>
// transactionId - from the previous step
let sendAHCRequest = function (transactionId) {
window.CITIZEN_ACCOUNT_VERIFICATION.startAccountVerificationJourney(transactionId);
}
</script>
Once you have the transaction ID, you can start the accountholder verification journey.
This call will redirect the user from the current page to a consent page with the details of the journey.
Accountholder Verification Webhooks
You can receive real time payment status updates via webhooks.
Configuring the webhooks you receive can be done in your merchant dashboard.
See here for webhook JSON structure & composition.
Viewing Accountholder Verification
We provide all customers with access to their own Yaspa dashboard where they can see account verification.
You also have the option of displaying this data to your own systems using our Accountholder Verification API.
Integrating Verified Pay-Ins
Yaspa lets you take pay-ins from customers after they verify the bank account, directly from the verified bank account.
The Yaspa Pay SDK is a few lines of Javascript, called from your pay-ins page.
Adding the JS Verified Pay-In SDK to your page
Javascript: Adding the JS Verified Pay-In SDK
<script src="https://sdk.yaspa.com/v6/sdk/sdk-verified-payin.js" data-api-key="[Your-merchant-public-api-key]"></script>
<script src="https://test-sdk.yaspa.com/v6/sdk/sdk-verified-payin.js" data-api-key="[Your-merchant-public-api-key]"></script>
Javascript: Adding the JS Verified Pay-In SDK programmatically
function setupCitizenSdk() {
let scriptTag = document.createElement('script');
scriptTag.src = "https://sdk.yaspa.com/v6/sdk/sdk-verified-payin.js";
scriptTag.dataset.apiKey = "[Your-merchant-public-api-key]"
document.body.appendChild(scriptTag)
}
//Then you can call the function on which point you want to load the sdk
setupCitizenSdk()
function setupCitizenSdk() {
let scriptTag = document.createElement('script');
scriptTag.src = "https://test-sdk.yaspa.com/v6/sdk/sdk-verified-payin.js";
scriptTag.dataset.apiKey = "[Your-merchant-public-api-key]"
document.body.appendChild(scriptTag)
}
//Then you can call the function on which point you want to load the sdk
setupCitizenSdk()
The SDK is a Javascript library that you link to from your page
You can find your public api key in the dashboard in your merchant information page.
Checking that our SDK has been loaded and is ready to be used
Javascript: Check the readiness of the SDK
window.CITIZEN_VERIFIED_PAYIN.ready().then(() => {
//in this point the sdk is ready to be used
})
window.CITIZEN_VERIFIED_PAYIN.ready().then(() => {
//in this point the sdk is ready to be used
})
You are able to check if the CITIZEN_VERIFIED_PAYIN is ready to be used calling the function .ready()
of the SDK.
This will return a promise
that will be resolved when SDK is ready to be used.
Creating the Verified Pay-In Instruction
Java: Creating a Verified Pay-In Session
public class CitizenTransactionDetails implements Serializable {
// This is just a Java class that represents the json object that you will need to send to the Yaspa backend.
// These are required fields.
private static final long serialVersionUID = 212345678976543210L;
private String paymentGiro; //Either FPS or SEPA
private String customerIdentifier; // The internal id you use on your systems to identity your user
private String customerEmailAddress;
private String amount;
private String currency; // has to be a valid currency ISO code e.g. USD, EUR, GBP
private String reference;
private String description;
private String customerIpAddress;
private String customerDeviceOs;
private String searchableText;
private String payload;
private boolean isPayloadEncrypted;
private List<String> supportedCountries; // has to be an array of valid country ISO codes e.g GB, NL
private String successRedirectUrl;
private String failureRedirectUrl;
private Boolean disableAddingNewBanks;
private String language;
//Getters and Setters
}
@RestController
@RequestMapping(value = "my-verified-pay-in-endpoint")
public class PayInEndpoints {
//Your backend will then make a request to the Yaspa service to create a transaction.
@RequestMapping(method = RequestMethod.POST, path = "/your-example-verified-pay-in-endpoint")
public Callable<ResponseEntity<TextNode>> createCitizenPayInTransaction(TransactionDetails details) {
CitizenTransactionDetails citizenPayInDetails = new CitizenTransactionDetails();
citizenPayInDetails.setCustomerEmailAddress(DB.getCustomerEmail);//only needed for email journey
citizenPayInDetails.setCustomerIdentifier(DB.getCustomerId);//should be the id of the customer's account on the merchant's internal system.
citizenPayInDetails.setAmount(details.getAmount);
citizenPayInDetails.setCurrency("GBP");
citizenPayInDetails.setPaymentGiro(PaymentGiro.FPS);
citizenPayInDetails.setReference("This is my reference");
citizenPayInDetails.setDescription("This is my description");
citizenPayInDetails.setCustomerIpAddress(details.getCustomerIpAddress());
citizenPayInDetails.setCustomerDeviceOs(details.getCustomerDeviceOs());
citizenPayInDetails.setSearchableText(details.getSearchableText());
citizenPayInDetails.setPayload(details.getPayload());
citizenPayInDetails.setIsPayloadEncrypted(details.getIsPayloadEncrypted());
citizenPayInDetails.setDisableAddingNewBanks(details.getDisableAddingNewBanks());
citizenPayInDetails.setSupportedCountries(DB.getSupportedCountries());
citizenPayInDetails.setSuccessRedirectUrl("<my-success-redirect-url>");
citizenPayInDetails.setFailureRedirectUrl("<my-failure-redirect-url>");
citizenPayInDetails.setBankSuccessRedirectUrl("<my-bank-success-redirect-url>");
citizenPayInDetails.setBankFailureRedirectUrl("<my-bank-failure-redirect-url>");
citizenPayInDetails.setLanguage(details.getLanguage());
RestTemplate restTemplate = new RestTemplate();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("AuthorizationCitizen", [YOUR_MERCHANT_PRIVATE_API_KEY]]);
ResponseEntity<TextNode> payInInitResponse = restTemplate
.exchange("https://api.yaspa.com/v2/payins/verified/session", HttpMethod.POST,
new HttpEntity<>(citizenPayInDetails, httpHeaders), TextNode.class);
String citizenTransactionId = payInInitResponse.getBody().asText();
return ResponseEntity.ok(new TextNode(citizenTransactionId)); //Return this to your front end
}
}
public class CitizenTransactionDetails implements Serializable {
// This is just a Java class that represents the json object that you will need to send to the Yaspa backend.
// These are required fields.
private static final long serialVersionUID = 212345678976543210L;
private String paymentGiro; //Either FPS or SEPA
private String customerIdentifier; // The internal id you use on your systems to identity your user
private String customerEmailAddress;
private String amount;
private String currency; // has to be a valid currency ISO code e.g. USD, EUR, GBP
private String reference;
private String description;
private String customerIpAddress;
private String customerDeviceOs;
private String searchableText;
private String payload;
private boolean isPayloadEncrypted;
private List<String> supportedCountries; // has to be an array of valid country ISO codes e.g GB, NL
private String successRedirectUrl;
private String failureRedirectUrl;
private Boolean disableAddingNewBanks;
private String language;
//Getters and Setters
}
@RestController
@RequestMapping(value = "my-verified-pay-in-endpoint")
public class PayInEndpoints {
//Your backend will then make a request to the Yaspa service to create a transaction.
@RequestMapping(method = RequestMethod.POST, path = "/your-example-verified-pay-in-endpoint")
public Callable<ResponseEntity<TextNode>> createCitizenPayInTransaction(TransactionDetails details) {
CitizenTransactionDetails citizenPayInDetails = new CitizenTransactionDetails();
citizenPayInDetails.setCustomerEmailAddress(DB.getCustomerEmail);//only needed for email journey
citizenPayInDetails.setCustomerIdentifier(DB.getCustomerId);//should be the id of the customer's account on the merchant's internal system.
citizenPayInDetails.setAmount(details.getAmount);
citizenPayInDetails.setCurrency("GBP");
citizenPayInDetails.setPaymentGiro(PaymentGiro.FPS);
citizenPayInDetails.setReference("This is my reference");
citizenPayInDetails.setDescription("This is my description");
citizenPayInDetails.setCustomerIpAddress(details.getCustomerIpAddress());
citizenPayInDetails.setCustomerDeviceOs(details.getCustomerDeviceOs());
citizenPayInDetails.setSearchableText(details.getSearchableText());
citizenPayInDetails.setPayload(details.getPayload());
citizenPayInDetails.setIsPayloadEncrypted(details.getIsPayloadEncrypted());
citizenPayInDetails.setDisableAddingNewBanks(details.getDisableAddingNewBanks());
citizenPayInDetails.setSupportedCountries(DB.getSupportedCountries());
citizenPayInDetails.setSuccessRedirectUrl("<my-success-redirect-url>");
citizenPayInDetails.setFailureRedirectUrl("<my-failure-redirect-url>");
citizenPayInDetails.setBankSuccessRedirectUrl("<my-bank-success-redirect-url>");
citizenPayInDetails.setBankFailureRedirectUrl("<my-bank-failure-redirect-url>");
citizenPayInDetails.setLanguage(details.getLanguage());
RestTemplate restTemplate = new RestTemplate();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("AuthorizationCitizen", [YOUR_MERCHANT_PRIVATE_API_KEY]]);
ResponseEntity<TextNode> payInInitResponse = restTemplate
.exchange("https://testapi.yaspa.com/v2/payins/verified/session", HttpMethod.POST,
new HttpEntity<>(citizenPayInDetails, httpHeaders), TextNode.class);
String citizenTransactionId = payInInitResponse.getBody().asText();
return ResponseEntity.ok(new TextNode(citizenTransactionId)); //Return this to your front end
}
}
Setting up a verified pay-in in your backend is simple, and requires a number of fields set.
Parameter | Description | Type | Required |
---|---|---|---|
customerIdentifier | The internal id you use on your systems to identity your user | string | Y |
customerEmailAddress | The email of the paying customer. Only needed for email journey | string | N |
paymentGiro | payment type (SEPA or FPS) | string | Y |
amount | decimal value of the payment | string with valid 2 decimal number format | Y |
currency | currency | string with valid ISO currency code | Y |
reference | payment reference shown to the customer. Needs to be alphanumeric and 15 chars max. This MUST be unique | string | Y |
description | description shown to the customer | string | N |
customerIpAddress | IP for the paying customer | string with valid IPv4 or IPv6 format | Y |
customerDeviceOs | OS for the paying customer | string | Y |
searchableText | searchable string | string | N |
payload | meta-data of the payment | string | N |
isPayloadEncrypted | encrypt payload field (true/false) | boolean | N |
supportedCountries | filter the bank list in bank selection page | array of string country ISO codes | N |
successRedirectUrl | It redirect the page that the modal is shown in completion of the journey | string | N |
failureRedirectUrl | It redirect the page that the modal is shown in case of closing the modal on failed status | string | N |
successBankRedirectUrl | Url that the user is redirected to from their bank app on a successful approval | string | N |
failureBankRedirectUrl | Url that the user is redirected to from their bank app on a cancelled/failed request | string | N |
disableAddingNewBanks | Prevents user from removing existing bank accounts or adding new ones | boolean | N |
language | The language that will be used to translate the journey | string of language ISO-639-1 code. Default value 'en' | N |
Starting the No Email Verified Pay-In Journey (Direct Verified Pay-Ins)
You may not want the user to be sent an email to begin their verified pay-in journey. For this, we offer a way to start the journey on the current page.
This call will redirect the user from the current page to a consent page with the details of the journey.
Javascript: Starting the Verified Pay-In Journey
<script>
// citizenTransactionId - from the previous step
let sendVerifiedPayIn = function (citizenTransactionId) {
window.CITIZEN_VERIFIED_PAYIN.startVerifiedPayInJourney(citizenTransactionId);
}
</script>
Once you have the citizenTransactionId, you can start the verified pay-in journey.
Starting the QR code Verified Pay-In Journey
You may not want the user to be sent an email to begin their verified pay-in journey. For this, we offer a way to show to the user
a QR code, where he will be able to scan it and continue the journey on his device.
Javascript: Starting the QR code Verified Pay-In Journey
<script>
// citizenTransactionId - from the previous step
// options - an object that can contain the following optional fields:
// 1. initiatedCallback - a callback that is triggered when the background work is done and the modal is shown.
// Used mostly to handle the loading state of the host page. If non is passed, the loading state is handled from the modal
//
// e.g. const options = {
// initiatedCallback: function(){console.log("This function called when the modal is about to open")}
// }
let sendQrVerifiedPayIn = function (citizenTransactionId) {
window.CITIZEN_VERIFIED_PAYIN.startQRCodeVerifiedPayInJourney(citizenTransactionId, options);
}
</script>
Once you have the citizenTransactionId, you can start the QR code verified pay-in journey.
Integrating Verified Payouts
Yaspa lets you handle payouts to your customers after they have verified the bank account to which they wish to receive money. Before payouts can be enabled a RSA public key needs to be registered with Yaspa which is used to verify signed payout requests. Payouts are handled with the following calls:
A signed request is sent from your back end to Yaspa
This call initiates the payout and creates a temporary payout session.
A JavaScript SDK call is made from your front end to start the payout journey for your customer.
This call redirects your customer to their bank to confirm their bank account and then completes the payout. A permanent record of the payout is kept after this call.
If back office confirmation is needed before transferring money to a customer then a queued payout can be created. A queued payouts are handled as follows:
A signed request is sent from your back end to Yaspa
This call initiates the payout and creates a temporary payout session. The request body should have the
queue
parameter set.A JavaScript SDK call is made from your front end to start the payout journey for your customer.
This call redirects your customer to their bank to confirm their bank account but does not complete the payout.
The payout is confirmed or rejected on your merchant dashboard.
If the payout is confirmed then money is transaferred to your customer's confirmed bank account. Otherwise the payout is marked as rejected and no further action is taken.
Public Key Registration
For our system to be able to verify your payout requests, the public component of the openssl RSA key pair is required. This key is used to sign the requests for the payouts and is registered on our system through the admin dashboard.
Create a Public/Private Key Pair
Bash: Generate private key
openssl genpkey -algorithm RSA -outform PEM -out private_key.pem -pkeyopt rsa_keygen_bits:2048
A prerequisite for signing any request is to generate an RSA 2048 bit keypair using OpenSSL.
By executing the first block, a 2048 bit RSA key named private_key.pem
is generated, which will be the private key.
Bash: Generate public key
openssl rsa -in private_key.pem -pubout -out public_key.pub
The second step is generating a public key based on the private key. This can be easily done by executing the second block of code, which will generate a public key named public_key.pub
Request Authorisation Token
An authorisation token will be provided by Yaspa for the merchant to be able to start the payout journey. When the token is provided to you, you can submit it on the admin dashboard under the payout section.
Register Google authenticator
Once the token has been entered, you will need to setup Google authenticator to make sure the key cannot be easily changed.
Register Public component
Once Google Authenticator has been setup, you can register the public key from your RSA key pair that you will use to sign requests.
No Authorisation token
If there isn't any authorisation token registered for your entity, you need to ask for one from Yaspa and try again after receiving it.
Creating the Verified Payout Instruction
Java: Creating a Verified Payout Session
public class CitizenTransactionDetails implements Serializable {
// This is just a Java class that represents the json object that you will need to send to the Yaspa backend.
// These are required fields.
private static final long serialVersionUID = 212345678976543210L;
private String paymentGiro; //Either FPS or SEPA
private String customerEmailAddress;
private String merchantEmailAddress;
private String merchantId;
private String amount;
private String currency; // has to be a valid currency ISO code e.g. USD, EUR, GBP
private String reference;
private String merchantBankCode;
private String merchantAccountNumber;
private String customerIpAddress;
private String customerDeviceOs;
private List<String> supportedCountries; // has to be an array of valid country ISO codes e.g GB, NL
private String successRedirectUrl;
private String failureRedirectUrl;
private boolean queue;
private String heldReason;
private Boolean disableAddingNewBanks;
private String language;
//Getters and Setters
}
@RestController
@RequestMapping(value = "my-payments-endpoint")
public class PaymentEndpoints {
//Your backend will then make a request to the Yaspa service to create a transaction.
@RequestMapping(method = RequestMethod.POST, path = "/your-example-payment-endpoint")
public Callable<ResponseEntity<TextNode>> createCitizenPaymentTransaction(TransactionDetails details) {
CitizenTransactionDetails citizenPayoutDetails = new CitizenTransactionDetails();
citizenPayoutDetails.setCustomerEmailAddress(DB.getCustomerEmail());//only needed for email journey
citizenPayoutDetails.setMerchantId(details.getMerchantId());
citizenPayoutDetails.setAmount(details.getAmount());
citizenPayoutDetails.setCurrency("GBP");
citizenPayoutDetails.setPaymentGiro(PaymentGiro.FPS);
citizenPayoutDetails.setReference("MyShortReference123");
citizenPayoutDetails.setCustomerIpAddress(details.getCustomerIpAddress());
citizenPayoutDetails.setCustomerDeviceOs(details.getCustomerDeviceOs());
citizenPayoutDetails.setSupportedCountries(DB.getSupportedCountries());
citizenPayoutDetails.setSuccessRedirectUrl("<my-success-redirect-url>");
citizenPayoutDetails.setFailureRedirectUrl("<my-failure-redirect-url>");
citizenPayoutDetails.setQueue(DB.shouldPayoutQueued());
citizenPayoutDetails.setHeldReason(DB.getHeldReason());
citizenPayoutDetails.setDisableAddingNewBanks(details.getDisableAddingNewBanks());
citizenPayoutDetails.setBankSuccessRedirectUrl("<my-bank-success-redirect-url>");
citizenPayoutDetails.setBankFailureRedirectUrl("<my-bank-failure-redirect-url>");
citizenPayoutDetails.setLanguage(details.getLanguage());
RestTemplate restTemplate = new RestTemplate();
String citizenVerifiedPayoutUrl = "https://api.yaspa.com/v2/payouts/verified/session";
HttpHeaders httpHeaders = generateHeadersForSignedRequest(HttpMethod.POST,
citizenVerifiedPayoutUrl,
citizenPayoutDetails,
DB.getPrivateKey);
httpHeaders.set("AuthorizationCitizen", [YOUR_ENTITY_API_KEY]]);
ResponseEntity<TextNode> payoutInitResponse = restTemplate
.exchange(citizenVerifiedPayoutUrl, HttpMethod.POST,
new HttpEntity<>(citizenPayoutDetails, httpHeaders), TextNode.class);
String citizenPayoutTransactionId = payoutInitResponse.getBody().asText();
return ResponseEntity.ok(new TextNode(citizenPayoutTransactionId)); //Return this to your front end
}
}
private HttpHeaders generateHeadersForSignedRequest (
HttpMethod httpMethod, String url, Object requestBody, PrivateKey privateKey)
throws JsonProcessingException, SignatureException {
String requestExpiryTime = String.valueOf(Instant.now().getEpochSecond() + 300);
String textToSign = requestExpiryTime + "|" + httpMethod.name().toUpperCase() + "|" + url + "|";
if (requestBody != null) {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
ObjectWriter objectWriter = objectMapper.writer();
String requestJson = objectWriter.writeValueAsString(requestBody);
textToSign += requestJson;
}
String signature = generateSignature(textToSign, privateKey);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("Signature", signature);
httpHeaders.set("Expires-at", requestExpiryTime);
return httpHeaders;
}
private String generateSignature(String plainText, PrivateKey privateKey)
throws SignatureException {
try {
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(plainText.getBytes("UTF8"));
byte[] valueSigned = signature.sign();
return Base64.getEncoder().encodeToString(valueSigned);
} catch (NoSuchAlgorithmException | InvalidKeyException | UnsupportedEncodingException e) {
throw new SignatureException(e);
}
}
public class CitizenTransactionDetails implements Serializable {
// This is just a Java class that represents the json object that you will need to send to the Yaspa backend.
// These are required fields.
private static final long serialVersionUID = 212345678976543210L;
private String paymentGiro; //Either FPS or SEPA
private String customerEmailAddress;
private String merchantEmailAddress;
private String merchantId;
private String amount;
private String currency; // has to be a valid currency ISO code e.g. USD, EUR, GBP
private String reference;
private String merchantBankCode;
private String merchantAccountNumber;
private String customerIpAddress;
private String customerDeviceOs;
private List<String> supportedCountries; // has to be an array of valid country ISO codes e.g GB, NL
private String successRedirectUrl;
private String failureRedirectUrl;
private boolean queue;
private String heldReason;
private Boolean disableAddingNewBanks;
private String language;
//Getters and Setters
}
@RestController
@RequestMapping(value = "my-payments-endpoint")
public class PaymentEndpoints {
//Your backend will then make a request to the Yaspa service to create a transaction.
@RequestMapping(method = RequestMethod.POST, path = "/your-example-payment-endpoint")
public Callable<ResponseEntity<TextNode>> createCitizenPaymentTransaction(TransactionDetails details) {
CitizenTransactionDetails citizenPayoutDetails = new CitizenTransactionDetails();
citizenPayoutDetails.setCustomerEmailAddress(DB.getCustomerEmail());//only needed for email journey
citizenPayoutDetails.setMerchantId(details.getMerchantId());
citizenPayoutDetails.setAmount(details.getAmount());
citizenPayoutDetails.setCurrency("GBP");
citizenPayoutDetails.setPaymentGiro(PaymentGiro.FPS);
citizenPayoutDetails.setReference("MyShortReference123");
citizenPayoutDetails.setCustomerIpAddress(details.getCustomerIpAddress());
citizenPayoutDetails.setCustomerDeviceOs(details.getCustomerDeviceOs());
citizenPayoutDetails.setSupportedCountries(DB.getSupportedCountries());
citizenPayoutDetails.setSuccessRedirectUrl("<my-success-redirect-url>");
citizenPayoutDetails.setFailureRedirectUrl("<my-failure-redirect-url>");
citizenPayoutDetails.setQueue(DB.shouldPayoutQueued());
citizenPayoutDetails.setHeldReason(DB.getHeldReason());
citizenPayoutDetails.setDisableAddingNewBanks(details.getDisableAddingNewBanks());
citizenPayoutDetails.setBankSuccessRedirectUrl("<my-bank-success-redirect-url>");
citizenPayoutDetails.setBankFailureRedirectUrl("<my-bank-failure-redirect-url>");
citizenPayoutDetails.setLanguage(details.getLanguage());
RestTemplate restTemplate = new RestTemplate();
String citizenVerifiedPayoutUrl = "https://testapi.yaspa.com/v2/payouts/verified/session";
HttpHeaders httpHeaders = generateHeadersForSignedRequest(HttpMethod.POST,
citizenVerifiedPayoutUrl,
citizenPayoutDetails,
DB.getPrivateKey);
httpHeaders.set("AuthorizationCitizen", [YOUR_ENTITY_API_KEY]]);
ResponseEntity<TextNode> payoutInitResponse = restTemplate
.exchange(citizenVerifiedPayoutUrl, HttpMethod.POST,
new HttpEntity<>(citizenPayoutDetails, httpHeaders), TextNode.class);
String citizenPayoutTransactionId = payoutInitResponse.getBody().asText();
return ResponseEntity.ok(new TextNode(citizenPayoutTransactionId)); //Return this to your front end
}
}
private HttpHeaders generateHeadersForSignedRequest (
HttpMethod httpMethod, String url, Object requestBody, PrivateKey privateKey)
throws JsonProcessingException, SignatureException {
String requestExpiryTime = String.valueOf(Instant.now().getEpochSecond() + 300);
String textToSign = requestExpiryTime + "|" + httpMethod.name().toUpperCase() + "|" + url + "|";
if (requestBody != null) {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
ObjectWriter objectWriter = objectMapper.writer();
String requestJson = objectWriter.writeValueAsString(requestBody);
textToSign += requestJson;
}
String signature = generateSignature(textToSign, privateKey);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("Signature", signature);
httpHeaders.set("Expires-at", requestExpiryTime);
return httpHeaders;
}
private String generateSignature(String plainText, PrivateKey privateKey)
throws SignatureException {
try {
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(plainText.getBytes("UTF8"));
byte[] valueSigned = signature.sign();
return Base64.getEncoder().encodeToString(valueSigned);
} catch (NoSuchAlgorithmException | InvalidKeyException | UnsupportedEncodingException e) {
throw new SignatureException(e);
}
}
Setting up a verified payout in your backend is simple, and requires a number of fields set.
Parameter | Description | Type | Required |
---|---|---|---|
merchantId | Your merchantId. This can be obtained from the admin dashboard | string | Y |
customerIdentifier | Used to identify the customer receiving the payout. This can be an identifier internal to your system | string | Y |
customerEmailAddress | Customer email address which is used if using the payout journey | string | N |
amount | Decimal value of the payout - string with number with 2 decimal places | string | Y |
currency | string with valid ISO currency code | string | Y |
paymentGiro | payment type (SEPA or FPS) | string | Y |
reference | Reference for the payout (max 15 chars). This MUST be unique | string | Y |
customerDeviceOs | OS for the customer receiving the payout | string | Y |
customerIpAddress | IP address of the customer receiving the payout | string with valid IPv4 or IPv6 format | Y |
searchableText | searchable string | string | N |
payload | meta-data of the payment | string | N |
payloadEncrypted | encrypt payload field (true/false) | boolean | N |
supportedCountries | filter the bank list in bank selection page | array of string country ISO codes | N |
successRedirectUrl | Url that the user is redirected to from the modal on completion of a successful payout journey | string | N |
failureRedirectUrl | Url that the user is redirected to from the modal on completion of a failed payout journey | string | N |
successBankRedirectUrl | Url that the user is redirected to from their bank selection screen on a successful approval | string | N |
failureBankRedirectUrl | Url that the user is redirected to from their bank selection screen on a cancelled/failed request | string | N |
queue | determine if the payout will added to queue and waiting for manual confirmation or submitted right away | boolean | N |
heldReason | the reason that a payout added to a queue | string | N |
disableAddingNewBanks | Prevents user from removing existing bank accounts or adding new ones | boolean | N |
language | The language that will be used to translate the journey | string of language ISO-639-1 code. Default value 'en' | N |
Payout Request Signature
The request must be signed to authenticate the merchant. The signature is valid until a given expiry time set by the merchant (max 10 minutes from the time the request is made).
The signature plain text is generated by concatenating the request components, each one separated by the '|' delimiter:
expiryTime | httpMethod | url | requestBody
If the request body is not present in the request then the signature plain text is as follows:
expiryTime | httpMethod | url |
Component | Description |
---|---|
expiryTime | Integer UNIX timestamp for signature expiry time |
httpMethod | String HTTP method (GET, POST etc) in upper case |
url | String URL of the endpoint |
requestBody | String representation of the JSON request body if present |
An example of the signature plain text is as follows
1613639354|POST|https://api.yaspa.com/v1/payouts/verified-payout-session|{"customerEmailAddress":"john.doe@test.com","merchantEmailAddress":"info@trading.com","merchantInternalId":"john.doe","currency":"GBP","paymentGiro":"FPS","merchantBankCode":"608384","merchantAccountNumber":"40027188","amount":"5.50","reference":"Monthly pay out."}
1613639354|POST|https://testapi.yaspa.com/v1/payouts/verified-payout-session|{"customerEmailAddress":"john.doe@test.com","merchantEmailAddress":"info@trading.com","merchantInternalId":"john.doe","currency":"GBP","paymentGiro":"FPS","merchantBankCode":"608384","merchantAccountNumber":"40027188","amount":"5.50","reference":"Monthly pay out."}
The signature plain text is signed by an RSA 2048 bit key, the public part of which will have been registered on the Yaspa service in advance. It is base 64 encoded and set in a header.
Adding the JS Verified Payout SDK to your page
Javascript: Adding the JS Verified Payout SDK
<script src="https://sdk.yaspa.com/v6/sdk/sdk-payout.js" data-api-key="[Your-merchant-public-api-key]"></script>
<script src="https://test-sdk.yaspa.com/v6/sdk/sdk-payout.js" data-api-key="[Your-merchant-public-api-key]"></script>
Javascript: Adding the JS Verified Payout SDK programmatically
function setupCitizenSdk() {
let scriptTag = document.createElement('script');
scriptTag.src = "https://sdk.yaspa.com/v6/sdk/sdk-payout.js";
scriptTag.dataset.apiKey = "[Your-merchant-public-api-key]"
document.body.appendChild(scriptTag)
}
//Then you can call the function on which point you want to load the sdk
setupCitizenSdk()
function setupCitizenSdk() {
let scriptTag = document.createElement('script');
scriptTag.src = "https://test-sdk.yaspa.com/v6/sdk/sdk-payout.js";
scriptTag.dataset.apiKey = "[Your-merchant-public-api-key]"
document.body.appendChild(scriptTag)
}
//Then you can call the function on which point you want to load the sdk
setupCitizenSdk()
The SDK is a Javascript library that you link to from your page You can find your public api key in the dashboard in your merchant information page.
Checking that our SDK has been loaded and is ready to be used
Javascript: Check the readiness of the SDK
window.CITIZEN_PAYOUT.ready().then(() => {
//in this point the sdk is ready to be used
})
window.CITIZEN_PAYOUT.ready().then(() => {
//in this point the sdk is ready to be used
})
You are able to check if the CITIZEN_PAYOUT is ready to be used calling the function .ready()
of the SDK.
This will return a promise
that will be resolved when SDK is ready to be used.
Starting the Verified Payout Journey (Direct Verified Payouts)
Javascript: Starting the Verified Payout Journey
<script>
// transactionId - from the previous step
let sendVerifiedPayout = function (transactionId) {
window.CITIZEN_PAYOUT.startVerifiedPayoutJourney(transactionId);
}
</script>
Once you have the transaction ID, you can start the verified payout journey.
This call will redirect the user from the current page to a consent page with the details of the journey.
Starting the QR code Verified Payout Journey
You may not want the user to be sent an email to begin their verified payout journey. For this, we offer a way to show to the user
a QR code, where he will be able to scan it and continue the journey on his device.
Javascript: Starting the QR code Verified Payout Journey
<script>
// citizenTransactionId - from the previous step
// options - an object that can contain the following optional fields:
// 1. initiatedCallback - a callback that is triggered when the background work is done and the modal is shown.
// Used mostly to handle the loading state of the host page. If non is passed, the loading state is handled from the modal
//
// e.g. const options = {
// initiatedCallback: function(){console.log("This function called when the modal is about to open")}
// }
let sendQrVerifiedPayIn = function (citizenTransactionId) {
window.CITIZEN_PAYOUT.startQRCodeVerifiedPayoutJourney(citizenTransactionId, options);
}
</script>
Once you have the citizenTransactionId, you can start the QR code verified payout journey.
Hosted Journeys
Hosted journeys are a way for you to make use of SDK without having to incorporate it into your site. You can just generate a link to a page that we host and then redirect your user to. This way you do not need to worry about how to display the correct details or integrating/updating our SDK
Pay-Ins
Url
https://api.yaspa.com/v2/payins/hosted-payin/generate-link
https://testapi.yaspa.com/v2/payins/hosted-payin/generate-link
Use the following to make use of our standard pay-in journey.
To generate the link you will need to call the following endpoint from your backend as it will use your merchant private api key
Java: Generating Hosted Pay-In Link
public class HostedPayInDetails implements Serializable {
// This is just a Java class that represents the json object that you will need to send to the Yaspa backend.
// These are required fields.
private String customerIdentifier;
private String amount;
private String currency;
private PaymentGiro paymentGiro;
private String reference;
private String description;
private String searchableText;
private String payload;
private boolean isPayloadEncrypted;
private List<String> supportedCountries; // has to be an array of valid country ISO codes e.g GB, NL
private String language;
//Getters and Setters
}
@RestController
@RequestMapping(value = "my-hosted-payIn-endpoint")
public class HostedPayInEndpoints {
//Your backend will then make a request to the Yaspa service to create a transaction.
@RequestMapping(method = RequestMethod.POST, path = "/your-example-payin-endpoint")
public ResponseEntity<*> createCitizenHostedPayIn(HostedPayInDetails details) {
HostedPayInDetails citizenPayInDetails = new HostedPayInDetails();
citizenPayInDetails.setCustomerIdentifier("info@company.com");
citizenPayInDetails.setAmount(details.getAmount);
citizenPayInDetails.setCurrency("GBP");
citizenPayInDetails.setPaymentGiro(PaymentGiro.FPS);
citizenPayInDetails.setReference("MyPaymentReference123");
citizenPayInDetails.setDescription("This is my description for the payment");
citizenPayInDetails.setJourneyType("HOSTED_PAYMENT");
citizenPayInDetails.setSuccessRedirectUrl("<my-success-redirect-url>");
citizenPayInDetails.setFailureRedirectUrl("<my-failure-redirect-url>");
citizenPayInDetails.setLanguage(details.getLanguage());
RestTemplate restTemplate = new RestTemplate();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("AuthorizationCitizen", [YOUR_MERCHANT_PRIVATE_API_KEY]]);
ResponseEntity<*> HostedPayInLinkResponse = restTemplate
.exchange("https://api.yaspa.com/v2/payins/hosted-payin/generate-link", HttpMethod.POST,
new HttpEntity<>(citizenPayInDetails, httpHeaders), String.class);
String hostedPayInLink = HostedPayInLinkResponse.getBody();
return ResponseEntity.ok(hostedPayInLink); //Return this to your front end
}
}
public class HostedPayInDetails implements Serializable {
// This is just a Java class that represents the json object that you will need to send to the Yaspa backend.
// These are required fields.
private String customerIdentifier;
private String amount;
private String currency;
private PaymentGiro paymentGiro;
private String reference;
private String description;
private String searchableText;
private String payload;
private boolean isPayloadEncrypted;
private List<String> supportedCountries; // has to be an array of valid country ISO codes e.g GB, NL
private String language;
//Getters and Setters
}
@RestController
@RequestMapping(value = "my-hosted-payin-endpoint")
public class HostedPayInEndpoints {
//Your backend will then make a request to the Yaspa service to create a transaction.
@RequestMapping(method = RequestMethod.POST, path = "/your-example-payin-endpoint")
public ResponseEntity<*> createCitizenHostedPayIn(HostedPayInDetails details) {
HostedPayInDetails citizenPayInDetails = new HostedPayInDetails();
citizenPayInDetails.setCustomerIdentifier("info@company.com");
citizenPayInDetails.setAmount(details.getAmount);
citizenPayInDetails.setCurrency("GBP");
citizenPayInDetails.setPaymentGiro(PaymentGiro.FPS);
citizenPayInDetails.setReference("MyPaymentReference123");
citizenPayInDetails.setDescription("This is my description for the payment");
citizenPayInDetails.setJourneyType("HOSTED_PAYMENT");
citizenPayInDetails.setSuccessRedirectUrl("<my-success-redirect-url>");
citizenPayInDetails.setFailureRedirectUrl("<my-failure-redirect-url>");
citizenPayInDetails.setLanguage(details.getLanguage());
RestTemplate restTemplate = new RestTemplate();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("AuthorizationCitizen", [YOUR_MERCHANT_PRIVATE_API_KEY]]);
ResponseEntity<*> HostedPayInLinkResponse = restTemplate
.exchange("https://testapi.yaspa.com/v2/payins/hosted-payin/generate-link", HttpMethod.POST,
new HttpEntity<>(citizenPayInDetails, httpHeaders), String.class);
String hostedPayInLink = HostedPayInLinkResponse.getBody();
return ResponseEntity.ok(hostedPayInLink); //Return this to your front end
}
}
Parameter | Description | Type | Required |
---|---|---|---|
customerIdentifier | The internal id you use on your systems to identity your user | String | Y |
paymentGiro | either FPS (UK faster payments) or SEPA (EU SEPA Inst) | String | Y |
amount | A valid payment amount (2 decimal digit number) | String with valid 2 decimal number format | Y |
currency | currency | String with valid ISO currency code | Y |
reference | the reference shown to the customer in their bank statement. Needs to be alphanumeric and 15 chars max. This MUST be unique | String | Y |
journeyType | the type of the journey, payin (HOSTED_PAYMENT) or verified payin (HOSTED_VERIFIED_PAYMENT) | String | Y |
description | A description that will show up on the hosted page to describe what the pay-in is for. | String | N |
searchableText | a string that you can use to search for this pay-in | String | N |
payload | a string payload that can take any format e.g. JSON object | String | N |
isPayloadEncrypted | A boolean to specify whether you want to encrypt your payload (default: false) | Boolean | N |
supportedCountries | filter the bank list in bank selection page | array of string country ISO codes | N |
successRedirectUrl | the page redirection for a successful payin | String | N |
failureRedirectUrl | the page redirection for a failure payin | String | N |
successBankRedirectUrl | Url that the user is redirected to from their bank app on a successful approval | string | N |
failureBankRedirectUrl | Url that the user is redirected to from their bank app on a cancelled/failed request | string | N |
language | The language that will be used to translate the journey | string of language ISO-639-1 code. Default value 'en' | N |
You will then get a URL to the hosted page. It has an expiry of 1 week. Once expired you will need to generate a new hosted pay-in.
Response
https://banks.yaspa.com/hosted?transaction-id=fab54752-ddfe-7d61-40a8-51a49a
https://test-banks.yaspa.com/hosted?transaction-id=fab54752-ddfe-7d61-40a8-51a49a
Verified Pay-Ins
Url
https://api.yaspa.com/v2/payins/hosted-payin/generate-link
https://testapi.yaspa.com/v2/payins/hosted-payin/generate-link
Use the following to make use of our standard pay-in journey.
To generate the link you will need to call the following endpoint from your backend as it will use your merchant private api key
Java: Generating Hosted Verified Pay-In Link
public class HostedPayInDetails implements Serializable {
// This is just a Java class that represents the json object that you will need to send to the Yaspa backend.
// These are required fields.
private String customerIdentifier;
private String amount;
private String currency;
private PaymentGiro paymentGiro;
private String reference;
private String description;
private String searchableText;
private String payload;
private boolean isPayloadEncrypted;
private List<String> supportedCountries; // has to be an array of valid country ISO codes e.g GB, NL
private String language;
//Getters and Setters
}
@RestController
@RequestMapping(value = "my-hosted-verified-payIn-endpoint")
public class HostedPayInEndpoints {
//Your backend will then make a request to the Yaspa service to create a transaction.
@RequestMapping(method = RequestMethod.POST, path = "/your-example-payin-endpoint")
public ResponseEntity<*> createCitizenHostedPayIn(HostedPayInDetails details) {
HostedPayInDetails citizenPayInDetails = new HostedPayInDetails();
citizenPayInDetails.setCustomerIdentifier("info@company.com");
citizenPayInDetails.setAmount(details.getAmount);
citizenPayInDetails.setCurrency("GBP");
citizenPayInDetails.setPaymentGiro(PaymentGiro.FPS);
citizenPayInDetails.setReference("MyPaymentReference123");
citizenPayInDetails.setDescription("This is my description for the payment");
citizenPayInDetails.setJourneyType("HOSTED_VERIFIED_PAYMENT");
citizenPayInDetails.setSuccessRedirectUrl("<my-success-redirect-url>");
citizenPayInDetails.setFailureRedirectUrl("<my-failure-redirect-url>");
citizenPayInDetails.setLanguage(details.getLanguage());
RestTemplate restTemplate = new RestTemplate();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("AuthorizationCitizen", [YOUR_MERCHANT_PRIVATE_API_KEY]]);
ResponseEntity<*> HostedPayInLinkResponse = restTemplate
.exchange("https://api.yaspa.com/v2/payins/hosted-payin/generate-link", HttpMethod.POST,
new HttpEntity<>(citizenPayInDetails, httpHeaders), String.class);
String hostedPayInLink = HostedPayInLinkResponse.getBody();
return ResponseEntity.ok(hostedPayInLink); //Return this to your front end
}
}
public class HostedPayInDetails implements Serializable {
// This is just a Java class that represents the json object that you will need to send to the Yaspa backend.
// These are required fields.
private String customerIdentifier;
private String amount;
private String currency;
private PaymentGiro paymentGiro;
private String reference;
private String description;
private String searchableText;
private String payload;
private boolean isPayloadEncrypted;
private List<String> supportedCountries; // has to be an array of valid country ISO codes e.g GB, NL
private String language;
//Getters and Setters
}
@RestController
@RequestMapping(value = "my-hosted-verified-payin-endpoint")
public class HostedPayInEndpoints {
//Your backend will then make a request to the Yaspa service to create a transaction.
@RequestMapping(method = RequestMethod.POST, path = "/your-example-payin-endpoint")
public ResponseEntity<*> createCitizenHostedPayIn(HostedPayInDetails details) {
HostedPayInDetails citizenPayInDetails = new HostedPayInDetails();
citizenPayInDetails.setCustomerIdentifier("info@company.com");
citizenPayInDetails.setAmount(details.getAmount);
citizenPayInDetails.setCurrency("GBP");
citizenPayInDetails.setPaymentGiro(PaymentGiro.FPS);
citizenPayInDetails.setReference("MyPaymentReference123");
citizenPayInDetails.setDescription("This is my description for the payment");
citizenPayInDetails.setJourneyType("HOSTED_VERIFIED_PAYMENT");
citizenPayInDetails.setSuccessRedirectUrl("<my-success-redirect-url>");
citizenPayInDetails.setFailureRedirectUrl("<my-failure-redirect-url>");
citizenPayInDetails.setLanguage(details.getLanguage());
RestTemplate restTemplate = new RestTemplate();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("AuthorizationCitizen", [YOUR_MERCHANT_PRIVATE_API_KEY]]);
ResponseEntity<*> HostedPayInLinkResponse = restTemplate
.exchange("https://testapi.yaspa.com/v2/payins/hosted-payin/generate-link", HttpMethod.POST,
new HttpEntity<>(citizenPayInDetails, httpHeaders), String.class);
String hostedPayInLink = HostedPayInLinkResponse.getBody();
return ResponseEntity.ok(hostedPayInLink); //Return this to your front end
}
}
Parameter | Description | Type | Required |
---|---|---|---|
customerIdentifier | The internal id you use on your systems to identity your user | String | Y |
paymentGiro | either FPS (UK faster payments) or SEPA (EU SEPA Inst) | String | Y |
amount | A valid payment amount (2 decimal digit number) | String with valid 2 decimal number format | Y |
currency | currency | String with valid ISO currency code | Y |
reference | the reference shown to the customer in their bank statement. Needs to be alphanumeric and 15 chars max | String | Y |
journeyType | the type of the journey, payin (HOSTED_PAYMENT) or verified payin (HOSTED_VERIFIED_PAYMENT) | String | Y |
description | A description that will show up on the hosted page to describe what the pay-in is for. | String | N |
searchableText | a string that you can use to search for this pay-in | String | N |
payload | a string payload that can take any format e.g. JSON object | String | N |
isPayloadEncrypted | A boolean to specify whether you want to encrypt your payload (default: false) | Boolean | N |
supportedCountries | filter the bank list in bank selection page | array of String country ISO codes | N |
successRedirectUrl | the page redirection for a successful payin | String | N |
failureRedirectUrl | the page redirection for a failure payin | String | N |
successBankRedirectUrl | Url that the user is redirected to from their bank app on a successful approval | string | N |
failureBankRedirectUrl | Url that the user is redirected to from their bank app on a cancelled/failed request | string | N |
language | The language that will be used to translate the journey | string of language ISO-639-1 code. Default value 'en' | N |
You will then get a URL to the hosted page. It has an expiry of 1 week. Once expired you will need to generate a new hosted pay-in.
Response
https://banks.yaspa.com/hosted/payin?transaction-id=fab54752-ddfe-7d61-40a8-51a49a
https://test-banks.yaspa.com/hosted/payin?transaction-id=fab54752-ddfe-7d61-40a8-51a49a
Verified Pay-Outs
Url
https://api.yaspa.com/v2/payouts/hosted-payout/generate-link
https://testapi.yaspa.com/v2/payouts/hosted-payout/generate-link
Hosted Payouts feature requires to have completed the steps for integrating a verified payout. In other words, it requires to have created a public/private openSSL RSA 2048 bit keypair, registered your public key in our platform through the admin dashboard and finally use the above private to sign the request. If you have already done it for the payouts it is not necessary to go over the procedure. For more detailed guide on the above, check the signature section.
Use the following to make use of our standard verified pay-out journey. However, it is worth mentioning that hosted-payouts require the request to be signed in order to authenticate the merchant, before receiving the final link.
To generate the link you will need to call the following endpoint from your backend as it will use your merchant private api key along with signing details, such as expiration time and base64 encoded signature.
Headers
Header | Description |
---|---|
AuthorizationCitizen | Your private API key |
Expires-at | UNIX timestamp for signature expiration |
Signature | Base 64 encoded signature |
Content-Type | 'application/json' |
Java: Generating Hosted Pay-Out Link
public class HostedPayOutDetails implements Serializable {
// This is just a Java class that represents the json object that you will need to send to the Yaspa backend.
// These are required fields.
private String customerIdentifier;
private String amount;
private String currency;
private PaymentGiro paymentGiro;
private String reference;
private String description;
private List<String> supportedCountries; // has to be an array of valid country ISO codes e.g GB, NL
private String language;
//Getters and Setters
}
@RestController
@RequestMapping(value = "my-hosted-payOut-endpoint")
public class HostedPayOutEndpoints {
//Your backend will then make a request to the Yaspa service to create a transaction.
@RequestMapping(method = RequestMethod.POST, path = "/your-example-payout-endpoint")
public ResponseEntity<*> createCitizenHostedPayOut(HostedPayOutDetails details) {
HostedPayInDetails citizenPayOutDetails = new HostedPayOutDetails();
citizenPayOutDetails.setCustomerIdentifier("info@company.com");
citizenPayOutDetails.setAmount(details.getAmount);
citizenPayOutDetails.setCurrency("GBP");
citizenPayOutDetails.setPaymentGiro(PaymentGiro.FPS);
citizenPayOutDetails.setReference("MyPaymentReference123");
citizenPayOutDetails.setDescription("This is my description for the payment");
citizenPayInDetails.setLanguage(details.getLanguage());
RestTemplate restTemplate = new RestTemplate();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("AuthorizationCitizen", [YOUR_MERCHANT_PRIVATE_API_KEY]]);
ResponseEntity<*> HostedPayInLinkResponse = restTemplate
.exchange("https://api.yaspa.com/v2/payouts/hosted-payout/generate-link", HttpMethod.POST,
new HttpEntity<>(citizenPayOutDetails, httpHeaders), String.class);
String hostedPayOutLink = HostedPayOutLinkResponse.getBody();
return ResponseEntity.ok(hostedPayOutLink); //Return this to your front end
}
}
public class HostedPayOutDetails implements Serializable {
// This is just a Java class that represents the json object that you will need to send to the Yaspa backend.
// These are required fields.
private String customerIdentifier;
private String amount;
private String currency;
private PaymentGiro paymentGiro;
private String reference;
private String description;
private List<String> supportedCountries; // has to be an array of valid country ISO codes e.g GB, NL
private String language;
//Getters and Setters
}
@RestController
@RequestMapping(value = "my-hosted-payOut-endpoint")
public class HostedPayOutEndpoints {
//Your backend will then make a request to the Yaspa service to create a transaction.
@RequestMapping(method = RequestMethod.POST, path = "/your-example-payout-endpoint")
public ResponseEntity<*> createCitizenHostedPayOut(HostedPayOutDetails details) {
HostedPayInDetails citizenPayOutDetails = new HostedPayOutDetails();
citizenPayOutDetails.setCustomerIdentifier("info@company.com");
citizenPayOutDetails.setAmount(details.getAmount);
citizenPayOutDetails.setCurrency("GBP");
citizenPayOutDetails.setPaymentGiro(PaymentGiro.FPS);
citizenPayOutDetails.setReference("MyPaymentReference123");
citizenPayOutDetails.setDescription("This is my description for the payment");
citizenPayOutDetails.setLanguage(details.getLanguage());
RestTemplate restTemplate = new RestTemplate();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("AuthorizationCitizen", [YOUR_MERCHANT_PRIVATE_API_KEY]]);
ResponseEntity<*> HostedPayInLinkResponse = restTemplate
.exchange("https://testapi.yaspa.com/v2/payouts/hosted-payout/generate-link", HttpMethod.POST,
new HttpEntity<>(citizenPayOutDetails, httpHeaders), String.class);
String hostedPayOutLink = HostedPayOutLinkResponse.getBody();
return ResponseEntity.ok(hostedPayOutLink); //Return this to your front end
}
}
Body
Parameter | Description | Type | Required |
---|---|---|---|
customerIdentifier | The internal id you use on your systems to identity your user | String | y |
paymentGiro | either FPS (UK faster payments) or SEPA (EU SEPA Inst) | String | Y |
amount | A valid payment amount (2 decimal digit number) | String with valid 2 decimal number format | Y |
currency | currency | String with valid ISO currency code | Y |
reference | the reference shown to the customer in their bank statement. Needs to be alphanumeric and 15 chars max | String | Y |
description | A description that will show up on the hosted page to describe what the pay-out is for. | String | N |
journeyType | the type of the journey (default: HOSTED_PAYOUT) | String | N |
searchableText | a string that you can use to search for this pay-out | String | N |
payload | a string payload that can take any format e.g. JSON object | String | N |
isPayloadEncrypted | A boolean to specify whether you want to encrypt your payload (default: false) | Boolean | N |
isQueued | A boolean to specify whether you want to enqueue your payout (default: false) | Boolean | N |
successRedirectUrl | the page redirection for a successful payout | String | N |
failureRedirectUrl | the page redirection for a failure payout | String | N |
successBankRedirectUrl | Url that the user is redirected to from their bank selection page on a successful payout | string | N |
failureBankRedirectUrl | Url that the user is redirected to from their bank selection page on a cancelled/failed payout | string | N |
language | The language that will be used to translate the journey | string of language ISO-639-1 code. Default value 'en' | N |
Generating Hosted Pay-Out Link Request Signature
The request must be signed to authenticate the merchant. The signature is valid until a given expiry time set by the merchant (max 10 minutes from the time the request is made).
The signature plain text is generated by concatenating the request components, each one separated by the '|' delimiter:
An example of the signature plain text is as follows
1613639354|POST|https://api.yaspa.com/v2/payouts/hosted-payout/generate-link|{"customerIdentifier":"info@company.com","amount":"1","currency":"GBP","paymentGiro":"FPS","reference":"MyPaymentReference123"}
1613639354|POST|https://testapi.yaspa.com/v2/payouts/hosted-payout/generate-link|{"customerIdentifier":"info@company.com","amount":"1","currency":"GBP","paymentGiro":"FPS","reference":"MyPaymentReference123"}
expiryTime | httpMethod | url | requestBody
If the request body is not present in the request then the signature plain text is as follows:
expiryTime | httpMethod | url |
Component | Description |
---|---|
expiryTime | Integer UNIX timestamp for signature expiry time |
httpMethod | String HTTP method (GET, POST etc) in upper case |
url | String URL of the endpoint |
requestBody | String representation of the JSON request body if present |
The signature plain text is signed by an RSA 2048 bit key, the public part of which will have been registered on the Yaspa service in advance. It is base 64 encoded and set in a header.
Response
https://banks.yaspa.com/hosted/payout?transaction-id=f9ce6a1f-0776-4a1c-d98a-23c22b
https://test-banks.yaspa.com/hosted/payout?transaction-id=f9ce6a1f-0776-4a1c-d98a-23c22b
Response
Given that you have successfully completed the above steps, you will then get a link for Hosted Pay-Out. It has an expiry of 1 week. Once expired you will need to generate a new hosted pay-out.
Pay-In API
Our pay-in API allows you to create/start standard pay-in journeys, hosted pay-in journeys. Our pay-in API also enables you to display pay-in transactions information in your own apps and services.
Create Pay-In Session
Initiate a pay-in session on your backend as you will need to provide your private merchant api key (which you can find in your merchant dashboard).
You will then receive a citizenTransactionId. This will be used to start the pay-in journey.
cURL: Create Pay-In Session
curl https://api.yaspa.com/v2/payins/session \
-X POST \
-H Content-Type: application/json \
-H AuthorizationCitizen: your merchant private api key \
-d '{
customerIdentifier: 12345,
paymentGiro: FPS,
amount: 1.00,
currency: GBP,
reference: your reference,
description: your description,
customerIpAddress: 127.0.0.1,
customerDeviceOs: user OS,
searchableText: searchable text,
payload: {"address":"some address"},
isPayloadEncrypted: true,
supportedCountries: ['GB'],
successRedirectUrl: "https://www.example.com/success",
successBankRedirectUrl: "https://www.example.com/success",
failureRedirectUrl: "https://www.example.com/failure",
failureBankRedirectUrl: "https://www.example.com/failure",
language: "en"
}'
curl https://testapi.yaspa.com/v2/payins/session \
-X POST \
-H Content-Type: application/json \
-H AuthorizationCitizen: your merchant private api key \
-d '{
customerIdentifier: 12345,
paymentGiro: FPS,
amount: 1.00,
currency: GBP,
reference: your reference,
description: your description,
customerIpAddress: 127.0.0.1,
customerDeviceOs: user OS,
searchableText: searchable text,
payload: {"address":"some address"},
isPayloadEncrypted: true,
supportedCountries: ['GB'],
successRedirectUrl: "https://www.example.com/success",
failureRedirectUrl: "https://www.example.com/failure",
successBankRedirectUrl: "https://www.example.com/success",
failureBankRedirectUrl: "https://www.example.com/failure",
language: "en"
}'
Headers
Header | Description |
---|---|
AuthorizationCitizen | Your merchant private api key |
Content-Type | 'application/json' |
Request
Parameter | Description | Type | Required |
---|---|---|---|
customerIdentifier | The internal id you use on your systems to identity your user | string | Y |
customerEmailAddress | The email of the paying customer. Only needed for email journey | string | N |
paymentGiro | payment type (SEPA or FPS) | string | Y |
amount | decimal value of the payment | string with valid 2 decimal number format | Y |
currency | currency | string with valid ISO currency code | Y |
reference | payment reference shown to the customer. Needs to be alphanumeric and 15 chars max. This MUST be unique | string | Y |
description | description shown to the customer | string | N |
customerIpAddress | IP for the paying customer | string with valid IPv4 or IPv6 format | Y |
customerDeviceOs | OS for the paying customer | string | Y |
searchableText | searchable string | string | N |
payload | meta-data of the payment | string | N |
isPayloadEncrypted | encrypt payload field (true/false) | boolean | N |
supportedCountries | filter the bank list in bank selection page | array of string country ISO codes | N |
successRedirectUrl | It redirect the page that the modal is shown in completion of the journey | string | N |
failureRedirectUrl | It redirect the page that the modal is shown in case of closing the modal on failed status | string | N |
successBankRedirectUrl | Url that the user is redirected to from their bank app on a successful approval | string | N |
failureBankRedirectUrl | Url that the user is redirected to from their bank app on a cancelled/failed request | string | N |
language | The language that will be used to translate the journey | string of language ISO-639-1 code. Default value 'en' | N |
Response
The API response is a transaction ID that is required by the front end SDK.
String Response: Create Pay-In Session
<citizenTransactionId>
Get a single pay-in Transaction
Return a specific detailed pay-in transaction.
By Transaction ID
cURL: Get Single Pay-In Transaction
curl https://api.yaspa.com/v2/payins/{transactionId}
-X GET \
-H AuthorizationCitizen: <your merchant private api key> \
-H Content-Type: application/json
curl https://testapi.yaspa.com/v2/payins/{transactionId}
-X GET \
-H AuthorizationCitizen: <your merchant private api key> \
-H Content-Type: application/json
JSON Response: Get Single Pay-In Transaction
{
"citizenTransactionId": "<unique id for the pay-in transaction>",
"merchantId": "<id of merchant>",
"merchantTradingName": "<trading name of merchant>",
"customerIdentifier": "<the internal id you use on your systems to identity your user>",
"searchableText": "<a string that you can use to search for this pay-in>",
"financialServiceProvider": "<financial Service Provider, e.g. BARCLAYS>",
"creationDate": "<date of creation>",
"payload": "<a string payload that can take any format>",
"isPayloadEncrypted": "<boolean value indicated that the payload is encrypted or not>",
"version": "<version of api>",
"journeyType": "<type of journey, e.g. EMAIL/NO_EMAIL>",
"transactionType": "<type of transaction, e.g. PAYIN>",
"transactionStatus": "<status of the transaction>",
"paymentMethod": "e.g. OPEN_BANKING",
"paymentGiro": "e.g. FPS",
"customerAccountNumber": "<customer account number/iban *Only for verified pay-In*>",
"customerBankCode": "<customer sort code/bic *Only for verified pay-In*>",
"merchantAccountNumber": "<merchant account number/iban>",
"merchantBankCode": "<merchant sort code/bic>",
"paymentAmount": "<the amount of the payment>",
"paymentCurrency": "<the currency of the payment>",
"reference": "<a reference for the payment>",
"description": "<a description for the payment>"
}
Headers
Header | Description |
---|---|
AuthorizationCitizen | Your merchant private api key |
Response
Attribute | Description |
---|---|
citizenTransactionId | unique id for the pay-in transaction |
merchantId | id of merchant |
merchantTradingName | trading name of merchant |
customerIdentifier | the internal id you use on your systems to identity your user |
searchableText | a string that you can use to search for this pay-in |
financialServiceProvider | financial Service Provider, e.g. BARCLAYS |
creationDate | date of creation |
payload | a string payload that can take any format |
isPayloadEncrypted | boolean value indicated that the payload is encrypted or not |
version | version of api |
journeyType | type of journey, e.g. EMAIL/NO_EMAIL |
transactionType | type of transaction, e.g. PAYIN |
transactionStatus | status of the transaction |
paymentMethod | method of payment, e.g. OPEN_BANKING |
paymentGiro | paymentGiro, e.g. FPS |
customerAccountNumber | customer account number/iban |
customerBankCode | customer sort code/bic |
merchantAccountNumber | merchant account number/iban |
merchantBankCode | merchant sort code/bic |
paymentAmount | the amount of the payment |
paymentCurrency | the currency of the payment |
reference | a reference for the payment |
description | a description for the payment |
By reference
cURL: Get Single Pay-In Transaction by reference
curl https://api.yaspa.com/v2/payins/{reference}
-X GET \
-H AuthorizationCitizen: <your merchant private api key> \
-H Content-Type: application/json
curl https://testapi.yaspa.com/v2/payins/{reference}
-X GET \
-H AuthorizationCitizen: <your merchant private api key> \
-H Content-Type: application/json
JSON Response: Get Single Pay-In Transaction
{
"citizenTransactionId": "<unique id for the pay-in transaction>",
"merchantId": "<id of merchant>",
"merchantTradingName": "<trading name of merchant>",
"customerIdentifier": "<the internal id you use on your systems to identity your user>",
"searchableText": "<a string that you can use to search for this pay-in>",
"financialServiceProvider": "<financial Service Provider, e.g. BARCLAYS>",
"creationDate": "<date of creation>",
"payload": "<a string payload that can take any format>",
"isPayloadEncrypted": "<boolean value indicated that the payload is encrypted or not>",
"version": "<version of api>",
"journeyType": "<type of journey, e.g. EMAIL/NO_EMAIL>",
"transactionType": "<type of transaction, e.g. PAYIN>",
"transactionStatus": "<status of the transaction>",
"paymentMethod": "e.g. OPEN_BANKING",
"paymentGiro": "e.g. FPS",
"customerAccountNumber": "<customer account number/iban *Only for verified pay-In*>",
"customerBankCode": "<customer sort code/bic *Only for verified pay-In*>",
"merchantAccountNumber": "<merchant account number/iban>",
"merchantBankCode": "<merchant sort code/bic>",
"paymentAmount": "<the amount of the payment>",
"paymentCurrency": "<the currency of the payment>",
"reference": "<a reference for the payment>",
"description": "<a description for the payment>"
}
Headers
Header | Description |
---|---|
AuthorizationCitizen | Your merchant private api key |
Response
Attribute | Description |
---|---|
citizenTransactionId | unique id for the pay-in transaction |
merchantId | id of merchant |
merchantTradingName | trading name of merchant |
customerIdentifier | the internal id you use on your systems to identity your user |
searchableText | a string that you can use to search for this pay-in |
financialServiceProvider | financial Service Provider, e.g. BARCLAYS |
creationDate | date of creation |
payload | a string payload that can take any format |
isPayloadEncrypted | boolean value indicated that the payload is encrypted or not |
version | version of api |
journeyType | type of journey, e.g. EMAIL/NO_EMAIL |
transactionType | type of transaction, e.g. PAYIN |
transactionStatus | status of the transaction |
paymentMethod | method of payment, e.g. OPEN_BANKING |
paymentGiro | paymentGiro, e.g. FPS |
customerAccountNumber | customer account number/iban |
customerBankCode | customer sort code/bic |
merchantAccountNumber | merchant account number/iban |
merchantBankCode | merchant sort code/bic |
paymentAmount | the amount of the payment |
paymentCurrency | the currency of the payment |
reference | a reference for the payment |
description | a description for the payment |
Get Pay-In bank unavailable fallback url
When the customer is unable to continue the transaction by using a bank listed in the bank selector, the customer can proceed the transaction by directing to the fallback url, which is set from merchant. This fallback url can be any kind of url, such as merchant's webpage, or other third-party payment methods(e.g. paypal). The citizenTransactionId is included in the pay-in bank unavailable fallback url. Thus, the merchant can keep track of this transaction.
cURL: Get pay-In bank unavailable fallback url
curl https://api.yaspa.com/v2/payins/bank-unavailable-url/{citizenTransactionId} \
-X GET \
-H Content-Type: application/json \
curl https://testapi.yaspa.com/v2/payins/bank-unavailable-url/{citizenTransactionId} \
-X GET \
-H Content-Type: application/json \
Headers
Header | Description |
---|---|
Content-Type | 'application/json' |
Response
The API response is a url that has as query param the citizenTransactionId or null if the fallback url hasn't been set.
Attribute | Description |
---|---|
bankUnavailableFallbackURL | the bank unavailable fallback url |
transactionId | citizenTransactionId |
String Response: bank unavailable fallback url
<bankUnavailableFallbackURL>?transactionId=<citizenTransactionId>
Account Verification API
Our Account Verification API enables you to fetch and verify a user's bank account details via Open Banking from the user's bank. These details may then be used in your own applications.
Create Account Verification Session
The journey is initiated by creating an account verification session. This is done from your backend and uses your company private API key (from your admin dashboard).
cURL: Create Account Verification Session
curl https://api.yaspa.com/v2/account-verification/session \
-X POST \
-H Content-Type: application/json \
-H AuthorizationCitizen: <merchant private api key> \
-d '{
customerIdentifier=john.doe@test.com,
merchantId=your merchant ID,
scopes=[account_details]
}'
curl https://testapi.yaspa.com/v2/account-verification/session \
-X POST \
-H Content-Type: application/json \
-H AuthorizationCitizen: <merchant private api key> \
-d '{
customerIdentifier=john.doe@test.com,
merchantId=your merchant ID,
scopes=[account_details]
}'
Headers
Header | Description |
---|---|
AuthorizationCitizen | Your private API key |
Content-Type | 'application/json' |
Request
Parameter | Description | Type | Required |
---|---|---|---|
merchantId | Your merchant ID. This can be obtained from your admin dashboard | string | Y |
customerIdentifier | Used to identify the customer whose bank account details to fetch | string | Y |
customerEmailAddress | Email address if using the email journey | string | N |
customerIpAddress | IP for the customer | string with valid IPv4 or IPv6 format | N |
customerDeviceOs | OS for the customer | string | N |
scopes | the account information that the user will provide to you | array of 'account_details', 'transactions_details' values | Y |
searchableText | searchable string | string | N |
payload | meta-data of the request | string | N |
payloadEncrypted | encrypt payload field (true/false) | boolean | N |
supportedCountries | filter the bank list in bank selection page | array of string country ISO codes | N |
successRedirectUrl | Url that the modal is redirected to on a successful completion of the journey | string | N |
failureRedirectUrl | Url that the modal is redirected to on a failed journey | string | N |
successBankRedirectUrl | Url that the user is redirected to from their bank app on a successful approval | string | N |
failureBankRedirectUrl | Url that the user is redirected to from their bank app on a cancelled/failed request | string | N |
language | The language that will be used to translate the journey | string of language ISO-639-1 code. Default value 'en' | N |
Response
The API response is a transaction ID that is required by the front end SDK.
String Response: Create Accountholder Confirmation Session
<transaction ID>
Get Account Verification Transaction
Fetches a given account verification transaction with its fields decrypted. This call uses your private API key (obtained from your admin dashboard).
By Transaction ID
cURL: Get a Single Account Verification Transaction
curl https://api.yaspa.com/v2/account-verification/<transactionId>
-X GET \
-H AuthorizationCitizen: <merchant private api key> \
-H Content-Type: application/json
curl https://testapi.yaspa.com/v2/account-verification/<transactionId>
-X GET \
-H AuthorizationCitizen: <merchant private api key> \
-H Content-Type: application/json
JSON Response: Get Account Verification Transaction
{
"citizenTransactionId":<transaction ID>,
"merchantId":<your merchant ID>,
"merchantTradingName":"My Company",
"customerIdentifier":"john.doe@test.com",
"financialServiceProvider":"CITIZEN_TEST_BANK",
"version":"2",
"journeyType":"NO_EMAIL",
"transactionType":null,
"transactionStatus":"ACCEPTED",
"searchableText":null,
"payload":null,
"isPayloadEncrypted":false,
"creationDate":1647854171186,
"testParameters":{},
"accounts":[
{
"id":"a4b7f4fdt5g6l341133",
"accountName":"Yaspa Test-Account",
"accountHolderName":"Yaspa Test-Account",
"number":"57583676",
"partialAccountNumber":"676",
"sortCode":"040075",
"iban":"GB71REVO00997094014496",
"partialIban":"496",
"bic":"REVOGB21",
"balance":"null",
"type":"account",
"details":"{\"client_name\":\"Yaspa Test-Account\",\"account_number\":\"57583676\",\"sort_code\":\"040075\",\"iban\":\"GB71REVO00997094014496\",\"bic\":\"REVOGB21\"}",
"bank":"CITIZEN_TEST_BANK"
}
]
}
Headers
Header | Description |
---|---|
AuthorizationCitizen | Your private merchant API key |
Response
Attribute | Description |
---|---|
citizenTransactionId | identifier for the account verification journey |
merchantId | your merchant ID |
customerIdentifier | used to identify the customer whose bank details are fetched |
merchantTradingName | your merchant trading name |
financialServiceProvider | customer's bank |
version | account verification transaction version |
journeyType | type of joureny used to fetch the customer bank details |
transactionStatus | status of the journey |
creationDate | date the journey was initiated |
financialServiceProvider | the bank that user authorised |
accounts | customer bank account details |
Get Account Verification Bank Unavailable Fallback URL
A fallback URL can be set in your admin dasboard that is used when there is an error redirecting a customer to their bank. It includes the transaction ID as a parameter and may be fetched with this call.
cURL: Get Account Verification Bank Unavailable Fallback URL
curl https://api.yaspa.com/v2/account-verification/bank-unavailable-url/<transactionId> \
-X GET \
-H Content-Type: application/json \
curl https://testapi.yaspa.com/v2/account-verification/bank-unavailable-url/<transactionId> \
-X GET \
-H Content-Type: application/json \
Headers
Header | Description |
---|---|
Content-Type | 'application/json' |
Response
The API response is a url that has as query param the transaction ID or null if the fallback url hasn't been set.
Attribute | Description |
---|---|
bankUnavailableFallbackURL | Fallback URL for the given transaction |
String Response: bank unavailable fallback url
Fallback URL, eg: https://www.yaspa.com?transaction-id=9d7de170-ea61-5453-bd05-893876
Verified Pay-In API
Our Verified Pay-In API enables you to receive pay-ins from your customer's verified bank account. Your customer needs at least one verified bank account during this journey. If your customer doesn't have a verified bank account, they will be taken through our account verification journey automatically.
Types of Verified Pay-In Journey
Types | without Email | with Email | with QR code |
---|---|---|---|
Without Verified Account | account verification transaction & pay-in transaction | account verification transaction & pay-in transaction | account verification transaction & pay-in transaction |
With Verified Account | pay-in transaction | pay-in transaction | pay-in transaction |
Create Verified Pay-In Session
Initiate a verified pay-in session on your backend as you will need to provide your private api key (which you can find in your merchant dashboard).
You will then receive a citizenTransactionId. This will be used to start the verified pay-in journey.
cURL: Create Verified Pay-In Session
curl https://api.yaspa.com/v2/payins/verified/session \
-X POST \
-H Content-Type: application/json \
-H AuthorizationCitizen: your merchant private api key \
-d '{
customerIdentifier: 12345,
paymentGiro: FPS,
amount: 1.00,
currency: GBP,
reference: your reference,
description: your description,
customerIpAddress: 127.0.0.1,
customerDeviceOs: user OS,
searchableText: searchable text,
payload: {"address":"some address"},
isPayloadEncrypted: true,
supportedCountries: ['GB'],
successRedirectUrl: "https://www.example.com/success",
failureRedirectUrl: "https://www.example.com/failure",
successBankRedirectUrl: "https://www.example.com/success",
failureBankRedirectUrl: "https://www.example.com/failure",
disableAddingNewBanks: true,
language: "en"
}'
curl https://testapi.yaspa.com/v2/payins/verified/session \
-X POST \
-H Content-Type: application/json \
-H AuthorizationCitizen: your merchant private api key \
-d '{
customerIdentifier: 12345,
paymentGiro: FPS,
amount: 1.00,
currency: GBP,
reference: your reference,
description: your description,
customerIpAddress: 127.0.0.1,
customerDeviceOs: user OS,
searchableText: searchable text,
payload: {"address":"some address"},
isPayloadEncrypted: true,
supportedCountries: ['GB'],
successRedirectUrl: "https://www.example.com/success",
failureRedirectUrl: "https://www.example.com/failure",
successBankRedirectUrl: "https://www.example.com/success",
failureBankRedirectUrl: "https://www.example.com/failure",
disableAddingNewBanks: true,
language: "en"
}'
Headers
Header | Description |
---|---|
AuthorizationCitizen | Your merchant private api key |
Content-Type | 'application/json' |
Request
Parameter | Description | Type | Required |
---|---|---|---|
customerIdentifier | The internal id you use on your systems to identity your user | string | Y |
customerEmailAddress | The email of the paying customer. Only needed for email journey | string | N |
paymentGiro | payment type (SEPA or FPS) | string | Y |
amount | decimal value of the payment | string with valid 2 decimal number format | Y |
currency | currency | string with valid ISO currency code | Y |
reference | payment reference shown to the customer. Needs to be alphanumeric and 15 chars max. This MUST be unique | string | Y |
description | description shown to the customer | string | N |
customerIpAddress | IP for the paying customer | string with valid IPv4 or IPv6 format | Y |
customerDeviceOs | OS for the paying customer | string | Y |
searchableText | searchable string | string | N |
payload | meta-data of the payment | string | N |
isPayloadEncrypted | encrypt payload field (true/false) | boolean | N |
supportedCountries | filter the bank list in bank selection page | array of string country ISO codes | N |
successRedirectUrl | It redirect the page that the modal is shown in completion of the journey | string | N |
failureRedirectUrl | It redirect the page that the modal is shown in case of closing the modal on failed status | string | N |
successBankRedirectUrl | Url that the user is redirected to from their bank app on a successful approval | string | N |
failureBankRedirectUrl | Url that the user is redirected to from their bank app on a cancelled/failed request | string | N |
disableAddingNewBanks | Prevents user from removing existing bank accounts or adding new ones | boolean | N |
language | The language that will be used to translate the journey | string of language ISO-639-1 code. Default value 'en' | N |
Response
The API response is a citizenTransactionId that is required by the front end SDK.
String Response: Create Verified Pay-In Session
<citizenTransactionId>
Get Customer's Verified Accounts Details
Once you have created your verified pay-in session and retrieved your citizenTransactionId, you can retrieve a list of all the verified accounts a customer has with you, and the session details as well. You will just need to provide your citizenTransactionId and your merchant private api key.
cURL: Get Customer's Verified Accounts Details
curl https://api.yaspa.com/v2/account-verification/verified-payin/api/accounts/{citizenTransactionId} \
-X GET \
-H AuthorizationCitizen: <your merchant private api key> \
-H Content-Type: application/json
curl https://testapi.yaspa.com/v2/account-verification/verified-payin/api/accounts/{citizenTransactionId} \
-X GET \
-H AuthorizationCitizen: <your merchant private api key> \
-H Content-Type: application/json
JSON Response: Get Customer's Verified Accounts Details
{
"payInSession": {
"citizenTransactionId": "<unique id for the verified pay-in transaction>",
"providerTransactionId": "",
"customerIdentifier": "<the internal id you use on your systems to identity your user>",
"customerEmailAddress": "<The email of the paying customer>",
"customerBankAccountId": "<customer selected bank account id>",
"serviceProvider": "<financial Service Provider, e.g. BARCLAYS>",
"paymentGiro": "e.g. FPS",
"amount": "<the amount of the payment>",
"currency": "<the currency of the payment>",
"reference": "<a reference for the payment>",
"description": "<a description for the payment>",
"transactionStatus": "<status of the transaction>",
"customerIpAddress": "<IP for the paying customer>",
"customerDeviceOs": "<OS for the paying customer>",
"bankAccountNumber": "<bank account for the verified pay-in transaction>",
"bankCode": "<bank code for the verified pay-in transaction>",
"searchableText": "<a string that you can use to search for the verified pay-in transaction>",
"payload": "<a string payload that can take any format>",
"isPayloadEncrypted": "<boolean value indicated that the payload is encrypted or not>",
"supportedCountries": "<list of string country>",
"successRedirectUrl": "<success redirect url>",
"failureRedirectUrl": "<failure redirect url>"
},
"accountTransactions": [
{
"citizenTransactionId": "<unique id for the pay-in transaction>",
"merchantId": "<id of merchant>",
"merchantTradingName": "<trading name of merchant>",
"customerIdentifier": "<the internal id you use on your systems to identity your user>",
"financialServiceProvider": "<financial Service Provider, e.g. BARCLAYS>",
"version": "<version of api>",
"journeyType": "<type of journey, e.g. EMAIL/NO_EMAIL>",
"transactionType": "<type of transaction, e.g. ACCOUNT_VERIFICATION>",
"transactionStatus": "<status of the transaction>",
"searchableText": "<a string that you can use to search for the verified pay-in transaction>",
"payload": "<a string payload that can take any format>",
"isPayloadEncrypted": "<boolean value indicated that the payload is encrypted or not>",
"creationDate": "<date of creation>",
"accounts": [
{
"id": "<id of account>",
"accountName": "<name of account>",
"accountHolderName": "<account holder name>",
"number": "<account number>",
"partialAccountNumber": "<partial account number>",
"sortCode": "<sort code of account>",
"iban": "<iban number of account>",
"partialIban": "<partial Iban number of account>",
"bic": "<bic number>",
"balance": "<balance of account>",
"type": "<>",
"details": "<description about account>",
"bank": "<financial Service Provider, e.g. BARCLAYS>"
}
]
}
]
}
Headers
Header | Description |
---|---|
AuthorizationCitizen | Your merchant private API key |
Parameter | Description |
---|---|
citizenTransactionId | String of the transaction ID to process |
Verified Payout API
Verified payouts are described here. The following stages of the journey can be handled by API calls:
Initiate a payout and create a temporary payout session
Get valid pre-verified bank accounts that a user can make a payout to
Submit a payout to the merchant bank and create a permenant transaction
Fetch the details of a payout transaction
Confirm a queued payout transaction
Reject a queued payout transaction
At present redirection to a user's bank to confirm their bank account must be handled by the SDK rather than an API call. However if a user has confirmed their bank account as part of a verified pay-in then it can also be used when submitting a verified payout to the merchant bank.
Confirming and rejected queued payouts by API calls means they do not need to be confirmed or rejected in the merchant dashboard.
Create Verified Payout session
The first step in the process is to create a verified payout session with details of the payout. This request is typically created from your back end. The request uses your merchant private API key (from your admin dashboard) and the body must be signed with the signature set as a request header. The call returns a transaction ID which is used throughout the payout journey.
cURL: Create Verified Payout Session
curl https://api.yaspa.com/v2/payouts/verified/session \
-X POST \
-H Content-Type: application/json \
-H AuthorizationCitizen: <private API key> \
-H Signature: <base 64 encoded signature of the request body> \
-H Expires-at: <UNIX timestamp> \
-d '{
merchantId: <your merchant ID>, \
customerIdentifier: <your unique identifier for the customer>, \
currency: GBP, \
paymentGiro: FPS, \
amount: 3.50, \
reference: ref12345, \
customerIpAddress: 192.168.1.2, \
customerDeviceOs: iOS 14 \
}'
curl https://testapi.yaspa.com/v2/payouts/verified/session \
-X POST \
-H Content-Type: application/json \
-H AuthorizationCitizen: <private API key> \
-H Signature: <base 64 encoded signature of the request body> \
-H Expires-at: <UNIX timestamp> \
-d '{
merchantId: <your merchant ID>, \
customerIdentifier: customer@gmail.com, \
currency: GBP, \
paymentGiro: FPS, \
amount: 3.50, \
reference: ref1234, \
customerIpAddress: 192.168.1.2, \
customerDeviceOs: iOS 14 \
}'
Headers
Header | Description |
---|---|
AuthorizationCitizen | Your private API key |
Expires-at | UNIX timestamp for signature expiration |
Signature | Base 64 encoded signature |
Content-Type | 'application/json' |
Request
Parameter | Description | Type | Required |
---|---|---|---|
merchantId | Your merchantId. This can be obtained from the admin dashboard | string | Y |
customerIdentifier | Used to identify the customer receiving the payout. This can be an identifier internal to your system | string | Y |
customerEmailAddress | Customer email address which is used if using the payout journey | string | N |
amount | Decimal value of the payout - string with number with 2 decimal places | string | Y |
currency | string with valid ISO currency code | string | Y |
paymentGiro | payment type (SEPA or FPS) | string | Y |
reference | Reference for the payout (max 15 chars). This MUST be unique | string | Y |
customerDeviceOs | OS for the customer receiving the payout | string | Y |
customerIpAddress | IP address of the customer receiving the payout | string with valid IPv4 or IPv6 format | Y |
searchableText | searchable string | string | N |
payload | meta-data of the payment | string | N |
payloadEncrypted | encrypt payload field (true/false) | boolean | N |
supportedCountries | filter the bank list in bank selection page | array of string country ISO codes | N |
successRedirectUrl | Url that the user is redirected to from the modal on completion of a successful payout journey | string | N |
failureRedirectUrl | Url that the user is redirected to from the modal on completion of a failed payout journey | string | N |
successBankRedirectUrl | Url that the user is redirected to from their bank app on a successful approval | string | N |
failureBankRedirectUrl | Url that the user is redirected to from their bank app on a cancelled/failed request | string | N |
queue | determine if the payout will added to queue and waiting for manual confirmation or submitted right away | boolean | N |
heldReason | the reason that a payout added to a queue | string | N |
disableAddingNewBanks | Prevents user from removing existing bank accounts or adding new ones | boolean | N |
language | The language that will be used to translate the journey | string of language ISO-639-1 code. Default value 'en' | N |
Response
The API response is a transaction ID that is required by the front end SDK.
String Response: Create Verified Payout Session
<transaction ID>
Get Valid Bank Accounts For Payout
After the user has authorised the account verification with their bank, their bank account details have now been verified and can be accessed with the following call. This call uses your private API key. After a bank account has been verified it can be used for future payouts without the need to do the account verification journey again.
cURL: Get Valid Bank Accounts For Payout
curl https://api.yaspa.com/v2/account-verification/verified-payout/api/accounts/<transaction ID> \
-H AuthorizationCitizen: <your private API key> \
-H Content-Type: application/json
curl https://testapi.yaspa.com/v2/account-verification/verified-payout/api/accounts/<transaction ID> \
-H AuthorizationCitizen: <your private API key> \
-H Content-Type: application/json
Headers
Header | Description |
---|---|
AuthorizationCitizen | Your private API key |
Path variables
Parameter | Description | Type |
---|---|---|
transactionID | Transaction ID to process | String |
Response
The response contains details of verified bank accounts that the payout may be sent to
String Response: Get Valid Bank Accounts For Payout
{
"accountTransactions": [
{
"citizenTransactionId":<transaction ID>,
"merchantId":<your merchant ID>,
"merchantTradingName":"My merchant",
"customerIdentifier":"test1@citizen.is",
"financialServiceProvider":"CITIZEN_TEST_BANK",
"version":"2",
"journeyType": "VERIFIED_PAYOUT_NO_EMAIL",
"transactionStatus":"ACCEPTED",
"creationDate":1646997683853,
"testParameters":{},
"accounts": [
{
"id":"A3GbeDIfc6f99ecDJKLC",
"accountName":"Yaspa Test-Account",
"accountHolderName":"Yaspa Test-Account",
"partialAccountNumber":"676",
"partialIban":"496",
"type":"account",
"bank":"CITIZEN_TEST_BANK"
}
]
}
]
}
Submit a payout transaction
This call submits a payout transaction to your merchant bank for processing.
cURL: Submit Payout Transaction
curl https://api.yaspa.com/v2/payouts/verified/api/submit \
-X POST \
-H Content-Type: application/json \
-H AuthorizationCitizen: <private API key> \
-d '{
"citizenTransactionId": "<transactionId>",
"customerBankAccountId: "<bankAccountId>"
}'
curl https://testapi.yaspa.com/v2/payouts/verified/api/submit \
-X POST \
-H Content-Type: application/json \
-H AuthorizationCitizen: <private API key> \
-d '{
"citizenTransactionId": "<transactionId>",
"customerBankAccountId: "<bankAccountId>"
}'
Response: Submit Payout Transaction
{
"citizenTransactionId":<transaction ID>,
"merchantId":<your merchant ID>,
"merchantTradingName":"My merchant",
"customerIdentifier":<your unique identifier for the customer>,
"transactionStatus":"ACCEPTED",
"creationDate":1647010433548,
"testParameters":{},
"citizenCounterPartyId":"622b62816a47c2389498b875",
"providerPaymentId":"296348",
"currency":"GBP",
"paymentGiro":"FPS",
"merchantBankCode":"608384",
"merchantAccountNumber":"40074844",
"merchantBank":"OPENPAYD",
"counterPartyBank":"CITIZEN_TEST_BANK",
"counterPartyBankCode":"040075",
"counterPartyAccountNumber":"57583676",
"counterPartyAccountName":"YaspaTest Account",
"amount":10.00,
"reference":"Test payment"
}
Headers
Header | Description |
---|---|
AuthorizationCitizen | Your private API key |
Request
Parameter | Description |
---|---|
citizenTransactionId | Transaction ID returned when creating the payout session |
customerBankAccountId | Customer bank account ID returned when fetching valid bank accounts |
Response
Payout transaction details.
Get the payout transaction
Details of the payout transaction can be fetched at any stage after its creation. This call uses your private API key and the payout transaction ID as the past parameter of its path.
cURL: Get Verified Payout Transaction
curl https://api.yaspa.com/v2/payouts/transaction/<transaction ID> \
-H Content-Type: application/json \
-H AuthorizationCitizen: <private API key>
curl https://testapi.yaspa.com/v2/payouts/transaction/<transaction ID> \
-H Content-Type: application/json \
-H AuthorizationCitizen: <private API key>
Response: Get Payout Transaction
{
"citizenTransactionId":<transaction ID>,
"merchantId":<your merchant ID>,
"merchantTradingName":"My merchant",
"customerIdentifier":<your unique identifier for the customer>,
"transactionStatus":"ACCEPTED",
"creationDate":1647010433548,
"testParameters":{},
"citizenCounterPartyId":"622b62816a47c2389498b875",
"providerPaymentId":"296348",
"currency":"GBP",
"paymentGiro":"FPS",
"merchantBankCode":"608384",
"merchantAccountNumber":"40074844",
"merchantBank":"OPENPAYD",
"counterPartyBank":"CITIZEN_TEST_BANK",
"counterPartyBankCode":"040075",
"counterPartyAccountNumber":"57583676",
"counterPartyAccountName":"YaspaTest Account",
"amount":10.00,
"reference":"Test payment"
}
Headers
Header | Description |
---|---|
AuthorizationCitizen | Your private API key |
Path variables
Parameter | Description | Type |
---|---|---|
citizenTransactionId | Transaction ID to process | String |
Response
Payout transaction details.
Confirm a queued Verified Payout
Once you have created your verified payout session and retrieved your citizenTransactionId you can confirm a payout that is added to queue.
cURL: Confirm payout
curl https://api.yaspa.com/v2/payouts/transaction/confirm/<transaction ID> \
-X POST \
-H AuthorizationCitizen: <your merchant private api key> \
-H Content-Type: application/json \
-H Signature: Base 64 encoded signature \
-H Expires-at: UNIX timestamp for signature expiration
curl https://testapi.yaspa.com/v2/payouts/transaction/confirm/<transaction ID> \
-X POST \
-H AuthorizationCitizen: <your merchant private api key> \
-H Content-Type: application/json \
-H Signature: Base 64 encoded signature \
-H Expires-at: UNIX timestamp for signature expiration
JSON Response: Payout transaction details
{
"citizenTransactionId":<transaction ID>,
"merchantId":<your merchant ID>,
"merchantTradingName":"My merchant",
"customerIdentifier":<your unique identifier for the customer>,
"transactionStatus":"ACCEPTED",
"creationDate":1647010433548,
"citizenCounterPartyId":"622b62816a47c2389498b875",
"providerPaymentId":"296348",
"currency":"GBP",
"paymentGiro":"FPS",
"merchantBankCode":"608384",
"merchantAccountNumber":"40074844",
"merchantBank":"CONTIS",
"counterPartyBank":"CITIZEN_TEST_BANK",
"counterPartyBankCode":"040075",
"counterPartyAccountNumber":"57583676",
"counterPartyAccountName":"YaspaTest Account",
"amount":10.00,
"reference":"Test payment"
}
Headers
Header | Description |
---|---|
AuthorizationCitizen | Your merchant private API key |
Signature | The signature that you sign the request. You can find how to generate the signature here |
Expires-at | The expiration time of the signature on unix timestamp format. |
Path variables
Parameter | Description |
---|---|
citizenTransactionId | String of the transaction ID to process |
Response
Payout transaction details.
Reject a queued Verified Payout
Once you have created your verified payout session and retrieved your citizenTransactionId you can reject a payout that is added to queue.
cURL: Reject payout
curl https://api.yaspa.com/v2/payouts/transaction/reject \
-X POST \
-H AuthorizationCitizen: <your merchant private api key> \
-H Content-Type: application/json \
-H Signature: Base 64 encoded signature \
-H Expires-at: UNIX timestamp for signature expiration \
-d ' {
"citizenTransactionId": "<transactionID>",
"rejectionReason": "the reason why this payout has been rejected"
}'
curl https://testapi.yaspa.com/v2/payouts/transaction/reject \
-X POST \
-H AuthorizationCitizen: <your merchant private api key> \
-H Content-Type: application/json \
-H Signature: Base 64 encoded signature \
-H Expires-at: UNIX timestamp for signature expiration \
-d ' {
"citizenTransactionId": "<transactionID>",
"rejectionReason": "the reason why this payout has been rejected"
}'
JSON Response: Payout transaction details
{
"citizenTransactionId":<transaction ID>,
"merchantId":<your merchant ID>,
"merchantTradingName":"My merchant",
"customerIdentifier":<your unique identifier for the customer>,
"transactionStatus":"CANCELLED_BY_MERCHANT",
"creationDate":1647010433548,
"citizenCounterPartyId":"622b62816a47c2389498b875",
"providerPaymentId":"296348",
"currency":"GBP",
"paymentGiro":"FPS",
"merchantBankCode":"608384",
"merchantAccountNumber":"40074844",
"merchantBank":"CONTIS",
"counterPartyBank":"CITIZEN_TEST_BANK",
"counterPartyBankCode":"040075",
"counterPartyAccountNumber":"57583676",
"counterPartyAccountName":"YaspaTest Account",
"amount":10.00,
"reference":"Test payment"
}
Headers
Header | Description |
---|---|
AuthorizationCitizen | Your merchant private API key |
Signature | The signature that you sign the request. You can find how to generate the signature here |
Expires-at | The expiration time of the signature on unix timestamp format. |
Request
Parameter | Description | Required |
---|---|---|
citizenTransactionId | String of the transaction ID to process | Y |
rejectionReason | String of the reason why the payout has been rejected | N |
Response
Payout transaction details.
Account Management API
Our Account Management API enables you to create and update your Yaspa account, or accounts you manage from your own apps and services.
Register Merchant
When registering your merchant, you must provide a user email and password. This user will be your merchant admin. The trading name you provided will be used in emails or any other Yaspa forms.
cURL: Register Merchant
curl https://api.yaspa.com/v2/merchant/register \
-X POST \
-H Content-Type: application/json \
-d {
email: <Email for the user you want to set as a merchant admin>, \
password: <Password for the user you want to set a merchant admin>, \
tradingName: <Name of merchant used in emails and other Yaspa forms>
}
curl https://testapi.yaspa.com/v2/merchant/register \
-X POST \
-H Content-Type: application/json \
-d {
email: <Email for the merchant admin>, \
password: <Password for the merchant admin>, \
tradingName: <Name of merchant used in emails and other Yaspa forms>
}
Headers
Header | Description |
---|---|
Content-Type | 'application/json' |
Request
Parameter | Description | Required |
---|---|---|
the email address of your administrator (eg admin@yourcompany.com) | Y | |
password | a strong passphrase for your administrator | Y |
tradingName | your merchant's trading name | Y |
Response
Registered merchant details will be returned, you can save these details for future usage.
JSON Response: Registered Merchant Details
{
"id": "<Id of merchant. This merchantId will be used in other requests.>",
"email": "<The email address of your administrator>",
"tradingName": "<Trading name of merchant>",
"apiKeys": "<Your merchant private API key>",
"publicApiKeys": "<Your merchant public API key>",
"merchantUserIds": "<Admin users of the merchant>",
"rootAdminUserId": "<First admin of the merchant>"
}
Get Merchant Details
You will just need to provide your merchantId your merchant private api key.
cURL: Get merchant details
curl https://api.yaspa.com/v2/merchant/{merchantId} \
-X GET \
-H AuthorizationCitizen: <your merchant private api key> \
-H Content-Type: application/json
curl https://testapi.yaspa.com/v2/merchant/{merchantId} \
-X GET \
-H AuthorizationCitizen: <your merchant private api key> \
-H Content-Type: application/json
Headers
Header | Description |
---|---|
AuthorizationCitizen | Your merchant private api key |
Content-Type | 'application/json' |
Response
The merchant details and decrypted bank account details will be returned.
JSON Response: Registered Merchant And Acquiring Account Details
{
"id": "<Id of merchant>",
"email": "<The email address of your administrator>",
"tradingName": "<Trading name of merchant>",
"apiKeys": "<Your merchant private API key>",
"publicApiKeys": "<Your merchant public API key>",
"merchantUserIds": "<Admin users of the merchant>",
"rootAdminUserId": "<First admin of the merchant>",
"payInBankDetails": {
"accountName": "<The account name you provided>",
"accountNumber": "<Decrypted acquiring account number>",
"sortCode": "<Decrypted acquiring account sort code>",
"iban": "<Decrypted acquiring account iban>",
"bic": "<Decrypted acquiring account bic>",
"providerBankAccountId": "<The bank account id that can be identified by provider>",
"providerCustomerId": "<The customer id that can be identified by provider>"
},
"payOutBankDetails": {
"accountName": "<The account name you provided>",
"accountNumber": "<Decrypted acquiring account number>",
"sortCode": "<Decrypted acquiring account sort code>",
"iban": "<Decrypted acquiring account iban>",
"bic": "<Decrypted acquiring account bic>",
"providerBankAccountId": "<The bank account id that can be identified by provider>",
"providerCustomerId": "<The customer id that can be identified by provider>"
}
}
Generate New Merchant API Key
You only need to provide your merchant private api key to make this request. The old api key will still valid. You can get merchant details to check all the api keys you have.
cURL: Generate New Merchant API Key
curl https://api.yaspa.com/v2/merchant/generate-new-api-key \
-X POST \
-H AuthorizationCitizen: <your merchant private api key> \
-H Content-Type: application/json
curl https://testapi.yaspa.com/v2/merchant/generate-new-api-key \
-X POST \
-H AuthorizationCitizen: <your merchant private api key> \
-H Content-Type: application/json
Headers
Header | Description |
---|---|
AuthorizationCitizen | Your merchant private api key |
Content-Type | 'application/json' |
Response
A new merchant private api key will be returned.
String Response: Returned A New Merchant API Key
<new merchant private api key>
Disable Merchant API Key
You need to provide your admin api key and the api key you want to disable to make this request. You can get merchant details to check all the api keys you have.
cURL: Disable Merchant API Key
curl https://api.yaspa.com/v2/merchant/disable-api-key \
-X DELETE \
-H AuthorizationCitizen: <your admin api key> \
-H Content-Type: application/json \
-d { \
'<the api key you want to disable>' \
}
curl https://testapi.yaspa.com/v2/merchant/disable-api-key \
-X DELETE \
-H AuthorizationCitizen: <your admin api key> \
-H Content-Type: application/json \
-d { \
'<the api key you want to disable>' \
}
Headers
Header | Description |
---|---|
AuthorizationCitizen | Your amdin api key |
Content-Type | 'application/json' |
Request
Parameter | Description | Required |
---|---|---|
apiKeyToDisable | the api key you want to disable | Y |
Response
Return an empty body if successfully disable the api key.
Update Pay-In Success Redirect URL
We provide a default URL(https://www.yaspa.com/deposit-processing) if you don't set up the success redirect URL. However, you can use this request to change the URL your customers are sent to when they complete a pay-in. You only need to provide your merchant private api key and a valid redirect URL. You can use get merchant details endpoint to see the payInSuccessRedirect is set to the url you provided.
cURL: Updating pay-in success redirect url
curl https://api.yaspa.com/v2/merchant/pay-in-success-redirect \
-X PATCH \
-H Content-Type: application/json \
-H AuthorizationCitizen: <your merchant private api key> \
-d { \
"url": "https://www.yaspa.com/deposit-processing" \
}
curl https://testapi.yaspa.com/v2/merchant/pay-in-success-redirect \
-X PATCH \
-H Content-Type: application/json \
-H AuthorizationCitizen: <your merchant private api key> \
-d { \
"url": "https://www.yaspa.com/deposit-processing" \
}
Headers
Header | Description |
---|---|
AuthorizationCitizen | Your merchant private api key |
Content-Type | 'application/json' |
Request
Parameter | Description | Type | Required |
---|---|---|---|
url | the webpage your customers are sent to after a success pay-in | String | Y |
Update Pay-In Failure Redirect URL
We provide a default URL(https://www.yaspa.com/deposit-processing) if you don't set up the failure redirect URL. However, you can use this request to change the URL your customers are sent to when a pay-in failed. You only need to provide your merchant private api key and a valid redirect URL. You can use get merchant details endpoint to see the payInFailureRedirect is set to the url you provided.
cURL: Updating pay-in failure redirect url
curl https://api.yaspa.com/v2/merchant/pay-in-failure-redirect \
-X PATCH \
-H Content-Type: application/json \
-H AuthorizationCitizen: <your merchant private api key> \
-d { \
"url": "https://www.yaspa.com/deposit-processing" \
}
curl https://testapi.yaspa.com/v2/merchant/pay-in-failure-redirect \
-X PATCH \
-H Content-Type: application/json \
-H AuthorizationCitizen: <your merchant private api key> \
-d { \
"url": "https://www.yaspa.com/deposit-processing" \
}
Headers
Header | Description |
---|---|
AuthorizationCitizen | Your merchant private api key |
Content-Type | 'application/json' |
Request
Parameter | Description | Type | Required |
---|---|---|---|
url | the webpage your customers are sent to after a pay-in failed | String | Y |
Update Account Verification Success Redirect URL
We provide a default URL(https://www.yaspa.com/deposit-processing) if you don't set up the success redirect URL. However, you can use this request to change the URL your customers are sent to when they complete an account verification. You only need to provide your merchant private api key and a valid redirect URL. You can use get merchant details endpoint to see the accountVerificationSuccessRedirect is set to the url you provided.
cURL: Updating account verification success redirect url
curl https://api.yaspa.com/v2/merchant/account-verification-success-redirect \
-X PATCH \
-H Content-Type: application/json \
-H AuthorizationCitizen: <your merchant private api key> \
-d { \
"url": "https://www.yaspa.com/deposit-processing" \
}
curl https://testapi.yaspa.com/v2/merchant/account-verification-success-redirect \
-X PATCH \
-H Content-Type: application/json \
-H AuthorizationCitizen: <your merchant private api key> \
-d { \
"url": "https://www.yaspa.com/deposit-processing" \
}
Headers
Header | Description |
---|---|
AuthorizationCitizen | Your merchant private api key |
Content-Type | 'application/json' |
Request
Parameter | Description | Type | Required |
---|---|---|---|
url | the webpage your customers are sent to after a success account verification | String | Y |
Update Account Verification Failure Redirect URL
We provide a default URL(https://www.yaspa.com/deposit-processing) if you don't set up the failure redirect URL. However, you can use this request to change the URL your customers are sent to when the account verification failed. You only need to provide your merchant private api key and a valid redirect URL. You can use get merchant details endpoint to see the accountVerificationFailureRedirect is set to the url you provided.
cURL: Updating account verification failure redirect url
curl https://api.yaspa.com/v2/merchant/account-verification-failure-redirect \
-X PATCH \
-H Content-Type: application/json \
-H AuthorizationCitizen: <your merchant private api key> \
-d { \
"url": "https://www.yaspa.com/deposit-processing" \
}
curl https://testapi.yaspa.com/v2/merchant/account-verification-failure-redirect \
-X PATCH \
-H Content-Type: application/json \
-H AuthorizationCitizen: <your merchant private api key> \
-d { \
"url": "https://www.yaspa.com/deposit-processing" \
}
Headers
Header | Description |
---|---|
AuthorizationCitizen | Your merchant private api key |
Content-Type | 'application/json' |
Request
Parameter | Description | Type | Required |
---|---|---|---|
url | the webpage your customers are sent to after account verification failed | String | Y |
Update Payout Success Redirect URL
We provide a default URL(https://www.yaspa.com/deposit-processing) if you don't set up the success redirect URL. However, you can use this request to change the URL your customers are sent to when they complete a payout. You only need to provide your merchant private api key and a valid redirect URL. You can use get merchant details endpoint to see the payoutRedirect is set to the url you provided.
cURL: Updating payout success redirect url
curl https://api.yaspa.com/v2/merchant/payout-success-redirect \
-X PATCH \
-H Content-Type: application/json \
-H AuthorizationCitizen: <your merchant private api key> \
-d { \
"url": "https://www.yaspa.com/deposit-processing" \
}
curl https://testapi.yaspa.com/v2/merchant/payout-success-redirect \
-X PATCH \
-H Content-Type: application/json \
-H AuthorizationCitizen: <your merchant private api key> \
-d { \
"url": "https://www.yaspa.com/deposit-processing" \
}
Headers
Header | Description |
---|---|
AuthorizationCitizen | Your merchant private api key |
Content-Type | 'application/json' |
Request
Parameter | Description | Type | Required |
---|---|---|---|
url | the webpage your customers are sent to after a success payout | String | Y |
Update Payout Failure Redirect URL
We provide a default URL(https://www.yaspa.com/deposit-processing) if you don't set up the failure redirect URL. However, you can use this request to change the URL your customers are sent to when a payout failed. You only need to provide your merchant private api key and a valid redirect URL. You can use get merchant details endpoint to see the payoutFailureRedirect is set to the url you provided.
cURL: Updating payout failure redirect url
curl https://api.yaspa.com/v2/merchant/payout-failure-redirect \
-X PATCH \
-H Content-Type: application/json \
-H AuthorizationCitizen: <your merchant private api key> \
-d { \
"url": "https://www.yaspa.com/deposit-processing" \
}
curl https://testapi.yaspa.com/v2/merchant/payout-failure-redirect \
-X PATCH \
-H Content-Type: application/json \
-H AuthorizationCitizen: <your merchant private api key> \
-d { \
"url": "https://www.yaspa.com/deposit-processing" \
}
Headers
Header | Description |
---|---|
AuthorizationCitizen | Your merchant private api key |
Content-Type | 'application/json' |
Request
Parameter | Description | Type | Required |
---|---|---|---|
url | the webpage your customers are sent to after a payout failed | String | Y |
Add Merchant Webhook
You need to provide which event types to be posted to the url(webhook), and your merchant private api key.
cURL: Add webhooks for the merchant
curl https://api.yaspa.com/v2/merchant/webhook \
-X PATCH \
-H Content-Type: application/json \
-H AuthorizationCitizen: <your merchant private api key> \
-d { \
"eventTypes": ["PAYIN_CREATED"], \
"url": "www.yaspa.com", \
"version": "2" \
}
curl https://testapi.yaspa.com/v2/merchant/webhook \
-X PATCH \
-H Content-Type: application/json \
-H AuthorizationCitizen: <your merchant private api key> \
-d { \
"eventTypes": ["PAYIN_CREATED"], \
"url": "www.yaspa.com", \
"version": "2" \
}
Event Type
Event Type Name |
---|
PAYIN_CREATED |
PAYIN_REDIRECT |
PAYIN_DECISION |
PAYIN_ERROR |
PAYOUT_CREATED |
PAYOUT_ACCEPTED |
PAYOUT_QUEUED |
PAYOUT_ERROR |
PAYOUT_REJECTED |
ACCOUNT_VERIFICATION_CREATED |
ACCOUNT_VERIFICATION_DECISION |
ACCOUNT_VERIFICATION_REDIRECT |
ACCOUNT_VERIFICATION_ERROR |
Remove Merchant Webhook
You need to provide the webhook url that you would like to be removed.
cURL: Remove webhooks for the merchant
curl https://api.yaspa.com/v2/merchant/webhook \
-X DELETE \
-H Content-Type: application/json \
-H AuthorizationCitizen: <your merchant private api key> \
-d '<webhookUrl>'
curl https://testapi.yaspa.com/v2/merchant/webhook \
-X DELETE \
-H Content-Type: application/json \
-H AuthorizationCitizen: <your merchant private api key> \
-d '<webhookUrl>'
Headers
Header | Description |
---|---|
AuthorizationCitizen | Your merchant private api key |
Content-Type | 'application/json' |
Request
Parameter | Description | Type | Required |
---|---|---|---|
url | the url that will be removed from the webhooks | String | Y |
Corporate Account API
Our Corporate Account API enables you to get your corporate account information and transactions.
Get corporate accounts
You can get your corporate accounts linked to your merchant using your merchant private api key.
cURL: Get Corporate accounts
curl https://api.yaspa.com/v2/corporate-account/merchant/corporate-accounts \
-X GET \
-H Content-Type: application/json \
-H AuthorizationCitizen: <your merchant private api key> \
curl https://testapi.yaspa.com/v2/corporate-account/merchant/corporate-accounts \
-X GET \
-H Content-Type: application/json \
-H AuthorizationCitizen: <your merchant private api key> \
Headers
Header | Description |
---|---|
AuthorizationCitizen | Your merchant private api key |
Content-Type | 'application/json' |
Response
The API response is your merchant corporate account.
String Response: your merchant corporate account
{
"accountId": "<the id of the account>",
"merchantDescription": "<friendly name of the account>",
"customerNumber": "<the id of the owner>",
"accountNumber": "<the account number or iban depending the giro>",
"bankCode": "<sort code or bic depending the giro>",
"giro": "<the giro of the account>",
"currency": "<the currency of the account>",
"balance": "<the available balance of the account>",
"providerBankAccountId": "<the provide identifier of the account>",
"accountHolderName": "<the account holder name of the account>"
}
Get corporate account transactions
You can get your corporate account transaction using your merchant private api key, and the provider bank account Id.
cURL: Get Corporate Account Transactions
curl https://api.yaspa.com/v2/corporate-account/transactions/<providerBankAccountId> \
-X GET \
-H Content-Type: application/json \
-H AuthorizationCitizen: <your merchant private api key> \
curl https://testapi.yaspa.com/v2/corporate-account/transactions/<providerBankAccountId> \
-X GET \
-H Content-Type: application/json \
-H AuthorizationCitizen: <your merchant private api key> \
Headers
Header | Description |
---|---|
AuthorizationCitizen | Your merchant private api key |
Content-Type | 'application/json' |
Request Path Variables
Parameter | Description |
---|---|
providerBankAccountId | The identifier of the account on provider's system |
Request Query Parameters
Parameter | Description | Type | Required |
---|---|---|---|
page | The page number for the pagination | Integer | Y |
size | The size of the page (max 200) | Integer | Y |
dateFrom | The date from when the transaction were created (e.g. 2022-01-25) default time of 00:00) | String | N |
dateTo | The date up to when the transaction were created (e.g. 2022-02-30) default time of 00:00 | String | N |
Response
The API response is a list of corporate account transactions.
Parameter | Description | Type |
---|---|---|
description(Deprecated) | This the short reference of the payment | String |
reference | This the reference of the payment | String |
transactionType | The transaction type. The list of all the transaction types can be found here | String |
transactionId | The ID representing the transaction within the bank account(not necessary the same as CitizenTransactionId) | String |
clientReferenceNumber(Deprecated) | This is the transaction id of the payment | String |
transactionAmount | The transaction amount of the payment | String |
transactionCurrency | The currency | String with valid ISO currency code |
counterPartyFirstName | The first name of the requester | String |
counterPartyLastName | The last name of the requester | String |
transactionDate | The date when the transaction were created (e.g. 2021-02-04T13:28:07.397Z) | String |
debit | Shows if the transaction is debit or not. | Boolean |
List of the corporate account transactions
{
"content": [
{
"reference": "<the reference of the transaction>",
"transactionType": "<the type of the transaction>",
"transactionId": "<the id of the transaction>",
"transactionAmount": "<the amount of the transaction>",
"transactionCurrency": "<the currency of the transaction>",
"counterPartyFirstName": "<the first name of the person that created the transaction>",
"counterPartyLastName": "<the last name of the person that created the transaction>",
"transactionDate": "<the creation date of the transaction>",
"debit": "<shows if the transaction is debit or not>"
}
],
"totalPages": "<total pages number>"
}
Available transaction types
Value | Description |
---|---|
PAYIN | Money coming in from an external account |
PAYOUT | Money coming out from an external account |
TRANSFER | Money transferred internally between Yaspa accounts |
Download corporate account transactions by CurrencyCode
Use your merchant private api key and specify the currency of your corporate account, then you can download all the matched transactions of that corporate account. Currently, we only support GBP and EUR currency.
cURL: Download corporate account transactions by CurrencyCode
curl https://api.yaspa.com/v2/corporate-account/transactions/currency/{currencyCode}/generate-csv \
-X POST \
-H Content-Type: application/json \
-H AuthorizationCitizen: <your merchant private api key> \
-d '{
dateFrom: 2023-01-01,
dateTo: 2023-02-01,
amountFrom: 1.00,
amountTo: 10.00
}'
curl https://testapi.yaspa.com/v2/corporate-account/transactions/currency/{currencyCode}/generate-csv \
-X POST \
-H Content-Type: application/json \
-H AuthorizationCitizen: <your merchant private api key> \
-d '{
dateFrom: 2023-01-01,
dateTo: 2023-02-01,
amountFrom: 1.00,
amountTo: 10.00
}'
Headers
Header | Description |
---|---|
AuthorizationCitizen | Your merchant private api key |
Content-Type | 'application/json' |
Request
Parameter | Description | Type | Required |
---|---|---|---|
dateFrom | The date from when the transaction were created (e.g. 2022-01-25) default time of 00:00) | String | N |
dateTo | The date up to when the transaction were created (e.g. 2022-02-30) default time of 00:00 | String | N |
amountFrom | Filter out the transactions less than this amount | string with valid 2 decimal number format | N |
amountTo | Filter out the transactions more than this amount | string with valid 2 decimal number format | N |
Response
The API response includes the csv file name and base64 string. Please refer to the code snippet about how to convert the base64 string to csv either in your backend or frontend.
Json Response: the csv filename and Base64 string
{
"filename": "<fileName>.csv",
"data": "<Base64 String>"
}
Kotlin: Convert base64 to csv in your backend
val base64String = "TWVyY2hhbnQgSWQsUmVmZXJlbmNlLFRyYW5zYWN0aW9uIFR5cGUsUHJvdmlkZXIgVHJhbnNhY3Rpb24gSWQsVHJhbnNhY3Rpb24gQW1vdW50LFRyYW5zYWN0aW9uIEN1cnJlbmN5LE5hbWUsVHJhbnNhY3Rpb24gRGF0ZSxBY2NvdW50IEJhbGFuY2UsQ2l0aXplbiBUcmFuc2FjdGlvbiBJZAo2MmRhOGE4OThlYTk5YTUwYzJjMDMwMWMsMCwwLDAsMCwwLDAsMCwwLDA="
val csvFile = File("output.csv")
val decodedBytes = Base64.getDecoder().decode(base64String)
val csvString = String(decodedBytes, Charsets.UTF_8)
BufferedWriter(FileWriter(csvFile)).use {
writer -> writer.write(csvString)
}
Java: Convert base64 to csv in your backend
String base64String = "TWVyY2hhbnQgSWQsUmVmZXJlbmNlLFRyYW5zYWN0aW9uIFR5cGUsUHJvdmlkZXIgVHJhbnNhY3Rpb24gSWQsVHJhbnNhY3Rpb24gQW1vdW50LFRyYW5zYWN0aW9uIEN1cnJlbmN5LE5hbWUsVHJhbnNhY3Rpb24gRGF0ZSxBY2NvdW50IEJhbGFuY2UsQ2l0aXplbiBUcmFuc2FjdGlvbiBJZAo2MmRhOGE4OThlYTk5YTUwYzJjMDMwMWMsMCwwLDAsMCwwLDAsMCwwLDA=";
File csvFile = new File("output.csv");
byte[] decodedBytes = Base64.getDecoder().decode(base64String);
String csvString = new String(decodedBytes, "UTF-8");
try (BufferedWriter writer = new BufferedWriter(new FileWriter(csvFile))) {
writer.write(csvString);
} catch (IOException e) {
e.printStackTrace();
}
Javascript: Convert base64 to csv to a downloadable link in the browser
export const download = (filename, data) => {
let element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;base64,' + data);
element.setAttribute('download', filename);
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
Redirects
Throughout our multiple journeys, there are a number of points where we provide you the ability to redirect your users to a customisable url. In general there are 3 types of redirects:
Redirecting from the page that the SDK modal is shown on. (This is the case for either the QR code or Email journey. This is not available for direct mobile journeys)
A redirect from the user’s banking app once they have approved/declined a request.
A redirect for our “bank unavailable“ button which is shown on the bank selection page. This is used when the customer's bank is not in the bank selector list, either because it is not using Open Banking protocol or we are in progress of integrating it.
Configure SDK modal redirects
You can configure the success and failure redirects for the page that the modal is shown when you send the request to create the session for each journey (payins/account-verification/verified-payins/payouts)
The success redirect is used when a journey is successfully authorised and accepted.
The failure redirect is used when the journey fails. This can be due to an internal server error, error submitting to the bank, cancelled by the user, etc.
PayIn SDK redirect
You can check the payin session creation section to see the request and the attributes for this.
Verified PayIn SDK redirect
You can check the verified payin session creation section to see the request and the attributes for this.
Account Verification SDK redirect
You can check the account verification session creation section to see the request and the attributes for this.
Payout SDK redirect
You can check the payout session creation section to see the request and the attributes for this.
Configure bank redirects
You can configure where the user will be redirected to when they authorise or reject a transaction from their banking app
The user will redirect to the (use the exact name in the dashboard) url if the transaction is successfully authorised within the bank app.
If for any reason the request fails to go through, the failure redirect will be used.
Failure reasons are:
Internal server error
External errors
User cancelled the journey
Dynamic Bank Redirects
These are dynamic redirects where your user will be redirected to from their banking app. These will override your default bank redirects. If these are not set, we will use the default redirects instead.
You set these dynamic bank redirects on session creation:
PayIn Bank Redirect
You can check the payin session creation section to see the request and the attributes for this.
Verified PayIn Bank Redirect
You can check the verified payin session creation section to see the request and the attributes for this.
Account Verification Bank Redirect
You can check the account verification session creation section to see the request and the attributes for this.
Payout Bank Redirect
You can check the payout session creation section to see the request and the attributes for this.
Configure Default Payin Bank Redirects
To configure your pay-in processing and failure redirects, you need to go to the Yaspa Admin Dashboard, under Company Settings in the tab PayIn settings. The field "Payment Authorization Processing Url" and "Payment Failure Authorization url" are the processing and failure redirect urls respectively.
There fields applied to the verified payin journey on the payment part of the journey.
Configure Default Account Verification Bank Redirects
To configure Account Verification processing and failure redirect you need to go to Yaspa Admin Dashboard, under Company Settings in the tab Account Verification Settings. The field "Account Verification Authorization Processing Url" and "Account Verification Failure Authorization url" are the processing and failure redirect urls respectively.
The field "Account Verification Failure Authorization url" will apply to verified payIn and payout journey on the verification part of the journey.
Configure Default Payout Bank Redirects
To configure Payout processing and failure redirect you need to go to Yaspa Admin Dashboard, under Company Settings in the tab Payout Settings. The field "Payout Authorization Processing Url" and "Payout Failure Authorization url" are the processing and failure redirect urls respectively.
There fields will be applied in payout journey on the submission of the payout.
Configure bank unavailable redirects
You can set a custom redirect to take the user to if their bank is not available. The default value is https://www.yaspa.com/bank-not-available.
Configure Payin Bank Unavailable Redirect
To configure the pay-in bank unavailable url redirect you need to go to Yaspa Admin Dashboard, under Company Settings in the tab PayIn settings. The field "Bank unavailable fallback Url" is the bank unavailable redirect url.
Configure Account Verification Bank Unavailable Redirect
To configure Account Verification bank unavailable url redirect you need to go to Yaspa Admin Dashboard, under Company Settings in the tab Account Verification settings. The field "Account Verification Bank Unavailable Fallback Url" is the bank unavailable redirect url.
The field "Account Verification Bank Unavailable Fallback Url" will apply to verified payIn on the verification part of the journey.
Configure Payout Bank Unavailable Redirect
To configure Payout bank unavailable url redirect you need to go to Yaspa Admin Dashboard, under Company Settings in the tab Payout Settings. The field "Payout Bank Unavailable Fallback Url" is the bank unavailable redirect url.
The field "Payout Bank Unavailable Fallback Url" will apply to payout on the verification part of the journey.
Withdrawals
Withdrawals allow funds to be transferred to external bank accounts for business processes such as acquiring funds, transfers to another merchant or similar. They differ from verified payouts in that the payout bank account does not need to be verified by its owner - its details are instead sent by a signed REST call from the merchant's back end.
Creating Counter Party
The first step to make withdrawals is to create a counter party. This request is typically created from your back end. The request uses your merchant private API key (from your admin dashboard) and the body must be signed with the signature set as a request header.
cURL: Create Counter Party
curl https://api.yaspa.com/v2/corporate-account/admin-counter-party \
-X POST
-H "AuthorizationCitizen: <your merchant private api key>" \
-H "Signature: <request signature>" \
-H "Expires-at: <signture expiry unix timestamp>" \
-d '{
"customerIdentifier": "1846593725421829",
"bankCountry": "GB",
"accountGiro": "FPS",
"accountCurrency": "GBP",
"accountName": "Internal Account",
"accountNumber": "12345678",
"bankCode": "010203",
"counterPartyBank": "OPENPAYD",
"customerType": "CORPORATE"
}'
curl https://testapi.yaspa.com/v2/corporate-account/admin-counter-party \
-X POST
-H "AuthorizationCitizen: <your merchant private api key>" \
-H "Signature: <request signature>" \
-H "Expires-at: <signture expiry unix timestamp>" \
-d '{
"customerIdentifier": "1846593725421829",
"bankCountry": "GB",
"accountGiro": "FPS",
"accountCurrency": "GBP",
"accountName": "Internal Account",
"accountNumber": "12345678",
"bankCode": "010203",
"counterPartyBank": "OPENPAYD",
"customerType": "CORPORATE"
}'
Headers
Header | Description |
---|---|
AuthorizationCitizen | Your merchant private api key |
Signature | Base 64 encoded signature |
Expires-at | UNIX timestamp for signature expiration |
Content-Type | 'application/json' |
Request
Parameter | Description | Type | Required |
---|---|---|---|
customerIdentifier | The internal id you use on your systems to identity your user | string | Y |
bankCountry | The jurisdiction of the counter party account. it should follow the country ISO codes. For example supported countries are [GB], [IE], [NL] | String | Y |
accountGiro | Payment rail for the counter party bank account. Depending of the currency of the transaction it can be either FPS (UK faster payments) or SEPA (EU SEPA Inst) | String | Y |
accountCurrency | Counter party account currency. The supported currencies are "GBP" and "EUR". | String | Y |
accountName | Account name of the counter party | String | Y |
accountNumber | For transaction within the UK the sort code or for EUR the iban for the counter party | String | Y |
bankCode | The counter party sort code/bic | String | Y |
counterPartyBank | Bank of the counter party. If this account was created via a third party such as OPENPAYD, then this should be set to "OPENPAYD". | String | Y |
customerType | Type of the counter party. If this account is used for withdrawal in admin dashboard, then this should be set to "CORPORATE". Otherwise, using "RETAIL" for regular payouts | String | Y |
Response
JSON Response: Create Counter Party
{
"counterPartyId": "62a5ff6a5410953586eea940",
"merchantId": "62a325fed1b29b74d10791b9",
"payoutProviderCustomerId": "7bfe1fb4-70ff-480f-83a1-ef8df3ad4d01",
"payoutProviderAccountId": "clJVZ003Q2RzWnc5cC90ZFdZQ2Z1UT09",
"customerType": "CORPORATE",
"customerIdentifier": "1846593725421829",
"bankCountry": "GB",
"accountCurrency": "GBP",
"accountGiro": "FPS",
"accountNumber": "73200505",
"bankCode": "231470",
"accountName": "test Company",
"merchantBank": "OPENPAYD",
"counterPartyBank": "OPENPAYD"
}
Authentication
Using the API
Yaspa generates two different types of authentication.
- Private API key
This is used to authenticate with the Yaspa API.
- Public API key
This is used by the front end SDK to initiate any instructions created by your back end.
API key
This API key is generated on account creation.
You can find your merchant API key in the API Keys section of your admin dashboard.
If you are using our API directly, these keys are returned in the register merchant response.
Public API key
The public API key is generated on account creation.
You can find your merchant public API key in the API Keys section of your admin dashboard.
If you are using our API directly, these keys are returned in the register merchant response.
Use this key for your front end implementation.
Signatures
Signatures provide authentication and also integrity protection. Part of our supported functionality requires the merchant to sign certain requests. In that way it is possible to verify that the request has originated from the right merchant but also provide data integrity.
Create a Public/Private Key Pair
Bash: Generate private key
openssl genpkey -algorithm RSA -outform PEM -out private_key.pem -pkeyopt rsa_keygen_bits:2048
A prerequisite for signing any request is to generate an RSA 2048 keypair using OpenSSL.
By executing the first block, a 2048 bit RSA key named private_key.pem
is generated, which will be the private key.
Bash: Generate public key
openssl rsa -in private_key.pem -pubout -out public_key.pub
The second step is generating a public key based on the private key. This can be easily done by executing the second block of code, which will generate a public key named public_key.pub
Register your Public Key
For our system to be able to verify your payout requests, the public component of the openssl RSA key is used to sign the requests. This key should be registered on our system through the admin dashboard.
Request Authorisation Token
An authorisation token will be provided by Yaspa for the merchant to be able to start the payout journey. When the token is provided to you, you can submit it on the admin dashboard under the payout section.
Register Google authenticator
Once the token has been entered, you will need to set up Google authenticator to make sure the key cannot be easily changed.
Register Public component
Once Google Authenticator has been setup, you can register the public key from your RSA key pair that you will use to sign requests.
No Authorisation token
If there isn't any authorisation token registered for your entity, you need to ask for one from Yaspa and try again after receiving it.
Signing requests
Java: Signing a request
public class CounterPartyDetails implements Serializable{
private static final long serialVersionUID = 212345678976543211L;
private String customerIdentifier; // The internal id you use on your systems to identity your use
private String bankCountry; // GB or EUR countires
private String accountGiro; //Either FPS or SEPA
private String accountCurrency; // GPB or EUR
private String accountName; // Account name of the counter party
private String accountNumber; // Bank account number of the counter party
private String bankCode; //Either SORT CODE or BIC
private String counterPartyBank; // OPENPAYD or third party
private String customerType; // Either COPRORATE or RETAIL
}
@RestController
@RequestMapping(value = "add-counterparty-endpoint")
public class AddCounterParty {
//Your backend will then make a request to the Yaspa service to add a counterparty.
@RequestMapping(method = RequestMethod.POST, path = "/your-example-add-counterparty-endpoint")
public Callable<ResponseEntity<TextNode>> addCounterParty(TransactionDetails details) {
CounterPartyDetails counterPartyDetails = new CounterPartyDetails();
counterPartyDetails.setCustomerIdentifier("1846593725421829");//
counterPartyDetails.setbankCountry("GB");
counterPartyDetails.setPaymentGiro(PaymentGiro.FPS);
counterPartyDetails.setCurrency("GBP");
counterPartyDetails.setAccountName("Internal Account");
counterPartyDetails.setAccountNumber("12345678");
counterPartyDetails.setbankCode("010203");
counterPartyDetails.setCounterPartyBank("OPENPAYD");
counterPartyDetails.setcustomerType("CORPORATE");
RestTemplate restTemplate = new RestTemplate();
String citizenAddCounterpartyUrl = "https://api.yaspa.com/v2/corporate-account/admin-counter-party";
HttpHeaders httpHeaders = generateHeadersForSignedRequest(HttpMethod.POST,
citizenAddCounterpartyUrl,
counterPartyDetails,
DB.getPrivateKey);
httpHeaders.set("AuthorizationCitizen", [YOUR_ENTITY_API_KEY]]);
ResponseEntity<TextNode> payoutInitResponse = restTemplate
.exchange(citizenAddCounterpartyUrl, HttpMethod.POST,
new HttpEntity<>(counterPartyDetails, httpHeaders), TextNode.class);
return ResponseEntity.ok(); //Return this to your front end
}
}
private HttpHeaders generateHeadersForSignedRequest (
HttpMethod httpMethod, String url, Object requestBody, PrivateKey privateKey)
throws JsonProcessingException, SignatureException {
String requestExpiryTime = String.valueOf(Instant.now().getEpochSecond() + 300);
String textToSign = requestExpiryTime + "|" + httpMethod.name().toUpperCase() + "|" + url + "|";
if (requestBody != null) {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
ObjectWriter objectWriter = objectMapper.writer();
String requestJson = objectWriter.writeValueAsString(requestBody);
textToSign += requestJson;
}
String signature = generateSignature(textToSign, privateKey);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("Signature", signature);
httpHeaders.set("Expires-at", requestExpiryTime);
return httpHeaders;
}
private String generateSignature(String plainText, PrivateKey privateKey)
throws SignatureException {
try {
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(plainText.getBytes("UTF8"));
byte[] valueSigned = signature.sign();
return Base64.getEncoder().encodeToString(valueSigned);
} catch (NoSuchAlgorithmException | InvalidKeyException | UnsupportedEncodingException e) {
throw new SignatureException(e);
}
}
public class CounterPartyDetails implements Serializable{
private static final long serialVersionUID = 212345678976543211L;
private String customerIdentifier; // The internal id you use on your systems to identity your use
private String bankCountry; // GB or EUR countires
private String accountGiro; //Either FPS or SEPA
private String accountCurrency; // GPB or EUR
private String accountName; // Account name of the counter party
private String accountNumber; // Bank account number of the counter party
private String bankCode; //Either SORT CODE or BIC
private String counterPartyBank; // OPENPAYD or third party
private String customerType; // Either COPRORATE or RETAIL
}
@RestController
@RequestMapping(value = "add-counterparty-endpoint")
public class AddCounterParty {
//Your backend will then make a request to the Yaspa service to add a counterparty.
@RequestMapping(method = RequestMethod.POST, path = "/your-example-add-counterparty-endpoint")
public Callable<ResponseEntity<TextNode>> addCounterParty(TransactionDetails details) {
CounterPartyDetails counterPartyDetails = new CounterPartyDetails();
counterPartyDetails.setCustomerIdentifier("1846593725421829");//only needed for email journey
counterPartyDetails.setbankCountry("GB");
counterPartyDetails.setPaymentGiro(PaymentGiro.FPS);
counterPartyDetails.setCurrency("GBP");
counterPartyDetails.setAccountName("Internal Account");
counterPartyDetails.setAccountNumber("12345678");
counterPartyDetails.setbankCode("010203");
counterPartyDetails.setCounterPartyBank("OPENPAYD");
counterPartyDetails.setcustomerType("CORPORATE");
RestTemplate restTemplate = new RestTemplate();
String citizenAddCounterpartyUrl = "https://testapi.yaspa.com/v2/corporate-account/admin-counter-party";
HttpHeaders httpHeaders = generateHeadersForSignedRequest(HttpMethod.POST,
citizenAddCounterpartyUrl,
counterPartyDetails,
DB.getPrivateKey);
httpHeaders.set("AuthorizationCitizen", [YOUR_ENTITY_API_KEY]]);
ResponseEntity<TextNode> payoutInitResponse = restTemplate
.exchange(citizenAddCounterpartyUrl, HttpMethod.POST,
new HttpEntity<>(counterPartyDetails, httpHeaders), TextNode.class);
return ResponseEntity.ok(); //Return this to your front end
}
}
private HttpHeaders generateHeadersForSignedRequest (
HttpMethod httpMethod, String url, Object requestBody, PrivateKey privateKey)
throws JsonProcessingException, SignatureException {
String requestExpiryTime = String.valueOf(Instant.now().getEpochSecond() + 300);
String textToSign = requestExpiryTime + "|" + httpMethod.name().toUpperCase() + "|" + url + "|";
if (requestBody != null) {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
ObjectWriter objectWriter = objectMapper.writer();
String requestJson = objectWriter.writeValueAsString(requestBody);
textToSign += requestJson;
}
String signature = generateSignature(textToSign, privateKey);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("Signature", signature);
httpHeaders.set("Expires-at", requestExpiryTime);
return httpHeaders;
}
private String generateSignature(String plainText, PrivateKey privateKey)
throws SignatureException {
try {
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(plainText.getBytes("UTF8"));
byte[] valueSigned = signature.sign();
return Base64.getEncoder().encodeToString(valueSigned);
} catch (NoSuchAlgorithmException | InvalidKeyException | UnsupportedEncodingException e) {
throw new SignatureException(e);
}
}
The action of signing requires the merchant private key.The signature is valid until a given expiry time set by the merchant (max 10 minutes from the time the request is made).
The signature plain text is generated by concatenating the request components, each one separated by the '|' delimiter:
expiryTime | httpMethod | url | requestBody
If the request body is not present in the request then the signature plain text is as follows:
expiryTime | httpMethod | url |
Component | Description |
---|---|
expiryTime | Integer UNIX timestamp for signature expiry time |
httpMethod | String HTTP method (GET, POST etc) in upper case |
url | String URL of the endpoint |
requestBody | String representation of the JSON request body if present |
An example of the signature plain text is as follows
1613639354|POST|https://api.yaspa.com/v2/corporate-account/admin-counter-party"|{"customerIdentifier":"1846593725421829","bankCountry":"GB","accountGiro":"FPS","accountCurrency":"GBP","accountName":"Internal Account","accountNumber":"12345678","bankCode":"010203","counterPartyBank":"OPENPAYD","customerType":"CORPORATE"}
1613639354|POST|https://testapi.yaspa.com/v2/corporate-account/admin-counter-party"|{"customerIdentifier":"1846593725421829","bankCountry":"GB","accountGiro":"FPS","accountCurrency":"GBP","accountName":"Internal Account","accountNumber":"12345678","bankCode":"010203","counterPartyBank":"OPENPAYD","customerType":"CORPORATE"}
The signature plain text is signed by an RSA 2048 bit key, the public part of which will have been registered on the Yaspa service in advance. It is base 64 encoded and set in a header.
Webhooks
Webhooks are JSON objects that Yaspa posts back to your merchant endpoints.
Configuring the webhooks you receive can be done in your merchant dashboard.
Webhook Signatures
All webhook updates will contain a signature of the transaction details which you can verify by the using of our public key. You get the public key with a simple GET call to /v2/merchant/citizen-signing-public-key
- For signing we use SHA256 with RSA
- You can get the public RSA key from https://api.yaspa.com/v2/merchant/citizen-signing-public-key (or testapi.yaspa.com for test)
The signature can be found under the "Citizen-Signature" header of the request.
Verify Webhook Signature
Javascript: Verify Webhook Signature
const citizenPublicKey = "CITIZEN_PK";
// data is the data key of the webhook payload in webhooks
const verifySignature = (data, signature) => {
const dataToVerify = JSON.stringify(data)
//Convert the public key in base 64 (DER encoded) to array buffer
let publicKeyAB = stringToArrayBuffer(atob(citizenPublicKey));
const pubKey = crypto.createPublicKey({key: publicKeyAB, format: 'der', type: 'spki'})
const verifySignatureFunction = crypto.createVerify('RSA-SHA256')
verifySignatureFunction.update(dataToVerify, 'utf8');
verifySignatureFunction.end()
let verified = verifySignatureFunction.verify(pubKey, signature, "base64");
}
Java: Verify Webhook Signature
String citizenPublicKey = "CITIZEN_PK";
String webhookData = "WEBHOOKDATA";
String webhookSignature = "WEBHOOKSIGNATURE";
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(citizenPublicKey));
PublicKey key = keyFactory.generatePublic(publicKeySpec);
Signature verifySignatureFunction = Signature.getInstance("SHA256withRSA");
verifySignatureFunction.initVerify(key);
verifySignatureFunction.update(webhookData.getBytes("utf-8"));
Boolean verified = verifySignatureFunction.verify(Base64.getDecoder().decode(webhookSignature));
- Get the Yaspa Public Signing Key
- Decode the public key to
UTF-8
fromBase64
- Generate a public key using the
decoded key
extracted from step 2 - Create a Signature Verification
function/object
with algorithmRSA-SHA256
- Pass the generated public key
- Pass the Web Hook Data encoded as
UTF-8
- Verify the result by passing the Webhook Signature
Pay-In Webhook Format
JSON: Pay-In Webhook Response
{
"type":"<the event type of a webhook>",
"data": {
"citizenTransactionId": "<Citizen transaction id>",
"merchantId": "<The id of your merchant>",
"merchantTradingName": "<The trading name of your merchant>",
"customerIdentifier": "<Customer id on your system>",
"customerAccountNumber": "<the account number of the customer used in verified payin>",
"customerBankCode": "<the bank code of the customer used in verified payin>",
"customerName": "<the account holder name of the customer used in verified payin>",
"version": "<Version of api>",
"journeyType": "<Type of this pay-in journey. eg. EMAIL>",
"transactionStatus": "<Current status of this transaction. eg. INITIATED>",
"searchableText": "<A string that you can use to search for this pay-in>",
"creationDate": "<Date of creation>",
"paymentMethod": "<Method of payment, e.g. OPEN_BANKING>",
"merchantAccountNumber": "<The account number of your merchant>",
"merchantBankCode": "<The bank code of your merchant>",
"reference": "<The reference given to the payin>",
"paymentGiro": "<PaymentGiro, e.g. FPS>",
"paymentAmount": "<The amount of the payment>",
"paymentCurrency": "<The currency of the payment>",
"description": "<The description given to the payin>",
"customerEmailAddress": "<The customers email address>",
"payload": "<the meta-data of the payin>",
"payloadEncrypted": "<Boolean value indicated that the payload is encrypted or not>"
}
}
Pay-In Transaction
Parameter | Description |
---|---|
citizenTransactionId | Citizen transaction id |
merchantId | The id of your merchant |
merchantTradingName | The trading name of your merchant |
customerIdentifier | Customer id on your system |
customerAccountNumber | Customer account number(this is filled only on verified payin) |
customerBankCode | Customer account number(this is filled only on verified payin) |
customerName | Customer account holder name(this is filled only on verified payin) |
version | Version of api |
journeyType | Type of this pay-in journey. eg. EMAIL |
transactionStatus | Current status of this transaction. eg. INITIATED |
searchableText | A string that you can use to search for this pay-in |
creationDate | Date of creation |
paymentMethod | Method of payment, e.g. OPEN_BANKING |
paymentGiro | PaymentGiro, e.g. FPS |
paymentAmount | The amount of the payment |
paymentCurrency | The currency of the payment |
payload | meta-data of the payment |
payloadEncrypted | Boolean value indicated that the payload is encrypted or not |
merchantAccountNumber | The account number of your merchant |
merchantBankCode | The bank code of your merchant |
reference | The reference given to the payin |
description | The description given to the payin |
customerEmailAddress | The customers email address |
Pay-In Transaction Statuses
TransactionStatus | Description |
---|---|
INITIATED | The journey has begun and the user is about to select the bank he will pay from |
PENDING_USER_AUTHORISATION | The user has selected the bank he wants to pay from and has been redirected to his bank |
ACCEPTED | The pay-in has been authorised by the user and accepted by the financial provider |
COMPLETE | Pay-in transaction is completed and funds have been settled |
CANCELLED | The user cancelled the pay-in |
REJECTED_BY_ASPSP | The pay-in has been rejected from the payer or payee bank |
EXPIRED | The pay-in has expired without the user authorising it |
FAILED | The pay-in failed to be authorised by the bank |
ERROR | An error occured during the pay-in journey. e.g INVALID_CONFIRMATION_CODE |
Pay-In Webhook Status Types
Webhook | Description | Pay-In Transaction Status |
---|---|---|
PAYIN_CREATED | Pay-In was created | INITIATED |
PAYIN_REDIRECT | The user has selected a bank and been redirected to that bank | PENDING_USER_AUTHORISATION |
PAYIN_CONSENT_GRANTED | The user has grant the consent to continue the payment | PENDING_USER_AUTHORISATION |
PAYIN_DECISION | Pay-In decision was made by the user | ACCEPTED or CANCELLED or REJECTED_BY_ASPSP or FAILED |
PAYIN_ERROR | An error occurred | ERROR |
PAYIN_EXPIRED | Pay-in has expired | EXPIRED |
PAYIN_COMPLETE | The money have been credited to your account (only for corporate accounts) | COMPLETE |
PAYIN_COMPLETE_CONFIRMED_ | If we receive a 200/201 response from the COMPLETE webhook, and the merchant set up event type PAYIN_COMPLETE_CONFIRMED, we will send this event to the merchant | COMPLETE |
Pay-In Completed Webhooks
Corporate accounts that are provided by Yaspa can be used for pay in transactions. Leveraging that, we can offer even more accurate updates regarding the process of the transaction and notify you when the money have been credited to your account.
This functionality is required when a corporate account provided by Yaspa is used for pay in transactions.
Steps for using the above functionality
- Register a new webhook (PAYIN_COMPLETE) that will handle the updates of transaction.
- If you are an existing client and you would like to integrate the new functionality you will need to update your backend to handle the new status.
What is the main difference
Pay-In transactions that will leverage the new functionality will no longer end in the ACCEPTED
stage but in the COMPLETE
. Therefore,
action may be required to be done in your backend. Furthermore, the transaction status history will contain that new state. In rare cases
due to racing conditions, the transaction history might contain the COMPLETE
status before the ACCEPTED
. However,
this would not affect the status of the transaction nor operation.
Account Verification Webhook Format
{
"type":"<the event type of a webhook>",
"data:": {
"citizenTransactionId": "<Citizen transaction id>",
"merchantId": "<The id of your merchant>",
"merchantTradingName": "<The trading name of your merchant>",
"customerIdentifier": "<Customer id on your system>",
"financialServiceProvider": "<Financial Service Provider, e.g. BARCLAYS>",
"version": "<Version of api>",
"journeyType": "<Type of this account verification journey. eg. NO_EMAIL>",
"transactionStatus": "<Current status of this transaction. eg. ACCEPTED>",
"creationDate": "<Date of creation>",
"accounts": [
{
"id": "<Id of the account>",
"accountName": "<Name of the account (eg Current/Credit)>",
"accountHolderName": "<Name of the accountholder>",
"number": "<Encrypted bank account number (UK)>",
"partialAccountNumber": "<Three digits of decrypted bank account number (UK)>",
"sortCode": "<Bank account sort code (UK)>",
"iban": "<Encrypted IBAN (EU)>",
"partialIban": "<Three digits decrypted of IBAN (EU)>",
"bic": "<Bank identifier (EU, eg Swift code)>",
"balance": "<Balance of the account>",
"type": "<Account type>",
"details": "<Account information (JSON list of transactions)>",
"bank": "<Bank of the account>"
}
],
"payload": "<the meta-data of the transaction>",
"payloadEncrypted": "<Boolean value indicated that the payload is encrypted or not>"
}
}
Account Verification Webhook parameters
Parameter | Description |
---|---|
citizenTransactionId | Citizen transaction id |
merchantId | The id of your merchant |
merchantTradingName | The trading name of your merchant |
customerIdentifier | Customer id on your system |
financialServiceProvider | financial Service Provider, e.g. BARCLAYS |
version | Version of api |
journeyType | Type of this pay-in journey. eg. EMAIL |
transactionStatus | Current status of this transaction. eg. INITIATED |
searchableText | A string that you can use to search for this pay-in |
creationDate | Date of creation |
accounts | Account object has account details only if transactionStatus is ACCEPTED |
payload | meta-data of the transaction |
payloadEncrypted | Boolean value indicated that the payload is encrypted or not |
Account Object parameters
Parameter | Description |
---|---|
id | Id of the account |
accountName | Name of the account (eg Current/Credit) |
accountHolderName | Name of the accountholder |
number | Encrypted bank account number (UK) |
partialAccountNumber | Three digits of decrypted bank account number (UK) |
sortCode | Bank account sort code (UK) |
iban | Encrypted IBAN (EU) |
partialIban | Three digits decrypted of IBAN (EU) |
bic | Bank identifier (EU, eg Swift code) |
balance | Balance of the account |
type | Account type |
details | Account information (JSON list of transactions) |
bank | Bank of the account |
Account verification Request Statuses
Account Verification Status | Description |
---|---|
CREATED | The journey has begun and the user is about to select the bank he want to verify the account from |
PENDING_USER_AUTHORISATION | The user has selected the bank he wants to verify and has been redirected to his bank |
PENDING_ASPSP_ACCEPTANCE | The request is processing from the bank |
ACCEPTED | The transaction has been completed |
CANCELLED | The transaction has been cancelled by the user |
FAILED | The transaction failed |
ERROR | An error occured processing the transaction |
Account verification Webhook Status Types
Status | Description | Account Verification Status |
---|---|---|
ACCOUNT_VERIFICATION_CREATED | Account verification journey was created | CREATED |
ACCOUNT_VERIFICATION_REDIRECT | The user has selected a bank and been redirected to that bank | PENDING_USER_AUTHORISATION |
ACCOUNT_VERIFICATION_DECISION | Account verification journey was completed | ACCEPTED or CANCELLED or FAILED |
ACCOUNT_VERIFICATION_ERROR | An error occurred | ERROR |
Payout Webhook format
JSON: Payout Webhook Response
{
"type":"<the event type of a webhook>",
"data": {
"citizenTransactionId": "<Citizen transaction id>",
"merchantId": "<The id of your merchant>",
"merchantTradingName": "<The trading name of your merchant>",
"customerIdentifier": "<Customer id on your system>",
"transactionStatus": "<The payout status>",
"creationDate": "<Date of creation>",
"citizenCounterPartyId": "<The id of counter party>",
"currency": "<The currency of the payout>",
"paymentGiro": "<PaymentGiro, e.g. FPS>",
"merchantBank": "<The bank of the merchant>",
"counterPartyBank": "<The bank of the customer that requests the payout>",
"counterPartyAccountName": "<The Account Name of Counter Party>",
"amount": "<The amount of the payout>",
"reference": "<The reference of the payout>",
"payload": "<the meta-data of the payout>",
"payloadEncrypted": "<Boolean value indicated that the payload is encrypted or not>",
"counterPartyBankCode": "<The Bank Code of Counter Party>",
"counterPartyAccountNumber": "<The Account Number of Counter Party>"
}
}
Payout transaction
Parameter | Description |
---|---|
citizenTransactionId | Citizen transaction id |
merchantId | The id of your merchant |
merchantTradingName | The trading name of your merchant |
customerIdentifier | Customer id on your system |
transactionStatus | The payout status |
creationDate | Date of creation |
citizenCounterPartyId | The id of counter party |
currency | The currency of the payout |
paymentGiro | PaymentGiro, e.g. FPS |
merchantBank | The bank of the merchant |
counterPartyBank | The bank of the customer that requests the payout |
counterPartyBankCode | The Bank Code of Counter Party |
counterPartyAccountNumber | The Account Number of Counter Party |
counterPartyAccountName | The Account Name of Counter Party |
searchableText | A string that you can use to search for this payout |
amount | The amount of the payout |
reference | The reference of the payout |
payload | meta-data of the payout |
payloadEncrypted | Boolean value indicated that the payload is encrypted or not |
Payout transaction statuses
Status | Description |
---|---|
CREATED | The payout has been initialised |
QUEUED | The payout has been added to a queue |
ACCEPTED | The payout has been submitted to the bank |
ERROR | The payout failed to be submitted |
FAILED | The payout has been already accepted and refund |
CANCELLED_BY_MERCHANT | The queued payout has been rejected by the merchant |
Payout Webhook status types
Webhook | Description | Payout Transaction Status |
---|---|---|
PAYOUT_CREATED | Payout was created | CREATED |
PAYOUT_ACCEPTED | Payout was submitted to the bank | ACCEPTED |
PAYOUT_QUEUED | Payout was added to queue | QUEUED |
PAYOUT_ERROR | An error occurred | ERROR, FAILED |
PAYOUT_REJECTED | Payout that was in queue was rejected | CANCELLED_BY_MERCHANT |
Pay-in Expiry
If a pay-in has not been authorised by the end user in their bank app within a set timeout after creation it will be expired. This timeout is currently 30 minutes. When a pay-in is expired its transactionStatus moves to EXPIRED and a PAYIN_EXPIRED web hook is sent.
A pay-in may also be rejected by a user in their bank app, or the user's bank may reject the payment or return an error. In these cases pay-ins are not expired, they will retain their final transaction status such as CANCELLED or REJECTED_BY_ASPSP.
Note that pay-in expiry relates only to end user authorisation in their bank app. There is no relationship between pay-in expiry and funds arriving in the receiving bank account.
Examples
The following examples demonstrate these scenarios, giving journey steps and the pay-in transactionStatus at that point in the journey.
Example A End user discontinues the journey. The pay-in is expired.
11:05:00 Merchant initiates pay-in (CREATED)
11:05:02 End user is redirected to their bank (PENDING_USER_AUTHORISATION)
11:05:07 End user discontinues the pay-in journey (PENDING_USER_AUTHORISATION)
11:35:00 Pay-in is expired and web hook sent (EXPIRED)
Example B End user cancels the journey in their bank app. The pay-in is not expired.
11:05:00 Merchant initiates pay-in (CREATED)
11:05:02 End user is redirected to their bank (PENDING_USER_AUTHORISATION)
11:05:07 End user cancels the pay-in journey (CANCELLED)
Example C End User completes a pay-in but there is a delay before the funds to arrive in the receiving bank account. The pay-in is not expired
11:05:00 Merchant initiates pay-in (CREATED)
11:05:02 End user is redirected to their bank (PENDING_USER_AUTHORISATION)
11:05:21 End user authorises the pay-in in their bank app (PAYIN_CONSENT_GRANTED)
11:05:23 Yaspa sends authorised payment instruction to the sending bank (ACCEPTED)
16:47:34 Funds arrive in receiving bank account (COMPLETE)
Web Hook
Upon a pay-in being expired, a PAYIN_EXPIRED web hook is sent if the merchant is subscribed to it. The web hook will look like the example on the right.
Expired pay-in web hook
{
"type": "PAYIN_EXPIRED",
"data": {
"citizenTransactionId": "4320daed-b193-4545-548a-af6327",
"merchantId": "635f9e6e9a264a14adb8ea02",
"merchantTradingName": "Test Company",
"customerIdentifier": "test@yaspa.com",
"version": "2",
"journeyType": "VERIFIED_PAYIN_NO_EMAIL",
"transactionType": "PAYIN",
"authType": "STANDARD",
"transactionStatus": "EXPIRED",
"creationDate": 1731931155092,
"testParameters": {},
"language": "en",
"showReceipt": false,
"paymentMethod": "OTHER",
"paymentGiro": "SEPA",
"customerAccountNumber": "IE67REVO99123456789",
"customerName": "John Doe",
"merchantAccountNumber": "DE311123456789",
"merchantBankCode": "NTSBDEB1XXX",
"paymentAmount": "15.00",
"paymentCurrency": "EUR",
"reference": "REF234560923",
"paymentProvider": "REVOLUT_EU",
"finalIsoStatusCode": "ACSC",
"cancelledByTerminal": false,
"retailRefundUnAcknowledgedPayins": false,
"metaData": {},
"physicalQRJourney": false,
"enhancedPayIn": false,
"payloadEncrypted": false
}
}
{
"type": "PAYIN_EXPIRED",
"data": {
"citizenTransactionId": "4320daed-b193-4545-548a-af6327",
"merchantId": "635f9e6e9a264a14adb8ea02",
"merchantTradingName": "Test Company",
"customerIdentifier": "test@yaspa.com",
"version": "2",
"journeyType": "VERIFIED_PAYIN_NO_EMAIL",
"transactionType": "PAYIN",
"authType": "STANDARD",
"transactionStatus": "EXPIRED",
"creationDate": 1731931155092,
"testParameters": {},
"language": "en",
"showReceipt": false,
"paymentMethod": "OTHER",
"paymentGiro": "SEPA",
"customerAccountNumber": "IE67REVO99123456789",
"customerName": "John Doe",
"merchantAccountNumber": "DE311123456789",
"merchantBankCode": "NTSBDEB1XXX",
"paymentAmount": "15.00",
"paymentCurrency": "EUR",
"reference": "REF234560923",
"paymentProvider": "REVOLUT_EU",
"finalIsoStatusCode": "ACSC",
"cancelledByTerminal": false,
"retailRefundUnAcknowledgedPayins": false,
"metaData": {},
"physicalQRJourney": false,
"enhancedPayIn": false,
"payloadEncrypted": false
}
}
Errors
The Yaspa API uses the following error codes:
Error Code | Meaning |
---|---|
400 | Bad Request -- Your request is invalid. |
401 | Unauthorized -- Your API key or Client Secret is wrong. |
403 | Forbidden -- Your account is restricted to perform that operation |
404 | Not Found -- The specified object could not be found. |
405 | Method Not Allowed -- You tried to access the API with an invalid method. |
406 | Not Acceptable -- You posted incorrect JSON |
409 | Conflict -- That object already exists (commonly the email of the account) |
500 | Internal Server Error -- Server side issues that are not caught by the above. Try again later. |
503 | Service Unavailable -- Citize is offline for maintenance. Please try again later. |
Yaspa Admin Dashboard
There are two deployments of the Adminstration Dashboard for test and for production environments.
Environment | Admin Console |
---|---|
Test Signin | https://test.yaspa.com/#/login |
Test Registration | https://test.yaspa.com/#/register/merchant-user |
Live | https://admin.yaspa.com/#/login |
Live Registration | https://admin.yaspa.com/#/register/merchant-user |
Understanding the Console
The Admin console is used to perform a number of important adminstration and support tasks:
- At integration time, it's used by adminstrators and integration engineers to configure the payment experience
- During live, it's used but support staff to look at transactions
- Based on your billing cycle it can be used to look at reports and transfer money to your bank account
Adding Company Users
The Admin Dashboard allows merchants to add more Company Users to help adminster their
Users can be added from the Company Users tab.
Click the Add User button, and you will be presented with a series of roles you can assign to the User.
As staff using the Admin Dashboard will have different jobs, they all will need different roles, this enforces the good security principle of supplying the minimum required access to staff to perform their jobs.
Role Base Security by Job
For those who want to get started quickly we have defined four typical jobs and what roles we suggest those staff receive:
Job | Roles | Explanation |
---|---|---|
Owner | Site Admin, Admin, Support, Finance | These users have the Site Admin role. This is the highest level of priviledge in Yaspa. This user can give themselves, and staff any role they like. Including financial roles. Because of the sensitivity of the financial role, we suggest having few trusted staff performing this job. |
Admin | Admin, Support | These users are able to add staff with any permissions except the Site Admin and Finance role. Admins are responsible for the day to day running of the operation and Support |
Finance | Finance, Support | These Users lack the ability to add Users, but can see all financial information and Support screens. The Finance role will allow them to conduct their financial reports and operations |
Customer Support | Support | These Users are reponsible for the day to day Support functions. These are able to investigate Customers and payments but have no write priviledges to anything in the System |
Role Base Security by Role
More roles are available and these can be used to turn on addition payment features. Talk to the Yaspa Customer Success manager to find out more. The complete list of roles is explained below
Role | Explanation |
---|---|
Site Admin | The Site Admin role is the highest level of priviledge in Yaspa. The Site Admin can add and remove any user and grant whatever roles they choose. Site Admins can also remove other Site Admins |
Admin | The Admin role is responsible for day to day adminstration. The Admin can add and remove any user except for Site Admins. They can grant any priviledge except for the Site Admin and Finance roles. Admins can also remove other Admins |
Finance | This role has permissions to see Balances. Future updates to the tool will play the Payout SSH keys also under their control. |
Support | This role has view access to the payin and payout screens. This role is designed for Customer Support and provides a borad set of read only priviledges. |
Cashier Engineer | Only needed if Payment Links are Used This Role has permissions to create, update and delete both permanent and one shot Payment links. |
Cashier | Only needed if Payment Links are Used This Role has to view the Cashier screen. This is used for payments at physical locations, where Yaspa is being used within a Kiosk and Cashiers want to mark up which Payments have been made |
Merchant Customer Support | Alpha functionality - Only needed if you are issuing ibans to customers This role has the ability to view the list of merchant customers with their generated iban information. |