Step-by-step guide
Learn how to accept payments in your Android app using our mobile SDK. This guide explains the process of integrating the checkout experience in your app.
Checkout experience flow
The following explains the flow of a user's journey in the checkout experience.
- The term
userused in this document refers to a customer trying to make a payment through your mobile application. - This guide assumes you named the button on your checkout screen as Checkout.
-
A user visits your app and taps Checkout.
-
Your mobile app sends the user's purchase information to your backend, your backend sends this information to Dojo's backend to create a payment intent.
-
Your mobile app starts the checkout process using the mobile SDK.
-
The mobile SDK collects the user payment details, sends them to the Dojo backend, and presents a result screen to the user. The mobile SDK then notifies the hosting application of the payment result.
-
Your backend receives a webhook notification when the payment is completed.

Flow diagram: Flow Checkout Page Android
sequenceDiagram
actor U as User
participant SDK as dojo mobile SDK
participant App as Merchant mobile app
participant MB as Merchant backend
participant DB as dojo backend
U->>App: Taps Checkout
App->>MB: Sends information about user purchases
MB->>DB: POST /payment-intents
DB-->>MB: Payment intent object
MB-->>SDK: Payment intent Id
SDK-->>U: Display prebuilt Checkout screen
U->>SDK: Enters payment details and taps Pay
SDK->>DB: Processes payment
DB-->>SDK: Sends response with the payment result
SDK-->>U: Displays the payment result
SDK->>App: Notifies mobile app with the payment result
DB->>MB: Sends webhooks
How to process a payment
This is a step-by-step guide that demonstrates how to process payments with Dojo's backend and your backend into your mobile app using Dojo's mobile SDK.
Before you start
Before you begin to integrate, make sure you have followed the Getting started guide and got your API keys.
For the test environment, use your secret key with the prefix sk_sandbox_.
This guide contains the following steps:
Step 1. Create a payment intent
With the checkout button in your app, call your backend and then call Dojo's backend endpoint to create a payment intent.
To create a payment intent, the following parameters are required:
-
amount: This includes the currency and value, in minor units, for example, "1000" for 10.00 GBP. -
reference: Your unique reference for the payment intent, like the order number.
Here's an example of how to create a payment intent for 10 GBP on your backend:
- Python
- C#
from urllib import response
from flask import Flask, jsonify, request, render_template
app = Flask(__name__)
@app.route('/checkout', methods=['GET', 'POST'])
def hello():
# POST request
if request.method == 'POST':
print(request.get_json()) # parse as JSON
conn = http.client.HTTPSConnection("api.dojo.tech")
# call post payment-intent
payload = json.dumps({
"amount": {
"value": 1000,
"currencyCode": "GBP"
},
"reference": "Order 245"
})
headers = {
'Content-Type': "application/json",
'Version': "2024-02-05",
'Authorization': "Basic sk_sandbox_c8oLGaI__msxsXbpBDpdtwJEz_eIhfQoKHmedqgZPCdBx59zpKZLSk8OPLT0cZolbeuYJSBvzDVVsYvtpo5RkQ" # <-- Change to your secret key
}
conn.request("POST", "/payment-intents/", payload, headers)
# handling the response from POST
res = conn.getresponse()
data = res.read()
resp_data = {}
resp_data['id'] = json.loads(data)["id"]
json_data = json.dumps(resp_data)
using Dojo.Net;
var paymentIntentsClient = new PaymentIntentsClient(new HttpClient(), new ApiKeyClientAuthorization("sk_sandbox_c8oLGaI__msxsXbpBDpdtwJEz_eIhfQoKHmedqgZPCdBx59zpKZLSk8OPLT0cZolbeuYJSBvzDVVsYvtpo5RkQ"));
var result = await paymentIntentsClient.CreatePaymentIntentAsync(new CreatePaymentIntentRequest
{
Amount = new()
{
Value = 1000,
CurrencyCode = "GBP"
},
Reference = "Order 245"
});
See the API reference for a complete list of parameters that can be used for payment intent creation. For configurations that apply to our mobile SDK, go to Configurations.
Step 2. Start checkout process
Once you've created the payment intent, pass the payment intent ID to your payment flow code.
To start the checkout process, ensure you have installed the latest SDK.
- Kotlin
- Java
// Get the PaymentHandler
val dojoPayUI =
DojoSDKDropInUI.createUIPaymentHandler(this) { result ->
// handle result
Toast.makeText(this, result.name, Toast.LENGTH_SHORT).show()
}
// On Pay tapped
dojoPayUI.startPaymentFlow(DojoPaymentFlowParams(paymentId = "<paymentIntentId>"))
// Get the PaymentHandler
private final DojoPaymentFlowHandler dojoPaymentFlowHandler = DojoSDKDropInUI.INSTANCE.createUIPaymentHandler(
this,
((dojoPaymentResult) -> {
Toast.makeText(this, dojoPaymentResult.name(),
Toast.LENGTH_LONG).show();
return Unit.INSTANCE;
}));
// On "Pay" tapped
dojoPaymentFlowHandler.startPaymentFlow(
new DojoPaymentFlowParams(
"<paymentIntentId>"
));
After the user fills in their payment information on the checkout screen, Dojo processes the payment and redirects the user to the result screen. The app receives a result code.
For additional configurations that apply to our mobile SDK, go to configurations.
Step 3. Handle post-payment events
After a user completes a payment, we recommend using webhooks to update the backend result and receive information about the payment. Set up endpoints to receive and handle webhook requests. By using webhooks, your application can receive updates about payment events and you can ensure that you don't lose any information about the payment. To handle these events, configure your backend for incoming webhook notifications and process these notifications accordingly.
Dojo's backend sends a payment_intent.status_updated event when the payment is completed (captured, refunded, reversed, canceled).
To set up webhooks, review our webhooks guide.
Ensure you validate the transaction result by either using a webhook or making a direct API call on your backend. The result code received on the application front-end might not be reliable as you might receive delayed responses.
Here's an example of how to subscribe to the payment_intent.status_updated event:
- cURL
- PowerShell
- Python
- C#
- PHP
# The sandbox API key passed in 'authorization' is public.
# Don't submit any personally identifiable information in any requests made with this key.
# Sign in to developer.dojo.tech to create your own private sandbox key and use that instead
# for secure testing.
curl -v --request POST \
--url https://api.dojo.tech/webhooks \
--header 'Authorization: Basic sk_sandbox_c8oLGaI__msxsXbpBDpdtwJEz_eIhfQoKHmedqgZPCdBx59zpKZLSk8OPLT0cZolbeuYJSBvzDVVsYvtpo5RkQ' \
--header 'Content-Type: application/json' \
--header 'Version: 2024-02-05' \
--data '{
"events": ["payment_intent.status_updated"],
"url": "https://example.com/incoming-events"
}'
# This is a public sandbox API key.
# Don’t submit any personally identifiable information in any requests made with this key.
# Sign in to developer.dojo.tech to create your own private sandbox key and use that instead
# for secure testing.
$publicSandboxKey = "sk_sandbox_c8oLGaI__msxsXbpBDpdtwJEz_eIhfQoKHmedqgZPCdBx59zpKZLSk8OPLT0cZolbeuYJSBvzDVVsYvtpo5RkQ"
Invoke-WebRequest `
-Uri 'https://api.dojo.tech/webhooks' `
-Method POST `
-Headers @{
"version" = "2024-02-05"
"Authorization" = "Basic $publicSandboxKey"
} `
-ContentType 'application/json' `
-Body '{
"events": [ "payment_intent.status_updated" ],
"url": "https://example.com/incoming-events"
}'
# The sandbox API key passed in 'authorization' is public.
# Don't submit any personally identifiable information in any requests made with this key.
# Sign in to developer.dojo.tech to create your own private sandbox key and use that instead
# for secure testing.
import http.client
conn = http.client.HTTPSConnection("api.dojo.tech")
payload = "{\"events\":[\"payment_intent.status_updated\"],\"url\":\"https://example.com/incoming-events\"}"
headers = {
'Content-Type': "application/json",
'Version': "2024-02-05",
'Authorization': "Basic sk_sandbox_c8oLGaI__msxsXbpBDpdtwJEz_eIhfQoKHmedqgZPCdBx59zpKZLSk8OPLT0cZolbeuYJSBvzDVVsYvtpo5RkQ" # <-- Change to your secret key
}
conn.request("POST", "/webhooks", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
conn.close()
// The sandbox API key passed in 'ApiKeyClientAuthorization' is public.
// Don’t submit any personally identifiable information in any requests made with this key.
// Sign in to developer.dojo.tech to create your own private sandbox key and use that instead
// for secure testing.
var webhooksClient = new Dojo.Net.WebhooksClient(new HttpClient(), new ApiKeyClientAuthorization("sk_sandbox_c8oLGaI__msxsXbpBDpdtwJEz_eIhfQoKHmedqgZPCdBx59zpKZLSk8OPLT0cZolbeuYJSBvzDVVsYvtpo5RkQ"));
webhooksClient.SubscribeAsync(new SubscriptionRequest()
{
Events = new List<string>() { "payment_intent.status_updated" },
Url = new Uri("https://example.com/incoming-events")
});
<?php
// The sandbox API key used in this example is public.
// Don't submit any personally identifiable information in any requests made with this key.
// Sign in to developer.dojo.tech to create your own private sandbox key and use that instead
// for secure testing.
namespace Test;
require_once "vendor/autoload.php";
use Dojo_PHP\ApiFactory;
use Dojo_PHP\Model\SubscriptionRequest;
$apiKey = "sk_sandbox_c8oLGaI__msxsXbpBDpdtwJEz_eIhfQoKHmedqgZPCdBx59zpKZLSk8OPLT0cZolbeuYJSBvzDVVsYvtpo5RkQ";
$api = ApiFactory::createWebhooksApi($apiKey);
$req = new SubscriptionRequest(["url" => "https://example.com/incoming-events", "events" => ["payment_intent.status_updated"]]);
$api->webhooksSubscribe(\Dojo_PHP\API_VERSION, $req);
Step 4. Test and go live
Before going live, test your integration using the test card numbers:
| Card Name | Card number | Expiry Date | CVV | 3D security | Status |
|---|---|---|---|---|---|
| No | Successful | ||||
| 2.0 | Successful | ||||
| No | Decline |
When you are ready to go live, switch your secret key to production one with the prefix sk_prod_.
Result codes
When you make a payment using an SDK integration, your app will receive a result code. Refer to the following result codes for more information.
| Result code | Result | Description |
|---|---|---|
0 | Successful | The transaction was successful. |
3 | Authorizing | The card holder hasn't completed 3DS, this status will only be seen on the REST API. |
4 | Referred | The card issuer has parked the transaction awaiting contact with the customer before proceeding to authorize or decline the transaction. |
5 | Declined | The transaction was declined by the card issuer or acquiring bank. |
20 | Duplicate Transaction | The transaction which was processed was a duplicate. Ensure each transaction has a unique OrderId. |
30 | Failed | Error executing transaction. |
400 | Invalid Request | The request has failed validation by our servers and the transaction hasn't been submitted to the gateway. Possible causes for this are invalid transaction type or other data in the request. |
401 | Issue with Access Token | The access token being used isn't valid, the transaction hasn't been submitted to the gateway. This can be caused if the token has already been used or the 30 minute expiry time has elapsed. |
404 | No Access Token Supplied | No access token has been supplied. Transaction hasn't been submitted to the gateway. |
500 | Internal Server Error | There's been an error submitting the transaction, please check the REST API for the status of the transaction. |
7770 | SDK Internal Error | There's a problem on the SDK side. Contact Dojo for more information. |