Getting Started
You can now integrate Atoa in just four easy steps.**.β
Step 1 - Sign up for developer accessβ
Get started by Downloading our mobile app from Play Store or Appstore
.
What you'll needβ
- An Android or iOS Smartphone
- If you need any help please contact our team at hello@paywithatoa.co.uk
Next, you'll need to follow the simple registration process to obtain the Developer Keyβ
After Registration and Bank Account linking open My Account -> API Access in the app to get Access ID and Access Secretβ
Step 2 - Create Payment Requestβ
Create a Payment Link
API Endpoint
https://api.atoa.me
curl --location --request POST 'https://api.atoa.me/api/payments/process-payment' \
--header 'Authorization: Bearer {Access Secret}' \
--header 'Content-Type: application/json' \
--data-raw '{
"customerId": "<Your Uniquer Customer Id>",
"orderId": "<Order Id>",
"amount": "<Total Amount - Optional>",
"currency": "GBP",
"paymentType": "<DOMSETIC>",
"autoRedirect": "<true or false>",
"institutionId": "<Institution ID - Optional>",
"storeId": "<Store ID - Optional>",
"consumerDetails": {
"phoneCountryCode": "<Consumer Phone Country Code>",
"phoneNumber": "<Consumer Phone Number>",
"email": "<Consumr Email>",
"firstName": "<Consumer First Name>",
"lastName": "<Consumer Last Name>"
}, // <Optional>
"callbackParams": {
}, // <Optional>
"expiresIn" : "<Milliseconds - Optional>",
"enableTips": "<true or false - Optional>", //Defaults to true
"allowRetry": "<true or false - Optional>", //Defaults to true
"strictExpiry": "<true or false - Optional>", //Defaults to false
"redirectUrl" : "<Redirect Url - Optional>",
"splitBill" : "<true or false - Optional>", //Defaults to false
"template": "<EXTERNAL_DISPLAY or RECEIPT - Optional>"
}'
You can skip this step if redirect is set to "true" in previous step. This step is useful for payments which are to be accepted via POS terminal screens or desktop devices.β
Option 1:β
You can redirect the user using payment url got from the above curl
Option 2:β
You can display the QR code taken from the above curl
Did you know...
If autoRedirect is true, the user will be shown a scannable QR code (on desktop devices) while the bank app will be opened automatically on mobile devices.
Step 3 - Handle Payment Statusβ
Option 1 Redirection and pollingβ
After the payment is successfully processed, it is essential to manage the transaction status and redirection. If you wish to redirect your users back to your website or shopping page for further interaction, you can specify the desired redirection URL
Note
After payment is successful, we will redirect customer back to the redirection url
https://<yourRedirectUrl>?status=<SUCCESS/FAILURE/PENDING>&paymenRequestId=<paymenRequestId>&paymentIdempotencyId=<paymentIdempotencyId>&orderId=<atoaOrderId>&atoaSignature<atoaSignature>
If the status is PENDING, you should Poll for success at regular intervals. It should take 2-3 minutes at maximum for payment to be completed (dependent on the bank used).β
curl --location --request GET 'https://api.atoa.me/api/payments/payment-status/<paymenRequestId>?type=request'
Pass query param &env=sandbox for sanbox testing
Option 2 Subscribe to webhookβ
Atoa uses webhooks to notify your application when an event happens in your account. Webhooks are particularly useful for asynchronous events such as changes in payment status like completion, failure, or pending.
To get started, you need to Register your webhook endpoint so Atoa knows where to deliver events.
Once registered, your endpoint will receive webhook payloads for payment status changes: COMPLETED, PENDING, or FAILED.
Here are the payloads that you will receive for different payment status:β
- COMPLETED
- PENDING
- FAILED
{
"merchantId": "41a77f74-8b67-4f04-be50-c8dd5ad8836f",
"customerId": "Abcam",
"consumerId": "60513141-4d0f-4d3d-9c8a-cc1bd61f40fd",
"merchantName": "jhon doe",
"paymentIdempotencyId": "ATOA1695808662681",
"status": "COMPLETED",
"statusDetails": {
"status": "COMPLETED",
"statusUpdateDate": "2023-09-27T09:58:13.347Z",
"isoStatus": {
"code": "ACSC",
"name": "AcceptedSettlementCompleted"
}
},
"paidAmount": "1005",
"tipAmount": "5.00",
"currency": "GBP",
"createdAt": "2023-09-27T09:57:50.067Z",
"updatedAt": "2023-09-27T09:57:50.067Z",
"taxAmount": 50.25,
"serviceAmount": 30.15,
"storeDetails": {
"id": "ee39ecfa-e336-461c-a957-1adc76ac087c",
"address": "Welwyn Garden City, Hertfordshire",
"locationName": "DEFAULT"
},
"orderId": "003decb3-c35",
"paymentRequestId": "6d1803f8-038a-48f3-8cd4-b44d37a3ab91",
"signatureHash": "1ea6ff07ca90ec4ca34dfd3b420dcdfe5db2d73e3a5de05e5379e8aa325a5e2e",
"errorDescription": null,
"redirectUrlParams": {},
"redirectUrl": "https://www.google.com"
}
{
"merchantId": "41a77f74-8b67-4f04-be50-c8dd5ad8836f",
"customerId": "rushi-mhatre-sdktest123",
"consumerId": "4d384a48-0fdc-4e67-b74e-bf047ded6733",
"merchantName": "Rushi refund invoicing",
"paymentIdempotencyId": "ATOA1699528680892",
"status": "PENDING",
"statusDetails": {
"status": "PENDING",
"statusUpdateDate": "2023-11-09T11:18:24.621Z",
"isoStatus": {
"code": "PDNG",
"name": "Pending"
}
},
"paidAmount": "1000",
"tipAmount": "0.00",
"currency": "GBP",
"createdAt": "2023-11-09T11:18:02.045Z",
"updatedAt": "2023-11-09T11:18:02.045Z",
"taxAmount": 50,
"serviceAmount": 30,
"storeDetails": {
"id": "ee39ecfa-e336-461c-a957-1adc76ac087c",
"address": "mumbai, 89001, mumbai 400031",
"locationName": "DEFAULT"
},
"orderId": "Sigantuet1212est2",
"paymentRequestId": "9ad86a9c-cf67-4412-bae9-673de58fe0b4",
"signature": "a891be4b58089f70e5732cc10ab1260c8827b4d4e6ca7445cf75aba513e67618",
"signatureHash": "c79240fa2d0d622077e53d675f9b9a41f1bb02f138652dfa2c20e18f8966150f",
"errorDescription": null,
"redirectUrlParams": null,
"redirectUrl": "https://www.google.com"
}
{
"merchantId": "41a77f74-8b67-4f04-be50-c8dd5ad8836f",
"customerId": "rushi-mhatre-sdktest123",
"consumerId": "4d384a48-0fdc-4e67-b74e-bf047ded6733",
"merchantName": "Rushi refund invoicing",
"paymentIdempotencyId": "ATOA1699528623706",
"status": "FAILED",
"statusDetails": {
"status": "FAILED",
"statusUpdateDate": "2023-11-09T11:17:25.871Z",
"isoStatus": {
"code": "RJCT",
"name": "Rejected"
}
},
"paidAmount": "1000",
"tipAmount": "0.00",
"currency": "GBP",
"createdAt": "2023-11-09T11:17:04.530Z",
"updatedAt": "2023-11-09T11:17:04.530Z",
"taxAmount": 50,
"serviceAmount": 30,
"storeDetails": {
"id": "ee39ecfa-e336-461c-a957-1adc76ac087c",
"address": "mumbai, 89001, mumbai 400031",
"locationName": "DEFAULT"
},
"orderId": "Sigantuet1212est2",
"paymentRequestId": "9ad86a9c-cf67-4412-bae9-673de58fe0b4",
"signature": "82341dfbd807afb4f636e465b6ef1ffa17e05fd4b4622fb6b99dc7c1afda58af",
"signatureHash": "c79240fa2d0d622077e53d675f9b9a41f1bb02f138652dfa2c20e18f8966150f",
"errorDescription": null,
"redirectUrlParams": null,
"redirectUrl": "https://www.google.com"
}
Here are the details of the payment status of the given payload :β
Status | Description |
---|---|
"COMPLETED" | indicates that the payment has been processed successfully, ensuring a smooth transfer of funds to the merchant's account. |
"PENDING" | signifies that the payment is currently in progress, awaiting final confirmation from the bank's end. |
"FAILED" | Any unsuccessful transaction is marked as failed. The customer will have to retry the payment. |
Step 4 - Verify Signatureβ
This is a mandatory step to confirm the authenticity of the details returned from Atoa for successful payments.β
Steps to Verify Signature
- orderId: Β Retrieve the orderId from your server. Do not use the atoaOrderId
- paymentRequestId: Β Returned by Redirect url or polling api.
- atoaSecret: That was generated from first step
generatedSignature = hmac_sha256(orderId + "|" + paymentRequestId, atoaSecret);
if (generatedSignature == atoaSignatureHash) {
payment is successful
}
Example of Generating Signature on Your Serverβ
- Java
- GO
/**
* This class defines routines for generating signatures for verfying the payments authenticity.
*/
public class Signature
{
private static final String HMAC_SHA256_ALGORITHM = "HmacSHA256";
/**
* Computes RFC 2104-compliant HMAC signature.
* * @param data
* The data to be signed.
* @param key
* The signing key.
* @return
* The Base64-encoded RFC 2104-compliant HMAC signature.
* @throws
* java.security.SignatureException when signature generation fails
*/
public static String calculateRFC2104HMAC(String data, String secret)
throws java.security.SignatureException
{
String result;
try {
// get an hmac_sha256 key from the raw secret bytes
SecretKeySpec signingKey = new SecretKeySpec(secret.getBytes(), HMAC_SHA256_ALGORITHM);
// get an hmac_sha256 Mac instance and initialize with the signing key
Mac mac = Mac.getInstance(HMAC_SHA256_ALGORITHM);
mac.init(signingKey);
// compute the hmac on input data bytes
byte[] rawHmac = mac.doFinal(data.getBytes());
// base64-encode the hmac
result = DatatypeConverter.printHexBinary(rawHmac).toLowerCase();
} catch (Exception e) {
throw new SignatureException("Failed to generate HMAC : " + e.getMessage());
}
return result;
}
}
import (
"crypto/hmac"
"crypto/sha256"
"crypto/subtle"
"encoding/hex"
"fmt"
)
func main() {
signature := "<signature>"
secret := "<secret>"
data := "<orderId>"
// Create a new HMAC by defining the hash type and the key (as byte array)
h := hmac.New(sha256.New, []byte(secret))
// Write Data to it
_, err := h.Write([]byte(data))
if err != nil {
panic(err)
}
// Get result and encode as hexadecimal string
sha := hex.EncodeToString(h.Sum(nil))
fmt.Printf("Result: %s\n", sha)
if subtle.ConstantTimeCompare([]byte(sha), []byte(signature)) == 1 {
fmt.Println("Works")
}
}
All set! You are all set to start accepting payment. We are constantly making efforts to improve atoa so If you are looking for deeper integration with atoa or have any doubts or feedback to improve feel free to share it with us at hello@paywithatoa.co.uk