Full integration example
This guide walks through the complete flow of a sale -- from authentication to payment confirmation -- using the sandbox environment with ready-to-use examples you can copy and run.
TIP
All examples use sandbox URLs. For production, replace sandboxappmax with appmax in the URLs.
What we will build
Authenticate -> Collect IP -> Create customer -> Create order -> Pay -> ConfirmBy the end of this guide you will have completed a full transaction in the sandbox.
Prerequisites
client_idandclient_secretfrom the merchant (obtained after installing the app)- HTML page to include the Appmax JS
- Endpoint to receive webhooks
1. Authenticate
Obtain a Bearer token using the merchant's credentials.
curl --request POST \
--url https://auth.sandboxappmax.com.br/oauth2/token \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'client_id=SEU_CLIENT_ID' \
--data-urlencode 'client_secret=SEU_CLIENT_SECRET'{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600
}Save the access_token. It will be used in all subsequent calls as Bearer YOUR_TOKEN. The token expires in 1 hour.
2. Collect the customer's IP
Before creating the customer, you must collect the IP using Appmax JS. Include the script on your checkout page:
<!DOCTYPE html>
<html>
<head>
<title>Checkout</title>
</head>
<body>
<form id="customer-form" data-appmax-customer>
<input type="text" name="first_name" placeholder="Nome" required />
<input type="text" name="last_name" placeholder="Sobrenome" required />
<input type="email" name="email" placeholder="E-mail" required />
<input type="text" name="phone" placeholder="Telefone" required />
<button type="submit">Continuar</button>
</form>
<script src="https://scripts.appmax.com.br/appmax.min.js"></script>
<script>
let clienteIP = null;
window.AppmaxScripts.init(
function onSuccess(data) {
clienteIP = data.ip;
console.log('IP coletado:', clienteIP);
},
function onError(err) {
console.error('Erro ao coletar IP:', err);
}
);
document.getElementById('customer-form').addEventListener('submit', function(e) {
e.preventDefault();
if (!clienteIP) {
alert('Aguarde a coleta do IP');
return;
}
// Send form data + clienteIP to your backend
enviarParaBackend({
first_name: this.first_name.value,
last_name: this.last_name.value,
email: this.email.value,
phone: this.phone.value,
ip: clienteIP
});
});
</script>
</body>
</html>WARNING
In the sandbox, if the IP is not available, use 127.0.0.1 for testing. In production, the real IP is required.
3. Create the customer
On your backend, send the customer data to the API. The combination of first_name + last_name + email + phone + ip is the unique key -- if a match already exists, the customer is updated.
curl --request POST \
--url https://api.sandboxappmax.com.br/v1/customers \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"first_name": "Junior",
"last_name": "Almeida",
"email": "[email protected]",
"phone": "51983655100",
"ip": "127.0.0.1",
"document_number": "25226493029",
"address": {
"postcode": "91520270",
"street": "Rua Francisco Carneiro da Rocha",
"number": "582",
"complement": "Casa",
"district": "Moinhos de Ventos",
"city": "Porto Alegre",
"state": "RS"
}
}'{
"data": {
"customer": {
"id": 2023
}
}
}Save data.customer.id -- this is the customer_id that will be used in the order.
4. Create the order
Link the order to the customer. Values are in cents (R$ 123.00 = 12300).
curl --request POST \
--url https://api.sandboxappmax.com.br/v1/orders \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"customer_id": 2023,
"products": [
{
"sku": "LIVRO-001",
"name": "Livro de receitas",
"quantity": 1,
"unit_value": 12300,
"type": "digital"
}
],
"shipping_value": 0,
"discount_value": 0
}'{
"data": {
"order": {
"id": 3531,
"status": "pendente"
}
}
}Save data.order.id -- this is the order_id that will be used in the payment. The status starts as pendente.
5. Process the payment
Choose one of the methods below. In the sandbox, use the test card 4000000000000010 to simulate a successful payment.
There are two approaches: via token (recommended) or via Appmax JS. This example uses tokenization:
Step 1 -- Tokenize the card:
curl --request POST \
--url https://api.sandboxappmax.com.br/v1/payments/tokenize \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"payment_data": {
"credit_card": {
"number": "4000000000000010",
"cvv": "123",
"expiration_month": "12",
"expiration_year": "28",
"holder_name": "Junior Almeida"
}
}
}'{
"data": {
"token": "422146c7523a46119d6073ea56193913"
}
}Step 2 -- Pay with the token:
curl --request POST \
--url https://api.sandboxappmax.com.br/v1/payments/credit-card \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"order_id": 3531,
"customer_id": 2023,
"payment_data": {
"credit_card": {
"token": "422146c7523a46119d6073ea56193913",
"holder_document_number": "25226493029",
"holder_name": "Junior Almeida",
"installments": 1,
"soft_descriptor": "MINHALOJA"
}
}
}'{
"data": {
"order": {
"id": 3531,
"status": "autorizado"
},
"payment": {
"method": "creditcard",
"installments": 1,
"paid_at": "2025-03-15 14:30:00"
},
"upsell_hash": "4000114202503117156088040208561001715608804"
}
}The autorizado status indicates the payment was accepted and is undergoing anti-fraud analysis. Wait for the order_approved webhook for confirmation.
6. Confirm the payment
Confirmation is asynchronous. There are two ways to know the payment was approved:
Via webhook (recommended)
Your endpoint will receive a POST when the status changes:
{
"event": "order_approved",
"event_type": "order",
"data": {
"order": {
"id": 3531,
"status": "aprovado",
"total_paid": 12300
},
"customer": {
"id": 2023,
"name": "Junior Almeida",
"email": "[email protected]"
},
"payment": {
"method": "creditcard",
"installments": 1,
"paid_at": "2025-03-15 14:30:00"
}
}
}Respond with HTTP 200 to acknowledge receipt.
Via query (polling)
If you need to check the status manually:
curl --request GET \
--url https://api.sandboxappmax.com.br/v1/orders/3531 \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'{
"data": {
"order": {
"id": 3531,
"status": "aprovado",
"total_paid": 12300,
"amounts": {
"sub_total": 12300,
"shipping_value": 0,
"discount": 0,
"installment_fee": 0
}
},
"customer": {
"id": 2023,
"name": "Junior Almeida",
"email": "[email protected]"
},
"payment": {
"method": "creditcard",
"installments": 1,
"paid_at": "2025-03-15 14:30:00"
}
}
}See all possible statuses.
7. After payment
Physical products: register the tracking code
To release the merchant's withdrawals, update the order with the tracking code:
curl --request POST \
--url https://api.sandboxappmax.com.br/v1/orders/shipping-tracking-code \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"order_id": 3531,
"shipping_tracking_code": "BR123456789XX"
}'Refund (if needed)
To request a full refund:
curl --request POST \
--url https://api.sandboxappmax.com.br/v1/orders/refund-request \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"order_id": 3531,
"type": "total",
"value": 12300
}'Flow summary
| Step | Endpoint | Result |
|---|---|---|
| Authenticate | POST /oauth2/token | access_token |
| Create customer | POST /v1/customers | customer_id |
| Create order | POST /v1/orders | order_id (status: pendente) |
| Tokenize card | POST /v1/payments/tokenize | token |
| Pay | POST /v1/payments/credit-card | status: autorizado |
| Confirm | Webhook order_approved | status: aprovado |
| Tracking | POST /v1/orders/shipping-tracking-code | Tracking linked |
Testing error scenarios
Use card 4000000000000028 to simulate a payment failure. The API will return:
{
"error": {
"message": "Payment not authorized"
}
}See more test cards in the credit card documentation.