Skip to content

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 -> Confirm

By the end of this guide you will have completed a full transaction in the sandbox.

Prerequisites


1. Authenticate

Obtain a Bearer token using the merchant's credentials.

bash
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'
json
{
  "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:

html
<!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.

bash
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"
  }
}'
json
{
  "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).

bash
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
}'
json
{
  "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:

bash
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"
    }
  }
}'
json
{
  "data": {
    "token": "422146c7523a46119d6073ea56193913"
  }
}

Step 2 -- Pay with the token:

bash
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"
    }
  }
}'
json
{
  "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.

bash
curl --request POST \
     --url https://api.sandboxappmax.com.br/v1/payments/pix \
     --header 'Authorization: Bearer YOUR_TOKEN' \
     --header 'Accept: application/json' \
     --header 'Content-Type: application/json' \
     --data '{
  "order_id": 3531,
  "payment_data": {
    "pix": {
      "document_number": "25226493029"
    }
  }
}'
json
{
  "data": {
    "order": {
      "id": 3531,
      "status": "pendente"
    },
    "pix": {
      "qr_code": "data:image/png;base64,iVBORw0KGgoAAAANS...",
      "emv_code": "00020126580014br.gov.bcb.pix0136a1b2c3d4...",
      "expires_at": "2025-03-15 15:30:00"
    }
  }
}

Display the qr_code as an image and the emv_code as copyable text. Wait for the order_paid_by_pix webhook for confirmation.

bash
curl --request POST \
     --url https://api.sandboxappmax.com.br/v1/payments/boleto \
     --header 'Authorization: Bearer YOUR_TOKEN' \
     --header 'Accept: application/json' \
     --header 'Content-Type: application/json' \
     --data '{
  "order_id": 3531,
  "payment_data": {
    "boleto": {
      "document_number": "25226493029"
    }
  }
}'
json
{
  "data": {
    "order": {
      "id": 3531,
      "status": "pendente"
    },
    "boleto": {
      "pdf_url": "https://boleto.sandboxappmax.com.br/pdf/abc123...",
      "digitable_line": "23793.38128 60000.000003 00000.000400 1 84340000012300",
      "due_date": "2025-03-22"
    }
  }
}

Offer the pdf_url as a download button and the digitable_line as copyable text. Wait for the order_paid webhook when the boleto is settled.


6. Confirm the payment

Confirmation is asynchronous. There are two ways to know the payment was approved:

Your endpoint will receive a POST when the status changes:

json
{
  "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:

bash
curl --request GET \
     --url https://api.sandboxappmax.com.br/v1/orders/3531 \
     --header 'Authorization: Bearer YOUR_TOKEN' \
     --header 'Accept: application/json'
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:

bash
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:

bash
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

StepEndpointResult
AuthenticatePOST /oauth2/tokenaccess_token
Create customerPOST /v1/customerscustomer_id
Create orderPOST /v1/ordersorder_id (status: pendente)
Tokenize cardPOST /v1/payments/tokenizetoken
PayPOST /v1/payments/credit-cardstatus: autorizado
ConfirmWebhook order_approvedstatus: aprovado
TrackingPOST /v1/orders/shipping-tracking-codeTracking linked

Testing error scenarios

Use card 4000000000000028 to simulate a payment failure. The API will return:

json
{
  "error": {
    "message": "Payment not authorized"
  }
}

See more test cards in the credit card documentation.


Next steps