MENU navbar-image

Introduction

API ClicPay v2 - M-Pesa, e-Mola, NetShop e autenticação

ClicPay API — v2

Visão geral

Esta documentação apresenta a API ClicPay v2, destinada à integração de soluções de pagamento (M-Pesa, e-Mola, Mkesh, NetShop), gestão de carteiras digitais e consulta de estados de transações.

Objetivo

Permitir que aplicações de terceiros criem e confirmem pagamentos, consultem o estado de transações, obtenham históricos e gerenciem carteiras de utilizadores de forma segura e auditável.

Autenticação

A API utiliza OAuth2 (Laravel Passport). Para testar endpoints protegidos na interface, insira um token Bearer através da opção Authorize. Sem um token válido, os pedidos autenticados irão retornar erros de autorização.

Testes e exemplos

Utilize a funcionalidade Try It Out para executar pedidos diretamente a partir da documentação. Os exemplos de código disponíveis no canto superior direito suportam Bash, JavaScript, PHP e Python.

Exemplos de pedidos e respostas

Sempre que possível, cada endpoint inclui exemplos de payloads de pedido e exemplos de resposta. Estes servem como referência, mas os valores reais podem variar conforme o ambiente (sandbox / produção).

Boas práticas de integração

Idempotência

Um timeout de rede não lhe diz se a cobrança saiu. Repetir arrisca cobrar duas vezes; não repetir perde o pagamento. A Idempotency-Key resolve isso: repetir um pedido com a mesma chave devolve a resposta original em vez de cobrar de novo.

Aplica-se a todos os POST de iniciação de pagamento: as seis rotas C2B (eMola, M-Pesa, mKesh, normais e /direct), card-payment e split/collect.

Como usar

A ordem das chaves do JSON não conta, e 100, 100.0 e "100.00" são o mesmo montante. Já a ordem dos elementos de splits[] conta, porque é significativa.

O que acontece a cada resposta

Resposta A chave fica Repetir com a mesma chave
200 / 201 sucesso guardada devolve o mesmo corpo
400 de validação guardada devolve o mesmo 400
4xx de rejeição do operador (com transaction_id) guardada devolve o mesmo corpo
500 com transaction_id guardada devolve o mesmo 500; consulte /transactions/{referencia}/status
401, 403, 429 libertada processa de novo
500 sem transaction_id libertada processa de novo
409 em curso retida espere o Retry-After e repita

A regra por trás da tabela: a chave só é libertada quando é certo que nada aconteceu. Se a transacção chegou a existir, a resposta fica guardada, mesmo sendo um erro, porque o operador pode já ter sido contactado.

Os dois erros que vai encontrar

Quando a M-Pesa diz que o pedido e repetido

A M-Pesa tambem deduplica do lado dela, pela referencia que lhe enviamos. Se reconhecer um pedido como repeticao de uma cobranca anterior devolve INS-10, e a ClicPay responde 200 com status em PROCESSING e provider_response_code igual a INS-10.

Isso NAO e uma falha. E o contrario: significa que a cobranca anterior seguiu. A accao correcta e consultar /transactions/{referencia}/status, nunca repetir. O mesmo vale para INS-9, em que a M-Pesa nao respondeu a tempo e o desfecho e desconhecido: a transacao fica em PROCESSING e resolve-se por consulta.

A regra geral, que vale para os tres operadores: um estado nao-terminal nunca autoriza uma segunda cobranca. Consulte antes de repetir.

Confirmar um pagamento: o polling e a fonte de verdade

O webhook e aceleracao, nao garantia. Perde-se. A forma oficial de confirmar um pagamento e GET /transactions/{referencia}/status, que pergunta ao operador quando a transacao ainda nao esta num estado final.

Nunca repita uma cobranca por causa de um estado nao-terminal. Consulte. Repetir e o que produz o pagamento duplicado, e para isso serve a Idempotency-Key descrita acima.

Um detalhe do card-payment: o replay devolve a sessão de checkout original, que pode já ter expirado do lado do NetShop. Isso é intencional, porque o replay é o registo da resposta original. Se precisa de uma sessão nova, use uma chave nova, que é o que semanticamente descreve um pagamento novo.

Authenticating requests

To authenticate requests, include an Authorization header with the value "Bearer {YOUR_AUTH_KEY}".

All authenticated endpoints are marked with a requires authentication badge in the documentation below.

Para testar a API, insira seu token Bearer no campo "Authorize". Você pode obter um token através do endpoint de autenticação da API.

Transações M-Pesa

Iniciar cobrança C2B M-Pesa

requires authentication

Idempotência. Envie Idempotency-Key com um valor único por tentativa de pagamento (UUID v4 recomendado, máximo 128 caracteres). Repetir o pedido com a mesma chave e o mesmo corpo devolve a resposta guardada, com o mesmo estado HTTP e o mesmo clicpay_reference, acompanhada do cabeçalho Idempotent-Replayed: true, sem contactar o operador e sem criar uma segunda transacção. A chave é privada da sua conta e vale 48 horas. Sem o cabeçalho, o comportamento é o de sempre.

Em 409, outro pedido com essa chave ainda está a ser processado: espere o Retry-After e repita com a mesma chave. Gerar uma chave nova nesse momento é o caminho para o pagamento duplicado.

Example request:
curl --request POST \
    "https://clicpay.co.mz/api/v2/wallets/115665/c2b/mpesa" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Idempotency-Key: 9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"msisdn\": \"841234567\",
    \"amount\": 1000,
    \"reference_description\": \"Pagamento de serviços\",
    \"internal_notes\": \"Pedido #9001\",
    \"splits\": [
        \"architecto\"
    ]
}"
const url = new URL(
    "https://clicpay.co.mz/api/v2/wallets/115665/c2b/mpesa"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Idempotency-Key": "9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "msisdn": "841234567",
    "amount": 1000,
    "reference_description": "Pagamento de serviços",
    "internal_notes": "Pedido #9001",
    "splits": [
        "architecto"
    ]
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://clicpay.co.mz/api/v2/wallets/115665/c2b/mpesa';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Idempotency-Key' => '9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'msisdn' => '841234567',
            'amount' => 1000.0,
            'reference_description' => 'Pagamento de serviços',
            'internal_notes' => 'Pedido #9001',
            'splits' => [
                'architecto',
            ],
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://clicpay.co.mz/api/v2/wallets/115665/c2b/mpesa'
payload = {
    "msisdn": "841234567",
    "amount": 1000,
    "reference_description": "Pagamento de serviços",
    "internal_notes": "Pedido #9001",
    "splits": [
        "architecto"
    ]
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Idempotency-Key': '9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()

Example response (200):


{
    "message": "Transação iniciada com sucesso",
    "clicpay_reference": "CPAYMPSESC2BABCDE12345",
    "status": "pending",
    "transaction_id": 789,
    "split_summary": {
        "direct": [],
        "collect": []
    }
}
 

Example response (401):


{
    "message": "Unauthenticated."
}
 

Example response (409, Pedido anterior com a mesma chave ainda em curso):


{
    "error": "idempotency_request_in_progress",
    "message": "Um pedido com esta Idempotency-Key ainda está a ser processado. Aguarde e repita com a MESMA chave.",
    "idempotency_key": "9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11",
    "retry_after_seconds": 12
}
 

Example response (422, Erro de validação):


{
    "errors": {
        "splits.0.wallet_split_id": [
            "O split não pertence a esta carteira ou não é dynamic_load."
        ]
    }
}
 

Example response (422, Idempotency-Key reutilizada com um corpo diferente):


{
    "error": "idempotency_key_reused_with_different_payload",
    "message": "Esta Idempotency-Key já foi usada com um corpo diferente.",
    "idempotency_key": "9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11"
}
 

Example response (422, Idempotency-Key com formato inválido):


{
    "error": "idempotency_key_invalid",
    "message": "O cabeçalho Idempotency-Key deve ter entre 1 e 128 caracteres.",
    "max_length": 128
}
 

Request      

POST api/v2/wallets/{wallet_id}/c2b/mpesa

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Idempotency-Key        

Example: 9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

wallet_id   integer     

The ID of the wallet. Example: 115665

wallet   integer     

ID da carteira M-Pesa. Example: 12

Body Parameters

msisdn   string     

MSISDN do pagador. Example: 841234567

amount   number     

Valor total a cobrar (1–150 000 MZN). Example: 1000

reference_description   string     

Descrição visível ao pagador (3–32 caracteres). Example: Pagamento de serviços

internal_notes   string  optional    

optional Notas internas (máx. 255 caracteres). Example: Pedido #9001

splits   string[]  optional    

optional Alocações dinâmicas para sub-carteiras do tipo dynamic_load desta carteira. Opcional — omitir mantém o comportamento normal.

wallet_split_id   integer     

ID do WalletSplit (deve ser dynamic_load e pertencer a esta carteira). Example: 42

value_type   string     

percentage ou amount. Example: percentage

value   number     

Percentagem (0–100) ou montante fixo em MZN. Example: 30

recipients   string[]  optional    

optional Com recipients → B2C Direct. Sem recipients → Wallet Collect. Percentagens devem somar 100.

identifier   string     

MSISDN do destinatário. Example: 841234567

percentage   number     

Percentagem (0.01–100). Example: 100

Iniciar cobrança C2B M-Pesa (direct)

requires authentication

Idempotência. Envie Idempotency-Key com um valor único por tentativa de pagamento (UUID v4 recomendado, máximo 128 caracteres). Repetir o pedido com a mesma chave e o mesmo corpo devolve a resposta guardada, com o mesmo estado HTTP e o mesmo clicpay_reference, acompanhada do cabeçalho Idempotent-Replayed: true, sem contactar o operador e sem criar uma segunda transacção. A chave é privada da sua conta e vale 48 horas. Sem o cabeçalho, o comportamento é o de sempre.

Em 409, outro pedido com essa chave ainda está a ser processado: espere o Retry-After e repita com a mesma chave. Gerar uma chave nova nesse momento é o caminho para o pagamento duplicado.

Example request:
curl --request POST \
    "https://clicpay.co.mz/api/v2/wallets/115665/c2b/mpesa/direct" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Idempotency-Key: 9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"msisdn\": \"841234567\",
    \"amount\": 1000,
    \"reference_description\": \"Pagamento de serviços\",
    \"internal_notes\": \"Pedido #9001\",
    \"splits\": [
        \"architecto\"
    ]
}"
const url = new URL(
    "https://clicpay.co.mz/api/v2/wallets/115665/c2b/mpesa/direct"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Idempotency-Key": "9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "msisdn": "841234567",
    "amount": 1000,
    "reference_description": "Pagamento de serviços",
    "internal_notes": "Pedido #9001",
    "splits": [
        "architecto"
    ]
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://clicpay.co.mz/api/v2/wallets/115665/c2b/mpesa/direct';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Idempotency-Key' => '9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'msisdn' => '841234567',
            'amount' => 1000.0,
            'reference_description' => 'Pagamento de serviços',
            'internal_notes' => 'Pedido #9001',
            'splits' => [
                'architecto',
            ],
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://clicpay.co.mz/api/v2/wallets/115665/c2b/mpesa/direct'
payload = {
    "msisdn": "841234567",
    "amount": 1000,
    "reference_description": "Pagamento de serviços",
    "internal_notes": "Pedido #9001",
    "splits": [
        "architecto"
    ]
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Idempotency-Key': '9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()

Example response (200):


{
    "message": "Transação iniciada com sucesso",
    "clicpay_reference": "CPAYMPSESC2BABCDE12345",
    "status": "pending",
    "transaction_id": 789,
    "split_summary": {
        "direct": [],
        "collect": []
    }
}
 

Example response (401):


{
    "message": "Unauthenticated."
}
 

Example response (409, Pedido anterior com a mesma chave ainda em curso):


{
    "error": "idempotency_request_in_progress",
    "message": "Um pedido com esta Idempotency-Key ainda está a ser processado. Aguarde e repita com a MESMA chave.",
    "idempotency_key": "9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11",
    "retry_after_seconds": 12
}
 

Example response (422, Erro de validação):


{
    "errors": {
        "splits.0.value_type": [
            "O campo value_type deve ser percentage ou amount."
        ]
    }
}
 

Example response (422, Idempotency-Key reutilizada com um corpo diferente):


{
    "error": "idempotency_key_reused_with_different_payload",
    "message": "Esta Idempotency-Key já foi usada com um corpo diferente.",
    "idempotency_key": "9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11"
}
 

Example response (422, Idempotency-Key com formato inválido):


{
    "error": "idempotency_key_invalid",
    "message": "O cabeçalho Idempotency-Key deve ter entre 1 e 128 caracteres.",
    "max_length": 128
}
 

Request      

POST api/v2/wallets/{wallet_id}/c2b/mpesa/direct

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Idempotency-Key        

Example: 9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

wallet_id   integer     

The ID of the wallet. Example: 115665

wallet   integer     

ID da carteira M-Pesa. Example: 12

Body Parameters

msisdn   string     

MSISDN do pagador. Example: 841234567

amount   number     

Valor total a cobrar (1–150 000 MZN). Example: 1000

reference_description   string     

Descrição visível ao pagador (3–32 caracteres). Example: Pagamento de serviços

internal_notes   string  optional    

optional Notas internas (máx. 255 caracteres). Example: Pedido #9001

splits   string[]  optional    

optional Alocações dinâmicas para sub-carteiras do tipo dynamic_load desta carteira. Opcional — omitir mantém o comportamento normal.

wallet_split_id   integer     

ID do WalletSplit (deve ser dynamic_load e pertencer a esta carteira). Example: 42

value_type   string     

percentage ou amount. Example: percentage

value   number     

Percentagem (0–100) ou montante fixo em MZN. Example: 30

recipients   string[]  optional    

optional Com recipients → B2C Direct. Sem recipients → Wallet Collect. Percentagens devem somar 100.

identifier   string     

MSISDN do destinatário. Example: 841234567

percentage   number     

Percentagem (0.01–100). Example: 100

POST api/v2/wallets/{wallet_id}/b2c/mpesa

requires authentication

Example request:
curl --request POST \
    "https://clicpay.co.mz/api/v2/wallets/115665/b2c/mpesa" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"msisdn\": \"841234567\",
    \"amount\": 500,
    \"reference_description\": \"Compra online\",
    \"internal_notes\": \"Pedido #12345\"
}"
const url = new URL(
    "https://clicpay.co.mz/api/v2/wallets/115665/b2c/mpesa"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "msisdn": "841234567",
    "amount": 500,
    "reference_description": "Compra online",
    "internal_notes": "Pedido #12345"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://clicpay.co.mz/api/v2/wallets/115665/b2c/mpesa';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'msisdn' => '841234567',
            'amount' => 500.0,
            'reference_description' => 'Compra online',
            'internal_notes' => 'Pedido #12345',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://clicpay.co.mz/api/v2/wallets/115665/b2c/mpesa'
payload = {
    "msisdn": "841234567",
    "amount": 500,
    "reference_description": "Compra online",
    "internal_notes": "Pedido #12345"
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()

Example response (200):


{
    "message": "Transação iniciada com sucesso",
    "clicpay_reference": "CP123456789",
    "status": "pending",
    "transaction_id": 124
}
 

Example response (400):


{
    "errors": {
        "msisdn": [
            "Número de telefone inválido"
        ],
        "amount": [
            "Valor deve ser entre 1 e 50000"
        ]
    }
}
 

Example response (401):


{
    "message": "Unauthenticated."
}
 

Example response (403):


{
    "message": "Acesso negado à carteira"
}
 

Request      

POST api/v2/wallets/{wallet_id}/b2c/mpesa

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

wallet_id   integer     

The ID of the wallet. Example: 115665

Body Parameters

msisdn   string     

Número de telefone Example: 841234567

amount   number     

Valor da transação (1-50000) Example: 500

reference_description   string     

Descrição da referência (3-32 caracteres) Example: Compra online

internal_notes   string  optional    

optional Notas internas (máx 255 caracteres) Example: Pedido #12345

Response

Response Fields

clicpay_reference   string     

Referência única da transação

status   string     

Status atual (pending/successful/failed)

transaction_id   integer     

ID interno da transação

Transações eMola

Iniciar cobrança C2B eMola

requires authentication

Idempotência. Envie Idempotency-Key com um valor único por tentativa de pagamento (UUID v4 recomendado, máximo 128 caracteres). Repetir o pedido com a mesma chave e o mesmo corpo devolve a resposta guardada, com o mesmo estado HTTP e o mesmo clicpay_reference, acompanhada do cabeçalho Idempotent-Replayed: true, sem contactar o operador e sem criar uma segunda transacção. A chave é privada da sua conta e vale 48 horas. Sem o cabeçalho, o comportamento é o de sempre.

Em 409, outro pedido com essa chave ainda está a ser processado: espere o Retry-After e repita com a mesma chave. Gerar uma chave nova nesse momento é o caminho para o pagamento duplicado.

Example request:
curl --request POST \
    "https://clicpay.co.mz/api/v2/wallets/115665/c2b/emola" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Idempotency-Key: 9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"msisdn\": \"841234567\",
    \"amount\": 1000,
    \"reference_description\": \"Pagamento de serviços\",
    \"internal_notes\": \"Pedido #9001\",
    \"splits\": [
        \"architecto\"
    ]
}"
const url = new URL(
    "https://clicpay.co.mz/api/v2/wallets/115665/c2b/emola"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Idempotency-Key": "9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "msisdn": "841234567",
    "amount": 1000,
    "reference_description": "Pagamento de serviços",
    "internal_notes": "Pedido #9001",
    "splits": [
        "architecto"
    ]
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://clicpay.co.mz/api/v2/wallets/115665/c2b/emola';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Idempotency-Key' => '9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'msisdn' => '841234567',
            'amount' => 1000.0,
            'reference_description' => 'Pagamento de serviços',
            'internal_notes' => 'Pedido #9001',
            'splits' => [
                'architecto',
            ],
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://clicpay.co.mz/api/v2/wallets/115665/c2b/emola'
payload = {
    "msisdn": "841234567",
    "amount": 1000,
    "reference_description": "Pagamento de serviços",
    "internal_notes": "Pedido #9001",
    "splits": [
        "architecto"
    ]
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Idempotency-Key': '9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()

Example response (200):


{
    "message": "Transação iniciada com sucesso",
    "clicpay_reference": "CPAYEMOLAC2BABCDE12345",
    "status": "pending",
    "transaction_id": 789,
    "provider_reference": null,
    "provider_response_code": "0",
    "split_summary": {
        "direct": [
            {
                "wallet_split_id": 42,
                "mode": "b2c_direct",
                "allocated": 300,
                "recipients": [
                    {
                        "msisdn": "841234567",
                        "amount": 300
                    }
                ]
            }
        ],
        "collect": [
            {
                "wallet_split_id": 43,
                "mode": "wallet_collect",
                "allocated": 200
            }
        ]
    }
}
 

Example response (400):


{
    "message": "Erro do provedor",
    "clicpay_reference": "CPAY...",
    "status": "failed"
}
 

Example response (401):


{
    "message": "Unauthenticated."
}
 

Example response (403):


{
    "message": "Sem acesso à carteira ou carteira inactiva."
}
 

Example response (409, Pedido anterior com a mesma chave ainda em curso):


{
    "error": "idempotency_request_in_progress",
    "message": "Um pedido com esta Idempotency-Key ainda está a ser processado. Aguarde e repita com a MESMA chave.",
    "idempotency_key": "9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11",
    "retry_after_seconds": 12
}
 

Example response (422, Erro de validação):


{
    "errors": {
        "splits.0.wallet_split_id": [
            "O split não pertence a esta carteira ou não é dynamic_load."
        ]
    }
}
 

Example response (422, Idempotency-Key reutilizada com um corpo diferente):


{
    "error": "idempotency_key_reused_with_different_payload",
    "message": "Esta Idempotency-Key já foi usada com um corpo diferente.",
    "idempotency_key": "9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11"
}
 

Example response (422, Idempotency-Key com formato inválido):


{
    "error": "idempotency_key_invalid",
    "message": "O cabeçalho Idempotency-Key deve ter entre 1 e 128 caracteres.",
    "max_length": 128
}
 

Request      

POST api/v2/wallets/{wallet_id}/c2b/emola

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Idempotency-Key        

Example: 9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

wallet_id   integer     

The ID of the wallet. Example: 115665

wallet   integer     

ID da carteira eMola. Example: 12

Body Parameters

msisdn   string     

MSISDN do pagador. Example: 841234567

amount   number     

Valor total a cobrar (1–150 000 MZN). Example: 1000

reference_description   string     

Descrição visível ao pagador (3–32 caracteres). Example: Pagamento de serviços

internal_notes   string  optional    

optional Notas internas (máx. 255 caracteres). Example: Pedido #9001

splits   string[]  optional    

optional Alocações dinâmicas para sub-carteiras do tipo dynamic_load desta carteira. Opcional — omitir mantém o comportamento normal.

wallet_split_id   integer     

ID do WalletSplit (deve ser dynamic_load e pertencer a esta carteira). Example: 42

value_type   string     

percentage aplica % sobre o amount total; amount é um valor fixo em MZN. Example: percentage

value   number     

Percentagem (0–100) ou montante fixo em MZN. Automaticamente reduzido se o split tiver limite (max_amount). Example: 30

recipients   string[]  optional    

optional Presente → modo B2C Direct: o valor alocado é disbursado imediatamente. Ausente → modo Wallet Collect: acumula saldo. Percentagens devem somar 100.

identifier   string     

MSISDN do destinatário. Example: 841234567

percentage   number     

Percentagem do valor alocado a este destinatário (0.01–100). Example: 100

Response

Response Fields

clicpay_reference   string     

Referência única da transação ClicPay.

status   string     

Estado actual: pending | successful | failed.

split_summary   object     

Presente quando splits[] foi enviado. direct lista B2C imediatos; collect lista acumulações. Splits ignorados (inactivos, limite atingido) não aparecem.

Iniciar cobrança C2B eMola (direct)

requires authentication

Idempotência. Envie Idempotency-Key com um valor único por tentativa de pagamento (UUID v4 recomendado, máximo 128 caracteres). Repetir o pedido com a mesma chave e o mesmo corpo devolve a resposta guardada, com o mesmo estado HTTP e o mesmo clicpay_reference, acompanhada do cabeçalho Idempotent-Replayed: true, sem contactar o operador e sem criar uma segunda transacção. A chave é privada da sua conta e vale 48 horas. Sem o cabeçalho, o comportamento é o de sempre.

Em 409, outro pedido com essa chave ainda está a ser processado: espere o Retry-After e repita com a mesma chave. Gerar uma chave nova nesse momento é o caminho para o pagamento duplicado.

Example request:
curl --request POST \
    "https://clicpay.co.mz/api/v2/wallets/115665/c2b/emola/direct" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Idempotency-Key: 9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"msisdn\": \"841234567\",
    \"amount\": 1000,
    \"reference_description\": \"Pagamento de serviços\",
    \"internal_notes\": \"Pedido #9001\",
    \"splits\": [
        \"architecto\"
    ]
}"
const url = new URL(
    "https://clicpay.co.mz/api/v2/wallets/115665/c2b/emola/direct"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Idempotency-Key": "9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "msisdn": "841234567",
    "amount": 1000,
    "reference_description": "Pagamento de serviços",
    "internal_notes": "Pedido #9001",
    "splits": [
        "architecto"
    ]
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://clicpay.co.mz/api/v2/wallets/115665/c2b/emola/direct';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Idempotency-Key' => '9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'msisdn' => '841234567',
            'amount' => 1000.0,
            'reference_description' => 'Pagamento de serviços',
            'internal_notes' => 'Pedido #9001',
            'splits' => [
                'architecto',
            ],
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://clicpay.co.mz/api/v2/wallets/115665/c2b/emola/direct'
payload = {
    "msisdn": "841234567",
    "amount": 1000,
    "reference_description": "Pagamento de serviços",
    "internal_notes": "Pedido #9001",
    "splits": [
        "architecto"
    ]
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Idempotency-Key': '9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()

Example response (200):


{
    "message": "Transação iniciada com sucesso",
    "clicpay_reference": "CPAYEMOLAC2BABCDE12345",
    "status": "pending",
    "transaction_id": 789,
    "split_summary": {
        "direct": [],
        "collect": []
    }
}
 

Example response (401):


{
    "message": "Unauthenticated."
}
 

Example response (409, Pedido anterior com a mesma chave ainda em curso):


{
    "error": "idempotency_request_in_progress",
    "message": "Um pedido com esta Idempotency-Key ainda está a ser processado. Aguarde e repita com a MESMA chave.",
    "idempotency_key": "9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11",
    "retry_after_seconds": 12
}
 

Example response (422, Erro de validação):


{
    "errors": {
        "splits.0.value_type": [
            "O campo value_type deve ser percentage ou amount."
        ]
    }
}
 

Example response (422, Idempotency-Key reutilizada com um corpo diferente):


{
    "error": "idempotency_key_reused_with_different_payload",
    "message": "Esta Idempotency-Key já foi usada com um corpo diferente.",
    "idempotency_key": "9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11"
}
 

Example response (422, Idempotency-Key com formato inválido):


{
    "error": "idempotency_key_invalid",
    "message": "O cabeçalho Idempotency-Key deve ter entre 1 e 128 caracteres.",
    "max_length": 128
}
 

Request      

POST api/v2/wallets/{wallet_id}/c2b/emola/direct

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Idempotency-Key        

Example: 9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

wallet_id   integer     

The ID of the wallet. Example: 115665

wallet   integer     

ID da carteira eMola. Example: 12

Body Parameters

msisdn   string     

MSISDN do pagador. Example: 841234567

amount   number     

Valor total a cobrar (1–150 000 MZN). Example: 1000

reference_description   string     

Descrição visível ao pagador (3–32 caracteres). Example: Pagamento de serviços

internal_notes   string  optional    

optional Notas internas (máx. 255 caracteres). Example: Pedido #9001

splits   string[]  optional    

optional Alocações dinâmicas para sub-carteiras do tipo dynamic_load desta carteira. Opcional — omitir mantém o comportamento normal.

wallet_split_id   integer     

ID do WalletSplit (deve ser dynamic_load e pertencer a esta carteira). Example: 42

value_type   string     

percentage ou amount. Example: percentage

value   number     

Percentagem (0–100) ou montante fixo em MZN. Example: 30

recipients   string[]  optional    

optional Com recipients → B2C Direct. Sem recipients → Wallet Collect. Percentagens devem somar 100.

identifier   string     

MSISDN do destinatário. Example: 841234567

percentage   number     

Percentagem (0.01–100). Example: 100

POST api/v2/wallets/{wallet_id}/b2c/emola

requires authentication

Example request:
curl --request POST \
    "https://clicpay.co.mz/api/v2/wallets/115665/b2c/emola" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"msisdn\": \"841234567\",
    \"amount\": 1000,
    \"reference_description\": \"Pagamento de serviços\",
    \"internal_notes\": \"Pagamento mensal\"
}"
const url = new URL(
    "https://clicpay.co.mz/api/v2/wallets/115665/b2c/emola"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "msisdn": "841234567",
    "amount": 1000,
    "reference_description": "Pagamento de serviços",
    "internal_notes": "Pagamento mensal"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://clicpay.co.mz/api/v2/wallets/115665/b2c/emola';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'msisdn' => '841234567',
            'amount' => 1000.0,
            'reference_description' => 'Pagamento de serviços',
            'internal_notes' => 'Pagamento mensal',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://clicpay.co.mz/api/v2/wallets/115665/b2c/emola'
payload = {
    "msisdn": "841234567",
    "amount": 1000,
    "reference_description": "Pagamento de serviços",
    "internal_notes": "Pagamento mensal"
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()

Example response (200):


{
    "message": "Transação iniciada com sucesso",
    "clicpay_reference": "CP123456789",
    "status": "pending",
    "transaction_id": 123
}
 

Example response (400):


{
    "errors": {
        "msisdn": [
            "Número de telefone inválido"
        ],
        "amount": [
            "Valor deve ser entre 1 e 50000"
        ]
    }
}
 

Example response (401):


{
    "message": "Unauthenticated."
}
 

Example response (403):


{
    "message": "Acesso negado à carteira"
}
 

Request      

POST api/v2/wallets/{wallet_id}/b2c/emola

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

wallet_id   integer     

The ID of the wallet. Example: 115665

Body Parameters

msisdn   string     

Número de telefone Example: 841234567

amount   number     

Valor da transação (1-50000) Example: 1000

reference_description   string     

Descrição da referência (3-32 caracteres) Example: Pagamento de serviços

internal_notes   string  optional    

optional Notas internas (máx 255 caracteres) Example: Pagamento mensal

Response

Response Fields

clicpay_reference   string     

Referência única da transação

status   string     

Status atual (pending/successful/failed)

transaction_id   integer     

ID interno da transação

Transações Mkesh

Iniciar cobrança C2B mKesh

requires authentication

Idempotência. Envie Idempotency-Key com um valor único por tentativa de pagamento (UUID v4 recomendado, máximo 128 caracteres). Repetir o pedido com a mesma chave e o mesmo corpo devolve a resposta guardada, com o mesmo estado HTTP e o mesmo clicpay_reference, acompanhada do cabeçalho Idempotent-Replayed: true, sem contactar o operador e sem criar uma segunda transacção. A chave é privada da sua conta e vale 48 horas. Sem o cabeçalho, o comportamento é o de sempre.

Em 409, outro pedido com essa chave ainda está a ser processado: espere o Retry-After e repita com a mesma chave. Gerar uma chave nova nesse momento é o caminho para o pagamento duplicado.

Example request:
curl --request POST \
    "https://clicpay.co.mz/api/v2/wallets/115665/c2b/mkesh" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Idempotency-Key: 9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"msisdn\": \"841234567\",
    \"amount\": 1000,
    \"reference_description\": \"Pagamento de serviços\",
    \"internal_notes\": \"Pedido #9001\",
    \"splits\": [
        \"architecto\"
    ]
}"
const url = new URL(
    "https://clicpay.co.mz/api/v2/wallets/115665/c2b/mkesh"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Idempotency-Key": "9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "msisdn": "841234567",
    "amount": 1000,
    "reference_description": "Pagamento de serviços",
    "internal_notes": "Pedido #9001",
    "splits": [
        "architecto"
    ]
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://clicpay.co.mz/api/v2/wallets/115665/c2b/mkesh';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Idempotency-Key' => '9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'msisdn' => '841234567',
            'amount' => 1000.0,
            'reference_description' => 'Pagamento de serviços',
            'internal_notes' => 'Pedido #9001',
            'splits' => [
                'architecto',
            ],
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://clicpay.co.mz/api/v2/wallets/115665/c2b/mkesh'
payload = {
    "msisdn": "841234567",
    "amount": 1000,
    "reference_description": "Pagamento de serviços",
    "internal_notes": "Pedido #9001",
    "splits": [
        "architecto"
    ]
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Idempotency-Key': '9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()

Example response (200):


{
    "message": "Transação iniciada com sucesso",
    "clicpay_reference": "CPAYKMESHC2BABCDE12345",
    "status": "pending",
    "transaction_id": 789,
    "split_summary": {
        "direct": [],
        "collect": []
    }
}
 

Example response (401):


{
    "message": "Unauthenticated."
}
 

Example response (409, Pedido anterior com a mesma chave ainda em curso):


{
    "error": "idempotency_request_in_progress",
    "message": "Um pedido com esta Idempotency-Key ainda está a ser processado. Aguarde e repita com a MESMA chave.",
    "idempotency_key": "9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11",
    "retry_after_seconds": 12
}
 

Example response (422, Erro de validação):


{
    "errors": {
        "splits.0.wallet_split_id": [
            "O split não pertence a esta carteira ou não é dynamic_load."
        ]
    }
}
 

Example response (422, Idempotency-Key reutilizada com um corpo diferente):


{
    "error": "idempotency_key_reused_with_different_payload",
    "message": "Esta Idempotency-Key já foi usada com um corpo diferente.",
    "idempotency_key": "9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11"
}
 

Example response (422, Idempotency-Key com formato inválido):


{
    "error": "idempotency_key_invalid",
    "message": "O cabeçalho Idempotency-Key deve ter entre 1 e 128 caracteres.",
    "max_length": 128
}
 

Request      

POST api/v2/wallets/{wallet_id}/c2b/mkesh

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Idempotency-Key        

Example: 9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

wallet_id   integer     

The ID of the wallet. Example: 115665

wallet   integer     

ID da carteira Mkesh. Example: 12

Body Parameters

msisdn   string     

MSISDN do pagador. Example: 841234567

amount   number     

Valor total a cobrar (1–150 000 MZN). Example: 1000

reference_description   string     

Descrição visível ao pagador (3–32 caracteres). Example: Pagamento de serviços

internal_notes   string  optional    

optional Notas internas (máx. 255 caracteres). Example: Pedido #9001

splits   string[]  optional    

optional Alocações dinâmicas para sub-carteiras do tipo dynamic_load desta carteira. Opcional — omitir mantém o comportamento normal.

wallet_split_id   integer     

ID do WalletSplit (deve ser dynamic_load e pertencer a esta carteira). Example: 42

value_type   string     

percentage ou amount. Example: percentage

value   number     

Percentagem (0–100) ou montante fixo em MZN. Example: 30

recipients   string[]  optional    

optional Com recipients → B2C Direct. Sem recipients → Wallet Collect. Percentagens devem somar 100.

identifier   string     

MSISDN do destinatário. Example: 841234567

percentage   number     

Percentagem (0.01–100). Example: 100

Iniciar cobrança C2B mKesh (direct)

requires authentication

Idempotência. Envie Idempotency-Key com um valor único por tentativa de pagamento (UUID v4 recomendado, máximo 128 caracteres). Repetir o pedido com a mesma chave e o mesmo corpo devolve a resposta guardada, com o mesmo estado HTTP e o mesmo clicpay_reference, acompanhada do cabeçalho Idempotent-Replayed: true, sem contactar o operador e sem criar uma segunda transacção. A chave é privada da sua conta e vale 48 horas. Sem o cabeçalho, o comportamento é o de sempre.

Em 409, outro pedido com essa chave ainda está a ser processado: espere o Retry-After e repita com a mesma chave. Gerar uma chave nova nesse momento é o caminho para o pagamento duplicado.

Example request:
curl --request POST \
    "https://clicpay.co.mz/api/v2/wallets/115665/c2b/mkesh/direct" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Idempotency-Key: 9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"msisdn\": \"841234567\",
    \"amount\": 1000,
    \"reference_description\": \"Pagamento de serviços\",
    \"internal_notes\": \"Pedido #9001\",
    \"splits\": [
        \"architecto\"
    ]
}"
const url = new URL(
    "https://clicpay.co.mz/api/v2/wallets/115665/c2b/mkesh/direct"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Idempotency-Key": "9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "msisdn": "841234567",
    "amount": 1000,
    "reference_description": "Pagamento de serviços",
    "internal_notes": "Pedido #9001",
    "splits": [
        "architecto"
    ]
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://clicpay.co.mz/api/v2/wallets/115665/c2b/mkesh/direct';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Idempotency-Key' => '9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'msisdn' => '841234567',
            'amount' => 1000.0,
            'reference_description' => 'Pagamento de serviços',
            'internal_notes' => 'Pedido #9001',
            'splits' => [
                'architecto',
            ],
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://clicpay.co.mz/api/v2/wallets/115665/c2b/mkesh/direct'
payload = {
    "msisdn": "841234567",
    "amount": 1000,
    "reference_description": "Pagamento de serviços",
    "internal_notes": "Pedido #9001",
    "splits": [
        "architecto"
    ]
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Idempotency-Key': '9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()

Example response (200):


{
    "message": "Transação iniciada com sucesso",
    "clicpay_reference": "CPAYKMESHC2BABCDE12345",
    "status": "pending",
    "transaction_id": 789,
    "split_summary": {
        "direct": [],
        "collect": []
    }
}
 

Example response (401):


{
    "message": "Unauthenticated."
}
 

Example response (409, Pedido anterior com a mesma chave ainda em curso):


{
    "error": "idempotency_request_in_progress",
    "message": "Um pedido com esta Idempotency-Key ainda está a ser processado. Aguarde e repita com a MESMA chave.",
    "idempotency_key": "9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11",
    "retry_after_seconds": 12
}
 

Example response (422, Erro de validação):


{
    "errors": {
        "splits.0.value_type": [
            "O campo value_type deve ser percentage ou amount."
        ]
    }
}
 

Example response (422, Idempotency-Key reutilizada com um corpo diferente):


{
    "error": "idempotency_key_reused_with_different_payload",
    "message": "Esta Idempotency-Key já foi usada com um corpo diferente.",
    "idempotency_key": "9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11"
}
 

Example response (422, Idempotency-Key com formato inválido):


{
    "error": "idempotency_key_invalid",
    "message": "O cabeçalho Idempotency-Key deve ter entre 1 e 128 caracteres.",
    "max_length": 128
}
 

Request      

POST api/v2/wallets/{wallet_id}/c2b/mkesh/direct

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Idempotency-Key        

Example: 9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

wallet_id   integer     

The ID of the wallet. Example: 115665

wallet   integer     

ID da carteira Mkesh. Example: 12

Body Parameters

msisdn   string     

MSISDN do pagador. Example: 841234567

amount   number     

Valor total a cobrar (1–150 000 MZN). Example: 1000

reference_description   string     

Descrição visível ao pagador (3–32 caracteres). Example: Pagamento de serviços

internal_notes   string  optional    

optional Notas internas (máx. 255 caracteres). Example: Pedido #9001

splits   string[]  optional    

optional Alocações dinâmicas para sub-carteiras do tipo dynamic_load desta carteira. Opcional — omitir mantém o comportamento normal.

wallet_split_id   integer     

ID do WalletSplit (deve ser dynamic_load e pertencer a esta carteira). Example: 42

value_type   string     

percentage ou amount. Example: percentage

value   number     

Percentagem (0–100) ou montante fixo em MZN. Example: 30

recipients   string[]  optional    

optional Com recipients → B2C Direct. Sem recipients → Wallet Collect. Percentagens devem somar 100.

identifier   string     

MSISDN do destinatário. Example: 841234567

percentage   number     

Percentagem (0.01–100). Example: 100

POST api/v2/wallets/{wallet_id}/b2c/mkesh

requires authentication

Example request:
curl --request POST \
    "https://clicpay.co.mz/api/v2/wallets/115665/b2c/mkesh" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"msisdn\": \"841234567\",
    \"amount\": 500,
    \"reference_description\": \"Compra online\",
    \"internal_notes\": \"Pedido #12345\"
}"
const url = new URL(
    "https://clicpay.co.mz/api/v2/wallets/115665/b2c/mkesh"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "msisdn": "841234567",
    "amount": 500,
    "reference_description": "Compra online",
    "internal_notes": "Pedido #12345"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://clicpay.co.mz/api/v2/wallets/115665/b2c/mkesh';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'msisdn' => '841234567',
            'amount' => 500.0,
            'reference_description' => 'Compra online',
            'internal_notes' => 'Pedido #12345',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://clicpay.co.mz/api/v2/wallets/115665/b2c/mkesh'
payload = {
    "msisdn": "841234567",
    "amount": 500,
    "reference_description": "Compra online",
    "internal_notes": "Pedido #12345"
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()

Example response (200):


{
    "message": "Transação iniciada com sucesso",
    "clicpay_reference": "CP123456789",
    "status": "pending",
    "transaction_id": 124
}
 

Example response (400):


{
    "errors": {
        "msisdn": [
            "Número de telefone inválido"
        ],
        "amount": [
            "Valor deve ser entre 1 e 50000"
        ]
    }
}
 

Example response (401):


{
    "message": "Unauthenticated."
}
 

Example response (403):


{
    "message": "Acesso negado à carteira"
}
 

Request      

POST api/v2/wallets/{wallet_id}/b2c/mkesh

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

wallet_id   integer     

The ID of the wallet. Example: 115665

Body Parameters

msisdn   string     

Número de telefone Example: 841234567

amount   number     

Valor da transação (1-50000) Example: 500

reference_description   string     

Descrição da referência (3-32 caracteres) Example: Compra online

internal_notes   string  optional    

optional Notas internas (máx 255 caracteres) Example: Pedido #12345

Response

Response Fields

clicpay_reference   string     

Referência única da transação

status   string     

Status atual (pending/successful/failed)

transaction_id   integer     

ID interno da transação

Transações NetShop

Iniciar pagamento por cartão

requires authentication

Idempotência. Envie Idempotency-Key com um valor único por tentativa de pagamento (UUID v4 recomendado, máximo 128 caracteres). Repetir o pedido com a mesma chave e o mesmo corpo devolve a resposta guardada, com o mesmo estado HTTP e o mesmo clicpay_reference, acompanhada do cabeçalho Idempotent-Replayed: true, sem contactar o operador e sem criar uma segunda transacção. A chave é privada da sua conta e vale 48 horas. Sem o cabeçalho, o comportamento é o de sempre.

Em 409, outro pedido com essa chave ainda está a ser processado: espere o Retry-After e repita com a mesma chave. Gerar uma chave nova nesse momento é o caminho para o pagamento duplicado.

Example request:
curl --request POST \
    "https://clicpay.co.mz/api/v2/wallets/115665/card-payment" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Idempotency-Key: 9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"amount\": 1500,
    \"reference_description\": \"Pagamento de fatura\",
    \"first_name\": \"João\",
    \"last_name\": \"Silva\",
    \"email\": \"QYvHk@example.com\",
    \"phone\": \"84 123 4567\",
    \"callback_url\": \"https:\\/\\/example.com\\/callback\",
    \"from_app\": \"Loja Online\"
}"
const url = new URL(
    "https://clicpay.co.mz/api/v2/wallets/115665/card-payment"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Idempotency-Key": "9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "amount": 1500,
    "reference_description": "Pagamento de fatura",
    "first_name": "João",
    "last_name": "Silva",
    "email": "QYvHk@example.com",
    "phone": "84 123 4567",
    "callback_url": "https:\/\/example.com\/callback",
    "from_app": "Loja Online"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://clicpay.co.mz/api/v2/wallets/115665/card-payment';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Idempotency-Key' => '9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'amount' => 1500.0,
            'reference_description' => 'Pagamento de fatura',
            'first_name' => 'João',
            'last_name' => 'Silva',
            'email' => 'QYvHk@example.com',
            'phone' => '84 123 4567',
            'callback_url' => 'https://example.com/callback',
            'from_app' => 'Loja Online',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://clicpay.co.mz/api/v2/wallets/115665/card-payment'
payload = {
    "amount": 1500,
    "reference_description": "Pagamento de fatura",
    "first_name": "João",
    "last_name": "Silva",
    "email": "QYvHk@example.com",
    "phone": "84 123 4567",
    "callback_url": "https:\/\/example.com\/callback",
    "from_app": "Loja Online"
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Idempotency-Key': '9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()

Example response (201):


{
    "message": "Sessão criada.",
    "clicpay_reference": "123456789",
    "status": "pending",
    "provider_reference": "123456789",
    "provider_response_code": "200",
    "provider_status_text": "Pending",
    "initiated_at": "2023-01-01T00:00:00Z",
    "completed_at": null,
    "transaction_id": 123,
    "checkout_url": "https://netshop.example.com/checkout/abc123",
    "session_id": "abc123"
}
 

Example response (400):


{
    "message": "Erro ao criar a sessão.",
    "clicpay_reference": "123456789",
    "status": "failed",
    "transaction_id": 123,
    "provider_response_code": "400"
}
 

Example response (401):


{
    "message": "Unauthenticated."
}
 

Example response (403):


{
    "message": "Acesso negado à carteira"
}
 

Example response (409, Pedido anterior com a mesma chave ainda em curso):


{
    "error": "idempotency_request_in_progress",
    "message": "Um pedido com esta Idempotency-Key ainda está a ser processado. Aguarde e repita com a MESMA chave.",
    "idempotency_key": "9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11",
    "retry_after_seconds": 12
}
 

Example response (422, Erro de validação):


{
    "errors": {
        "amount": [
            "O campo valor é obrigatório."
        ],
        "reference_description": [
            "O campo descrição da referência é obrigatório."
        ]
    }
}
 

Example response (422, Idempotency-Key reutilizada com um corpo diferente):


{
    "error": "idempotency_key_reused_with_different_payload",
    "message": "Esta Idempotency-Key já foi usada com um corpo diferente.",
    "idempotency_key": "9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11"
}
 

Example response (422, Idempotency-Key com formato inválido):


{
    "error": "idempotency_key_invalid",
    "message": "O cabeçalho Idempotency-Key deve ter entre 1 e 128 caracteres.",
    "max_length": 128
}
 

Request      

POST api/v2/wallets/{wallet_id}/card-payment

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Idempotency-Key        

Example: 9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

wallet_id   integer     

The ID of the wallet. Example: 115665

wallet   integer     

ID da carteira NetShop Example: 1234

Body Parameters

amount   number     

Valor do pagamento Example: 1500

reference_description   string     

Descrição da referência (máx 100 caracteres) Example: Pagamento de fatura

first_name   string  optional    

optional Primeiro nome do pagador Example: João

last_name   string  optional    

optional Último nome do pagador Example: Silva

email   string  optional    

optional Email do pagador Example: QYvHk@example.com

phone   string  optional    

optional Telefone do pagador Example: 84 123 4567

callback_url   url  optional    

optional URL de retorno Example: https://example.com/callback

from_app   string  optional    

optional Canal/aplicação que originou o pagamento Example: Loja Online

card_number   string  optional    
cardNumber   string  optional    
pan   string  optional    
cvv   string  optional    
cvc   string  optional    
expiry_month   string  optional    
expiry_year   string  optional    
expiration_month   string  optional    
expiration_year   string  optional    
card_holder   string  optional    
card_holder_name   string  optional    

Response

Response Fields

clicpay_reference   string     

Referência única da transação

status   string     

Status atual (pending/successful/failed)

provider_reference   string     

Referência do provedor de pagamento

provider_response_code   string     

Código de resposta do provedor

provider_status_text   string     

Descrição do status do provedor

message   string     

Mensagem descritiva do status

initiated_at   string     

Data e hora de início da transação (ISO 8601)

completed_at   string     

Data e hora de conclusão da transação (ISO 8601)

transaction_id   integer     

ID interno da transação

checkout_url   string     

URL do checkout NetShop

session_id   string     

ID da sessão NetShop

Estado de Transações

Consultar o estado de uma transação

requires authentication

Esta consulta é a fonte de verdade. O webhook é aceleração. Um webhook pode perder-se; esta rota pergunta ao operador. Nunca trate a ausência de webhook como falha de pagamento: consulte aqui.

Quando a transação ainda não está num estado final, a ClicPay contacta o operador e devolve o que ele disser. Se a última verificação tiver menos de 15 segundos, devolve o valor guardado sem voltar a contactar: o campo checked_at diz-lhe exactamente quando foi confirmado, para não ter de adivinhar se o valor é recente.

Estados finais (SUCCESSFUL, FAILED, CANCELLED, REFUNDED) são absorventes: não são re-consultados e nunca mudam por uma consulta posterior.

Uma consulta que falhe não altera o estado. Recebe 200 com o estado que havia, e checked_at actualizado. Um estado não-terminal nunca autoriza uma segunda cobrança: consulte, não repita o pagamento.

Example request:
curl --request GET \
    --get "https://clicpay.co.mz/api/v2/transactions/CPAYMPESAC2BAB12/status" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://clicpay.co.mz/api/v2/transactions/CPAYMPESAC2BAB12/status"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://clicpay.co.mz/api/v2/transactions/CPAYMPESAC2BAB12/status';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://clicpay.co.mz/api/v2/transactions/CPAYMPESAC2BAB12/status'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (200, Pagamento confirmado):


{
    "clicpay_reference": "CPAYMPESAC2BAB12",
    "status": "SUCCESSFUL",
    "provider_reference": "DGO4KXXBEVW",
    "provider_response_code": "INS-0",
    "provider_status_text": "Completed",
    "message": "Transaction status: Completed",
    "initiated_at": "2026-09-14T10:00:00+00:00",
    "completed_at": "2026-09-14T10:00:42+00:00",
    "checked_at": "2026-09-14T10:00:43+00:00"
}
 

Example response (200, Ainda em curso):


{
    "clicpay_reference": "CPAYMPESAC2BAB12",
    "status": "PROCESSING",
    "provider_reference": null,
    "provider_response_code": "INS-0",
    "provider_status_text": "Pending",
    "message": "Transaction status: Pending",
    "initiated_at": "2026-09-14T10:00:00+00:00",
    "completed_at": null,
    "checked_at": "2026-09-14T10:00:20+00:00"
}
 

Example response (401):


{
    "message": "Unauthenticated."
}
 

Example response (404):


{"message": "No query results for model [App\Models\Transaction]."}
 

Request      

GET api/v2/transactions/{clicpay_reference}/status

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

clicpay_reference   string     

Referência ClicPay da transação. Example: CPAYMPESAC2BAB12

Response

Response Fields

clicpay_reference   string     

Referência ClicPay da transação.

status   string     

Estado actual, em MAIÚSCULAS. Um de: PENDING, PROCESSING, SUCCESSFUL, FAILED, CANCELLED, REFUNDED, PARTIALLY_REFUNDED, AWAITING_ACTION, REJECTED. Compare em maiúsculas: a documentação anterior dizia minúsculas e estava errada.

provider_reference   string     

Referência da transação do lado do operador, quando já existe.

provider_response_code   string     

Código de resposta do operador (ex.: INS-0).

provider_status_text   string     

Estado textual do operador (ex.: Completed).

message   string     

Mensagem descritiva do estado.

initiated_at   string     

Quando a ClicPay registou o pedido (ISO 8601).

completed_at   string     

Quando a transação atingiu um estado final (ISO 8601), ou null.

checked_at   string     

Quando o estado foi confirmado junto do operador pela última vez (ISO 8601), ou null se nunca foi.

Carteiras

GET api/v2/me/wallets

requires authentication

Example request:
curl --request GET \
    --get "https://clicpay.co.mz/api/v2/me/wallets?payment_method_id=1&is_active=1&environment=production&include=paymentMethod&sort_by=created_at&sort_order=desc&per_page=20" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://clicpay.co.mz/api/v2/me/wallets"
);

const params = {
    "payment_method_id": "1",
    "is_active": "1",
    "environment": "production",
    "include": "paymentMethod",
    "sort_by": "created_at",
    "sort_order": "desc",
    "per_page": "20",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://clicpay.co.mz/api/v2/me/wallets';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'payment_method_id' => '1',
            'is_active' => '1',
            'environment' => 'production',
            'include' => 'paymentMethod',
            'sort_by' => 'created_at',
            'sort_order' => 'desc',
            'per_page' => '20',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://clicpay.co.mz/api/v2/me/wallets'
params = {
  'payment_method_id': '1',
  'is_active': '1',
  'environment': 'production',
  'include': 'paymentMethod',
  'sort_by': 'created_at',
  'sort_order': 'desc',
  'per_page': '20',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()

Example response (200):


{
    "data": [
        {
            "id": 1,
            "name": "Minha Carteira",
            "balance": 1000,
            "payment_method": {
                "id": 1,
                "name": "eMola",
                "slug": "emola"
            }
        }
    ],
    "links": {
        "first": "...",
        "last": "...",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 1,
        "per_page": 20,
        "to": 1,
        "total": 1
    }
}
 

Request      

GET api/v2/me/wallets

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

payment_method_id   integer  optional    

optional Filtrar por método de pagamento Example: 1

is_active   boolean  optional    

optional Filtrar por status ativo Example: true

environment   string  optional    

optional Filtrar por ambiente (sandbox/production) Example: production

include   string  optional    

optional Incluir relacionamentos (ex: paymentMethod) Example: paymentMethod

sort_by   string  optional    

optional Ordenar por campo (id, name, balance, created_at) Example: created_at

sort_order   string  optional    

optional Ordem da ordenação (asc, desc) Example: desc

per_page   integer  optional    

optional Itens por página (padrão: 10) Example: 20

Response

Response Fields

data   string[]     

Lista de carteiras

id   integer     

ID da carteira

name   string     

Nome da carteira

balance   number     

Saldo disponível

payment_method   object     

Método de pagamento associado

Autenticação

Obter utilizador autenticado

requires authentication

Example request:
curl --request GET \
    --get "https://clicpay.co.mz/api/user" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://clicpay.co.mz/api/user"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://clicpay.co.mz/api/user';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://clicpay.co.mz/api/user'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (401):

Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
 

{
    "message": "Unauthenticated."
}
 

Request      

GET api/user

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Obter token de acesso

requires authentication

Example request:
curl --request GET \
    --get "https://clicpay.co.mz/api/me/token" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://clicpay.co.mz/api/me/token"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://clicpay.co.mz/api/me/token';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://clicpay.co.mz/api/me/token'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (401):

Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
 

{
    "message": "Unauthenticated."
}
 

Request      

GET api/me/token

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Carteiras e Subcarteiras

Listar carteiras do parceiro. Devolve as carteiras a que o utilizador autenticado tem acesso (carteiras pessoais + carteiras das organizações em que é membro).

requires authentication

Example request:
curl --request GET \
    --get "https://clicpay.co.mz/api/v2/wallets?filter%5Bis_active%5D=1&filter%5Bpayment_method_id%5D=1&filter%5Benvironment%5D=production&filter%5Bsearch%5D=minha&sort=-created_at&per_page=20&page=1" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"filter\": {
        \"is_active\": true,
        \"payment_method_id\": 16,
        \"environment\": \"production\",
        \"search\": \"n\"
    },
    \"sort\": \"name\",
    \"per_page\": 7,
    \"page\": 66
}"
const url = new URL(
    "https://clicpay.co.mz/api/v2/wallets"
);

const params = {
    "filter[is_active]": "1",
    "filter[payment_method_id]": "1",
    "filter[environment]": "production",
    "filter[search]": "minha",
    "sort": "-created_at",
    "per_page": "20",
    "page": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "filter": {
        "is_active": true,
        "payment_method_id": 16,
        "environment": "production",
        "search": "n"
    },
    "sort": "name",
    "per_page": 7,
    "page": 66
};

fetch(url, {
    method: "GET",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://clicpay.co.mz/api/v2/wallets';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'filter[is_active]' => '1',
            'filter[payment_method_id]' => '1',
            'filter[environment]' => 'production',
            'filter[search]' => 'minha',
            'sort' => '-created_at',
            'per_page' => '20',
            'page' => '1',
        ],
        'json' => [
            'filter' => [
                'is_active' => true,
                'payment_method_id' => 16,
                'environment' => 'production',
                'search' => 'n',
            ],
            'sort' => 'name',
            'per_page' => 7,
            'page' => 66,
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://clicpay.co.mz/api/v2/wallets'
payload = {
    "filter": {
        "is_active": true,
        "payment_method_id": 16,
        "environment": "production",
        "search": "n"
    },
    "sort": "name",
    "per_page": 7,
    "page": 66
}
params = {
  'filter[is_active]': '1',
  'filter[payment_method_id]': '1',
  'filter[environment]': 'production',
  'filter[search]': 'minha',
  'sort': '-created_at',
  'per_page': '20',
  'page': '1',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, json=payload, params=params)
response.json()

Example response (200):


{
    "data": [
        {
            "id": 123,
            "name": "Carteira Mpesa Principal",
            "environment": "production",
            "is_active": true,
            "allow_c2b": true,
            "allow_b2c": true,
            "currency": "MZN",
            "payment_method": {
                "id": 1,
                "name": "Mpesa",
                "slug": "mpesa"
            },
            "owner": {
                "type": "organization",
                "id": 5,
                "name": "Acme Lda"
            },
            "balance": {
                "available": "1500.00",
                "accumulated": "2000.00"
            },
            "commission": {
                "c2b_percentage": "1.5000",
                "b2c_percentage": "1.0000"
            },
            "created_at": "2026-01-15T10:30:00+00:00",
            "updated_at": "2026-06-01T08:12:33+00:00"
        }
    ],
    "meta": {
        "pagination": {
            "type": "offset",
            "per_page": 20,
            "count": 1,
            "current_page": 1,
            "last_page": 1,
            "from": 1,
            "to": 1,
            "total": 1
        }
    }
}
 

Example response (401):


{
    "message": "Unauthenticated."
}
 

Example response (422):


{
    "message": "Sort inválido.",
    "errors": {
        "sort": [
            "Ordenação inválida..."
        ]
    }
}
 

Request      

GET api/v2/wallets

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

filter[is_active]   boolean  optional    

Filtra por estado activo. Example: true

filter[payment_method_id]   integer  optional    

ID do método de pagamento. Example: 1

filter[environment]   string  optional    

production ou sandbox. Example: production

filter[search]   string  optional    

Pesquisa parcial no nome. Example: minha

sort   string  optional    

Ordenação (created_at, -created_at, name, -name). Example: -created_at

per_page   integer  optional    

Itens por página (1-100). Example: 20

page   integer  optional    

Número da página. Example: 1

Body Parameters

filter   object  optional    
is_active   boolean  optional    

Example: true

payment_method_id   integer  optional    

The id of an existing record in the payment_methods table. Example: 16

environment   string  optional    

Example: production

Must be one of:
  • production
  • sandbox
search   string  optional    

Must not be greater than 100 characters. Example: n

sort   string  optional    

Example: name

Must be one of:
  • created_at
  • -created_at
  • name
  • -name
per_page   integer  optional    

Must be at least 1. Must not be greater than 100. Example: 7

page   integer  optional    

Must be at least 1. Example: 66

Detalhe de uma carteira.

requires authentication

Example request:
curl --request GET \
    --get "https://clicpay.co.mz/api/v2/wallets/115665" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://clicpay.co.mz/api/v2/wallets/115665"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://clicpay.co.mz/api/v2/wallets/115665';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://clicpay.co.mz/api/v2/wallets/115665'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (200):


{
    "data": {
        "id": 123,
        "name": "Carteira Mpesa Principal",
        "environment": "production",
        "is_active": true,
        "allow_c2b": true,
        "allow_b2c": true,
        "currency": "MZN",
        "payment_method": {
            "id": 1,
            "name": "Mpesa",
            "slug": "mpesa"
        },
        "owner": {
            "type": "organization",
            "id": 5,
            "name": "Acme Lda"
        },
        "balance": {
            "available": "1500.00",
            "accumulated": "2000.00"
        },
        "commission": {
            "c2b_percentage": "1.5000",
            "b2c_percentage": "1.0000"
        },
        "created_at": "2026-01-15T10:30:00+00:00",
        "updated_at": "2026-06-01T08:12:33+00:00"
    }
}
 

Example response (401):


{
    "message": "Unauthenticated."
}
 

Example response (403):


{
    "message": "This action is unauthorized."
}
 

Example response (404):


{
    "message": "No query results for model [App\\Models\\Wallet]."
}
 

Request      

GET api/v2/wallets/{id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   integer     

The ID of the wallet. Example: 115665

wallet   integer     

ID da carteira. Example: 123

Saldo de uma carteira. Endpoint dedicado e leve. Resposta é cacheada por 60 segundos por carteira — ideal para dashboards e polling de reconciliação.

requires authentication

Example request:
curl --request GET \
    --get "https://clicpay.co.mz/api/v2/wallets/115665/balance" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://clicpay.co.mz/api/v2/wallets/115665/balance"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://clicpay.co.mz/api/v2/wallets/115665/balance';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://clicpay.co.mz/api/v2/wallets/115665/balance'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (200):


{
    "data": {
        "wallet_id": 123,
        "currency": "MZN",
        "available": "1500.00",
        "accumulated": "2000.00",
        "debits": "500.00",
        "computed_at": "2026-06-03T15:42:11+00:00"
    }
}
 

Example response (401):


{
    "message": "Unauthenticated."
}
 

Example response (403):


{
    "message": "This action is unauthorized."
}
 

Example response (404):


{
    "message": "No query results for model [App\\Models\\Wallet]."
}
 

Request      

GET api/v2/wallets/{wallet_id}/balance

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

wallet_id   integer     

The ID of the wallet. Example: 115665

wallet   integer     

ID da carteira. Example: 123

Listar subcarteiras (splits) de uma carteira.

requires authentication

Example request:
curl --request GET \
    --get "https://clicpay.co.mz/api/v2/wallets/115665/splits?filter%5Bis_active%5D=1&filter%5Bsplit_mode%5D=wallet_collect&filter%5Bsearch%5D=split-a&sort=-created_at&per_page=20" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"filter\": {
        \"is_active\": true,
        \"split_mode\": \"wallet_collect\",
        \"search\": \"b\"
    },
    \"sort\": \"name\",
    \"per_page\": 22,
    \"page\": 67
}"
const url = new URL(
    "https://clicpay.co.mz/api/v2/wallets/115665/splits"
);

const params = {
    "filter[is_active]": "1",
    "filter[split_mode]": "wallet_collect",
    "filter[search]": "split-a",
    "sort": "-created_at",
    "per_page": "20",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "filter": {
        "is_active": true,
        "split_mode": "wallet_collect",
        "search": "b"
    },
    "sort": "name",
    "per_page": 22,
    "page": 67
};

fetch(url, {
    method: "GET",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://clicpay.co.mz/api/v2/wallets/115665/splits';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'filter[is_active]' => '1',
            'filter[split_mode]' => 'wallet_collect',
            'filter[search]' => 'split-a',
            'sort' => '-created_at',
            'per_page' => '20',
        ],
        'json' => [
            'filter' => [
                'is_active' => true,
                'split_mode' => 'wallet_collect',
                'search' => 'b',
            ],
            'sort' => 'name',
            'per_page' => 22,
            'page' => 67,
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://clicpay.co.mz/api/v2/wallets/115665/splits'
payload = {
    "filter": {
        "is_active": true,
        "split_mode": "wallet_collect",
        "search": "b"
    },
    "sort": "name",
    "per_page": 22,
    "page": 67
}
params = {
  'filter[is_active]': '1',
  'filter[split_mode]': 'wallet_collect',
  'filter[search]': 'split-a',
  'sort': '-created_at',
  'per_page': '20',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, json=payload, params=params)
response.json()

Example response (200):


{
    "data": [
        {
            "id": 100001,
            "name": "Split Marketing",
            "wallet_id": 123,
            "environment": "production",
            "is_active": true,
            "allow_b2c": true,
            "currency": "MZN",
            "split_mode": "wallet_collect",
            "split_value_type": "percentage",
            "split_value": "30.0000",
            "advanced_enabled": false,
            "max_amount": null,
            "balance": {
                "available": "750.00",
                "accumulated": "900.00",
                "debits": "150.00"
            },
            "created_at": "2026-02-10T09:00:00+00:00",
            "updated_at": "2026-06-01T08:12:33+00:00"
        }
    ],
    "meta": {
        "pagination": {
            "type": "offset",
            "per_page": 20,
            "count": 1,
            "current_page": 1,
            "last_page": 1,
            "from": 1,
            "to": 1,
            "total": 1
        }
    }
}
 

Example response (401):


{
    "message": "Unauthenticated."
}
 

Example response (403):


{
    "message": "This action is unauthorized."
}
 

Example response (404):


{
    "message": "No query results for model [App\\Models\\Wallet]."
}
 

Request      

GET api/v2/wallets/{wallet_id}/splits

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

wallet_id   integer     

The ID of the wallet. Example: 115665

wallet   integer     

ID da carteira mãe. Example: 123

Query Parameters

filter[is_active]   boolean  optional    

Filtra por estado. Example: true

filter[split_mode]   string  optional    

Filtra por modo (wallet_collect, b2c_direct, dynamic_load). Example: wallet_collect

filter[search]   string  optional    

Pesquisa parcial no nome. Example: split-a

sort   string  optional    

Ordenação (created_at, -created_at, name, -name). Example: -created_at

per_page   integer  optional    

Itens por página (1-100). Example: 20

Body Parameters

filter   object  optional    
is_active   boolean  optional    

Example: true

split_mode   string  optional    

Example: wallet_collect

Must be one of:
  • wallet_collect
  • b2c_direct
  • dynamic_load
search   string  optional    

Must not be greater than 100 characters. Example: b

sort   string  optional    

Example: name

Must be one of:
  • created_at
  • -created_at
  • name
  • -name
per_page   integer  optional    

Must be at least 1. Must not be greater than 100. Example: 22

page   integer  optional    

Must be at least 1. Example: 67

Detalhe de uma subcarteira.

requires authentication

Example request:
curl --request GET \
    --get "https://clicpay.co.mz/api/v2/wallets/115665/splits/100000" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://clicpay.co.mz/api/v2/wallets/115665/splits/100000"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://clicpay.co.mz/api/v2/wallets/115665/splits/100000';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://clicpay.co.mz/api/v2/wallets/115665/splits/100000'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (200, Sucesso):


{
    "data": {
        "id": 100001,
        "name": "Split Marketing",
        "wallet_id": 123,
        "environment": "production",
        "is_active": true,
        "allow_b2c": true,
        "currency": "MZN",
        "split_mode": "wallet_collect",
        "split_value_type": "percentage",
        "split_value": "30.0000",
        "advanced_enabled": false,
        "max_amount": null,
        "balance": {
            "available": "750.00",
            "accumulated": "900.00",
            "debits": "150.00"
        },
        "created_at": "2026-02-10T09:00:00+00:00",
        "updated_at": "2026-06-01T08:12:33+00:00"
    }
}
 

Example response (401):


{
    "message": "Unauthenticated."
}
 

Example response (403):


{
    "message": "This action is unauthorized."
}
 

Example response (404, Split não pertence à carteira indicada):


{
    "message": "No query results for model [App\\Models\\WalletSplit]."
}
 

Request      

GET api/v2/wallets/{wallet_id}/splits/{walletSplit_id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

wallet_id   integer     

The ID of the wallet. Example: 115665

walletSplit_id   integer     

The ID of the walletSplit. Example: 100000

wallet   integer     

ID da carteira mãe. Example: 123

walletSplit   integer     

ID da subcarteira. Example: 100001

Saldo de uma subcarteira. Resposta cacheada por 60 segundos por subcarteira. Inclui `max_amount` e `remaining_capacity` quando a subcarteira tem cap configurado.

requires authentication

Example request:
curl --request GET \
    --get "https://clicpay.co.mz/api/v2/wallets/115665/splits/100000/balance" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://clicpay.co.mz/api/v2/wallets/115665/splits/100000/balance"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://clicpay.co.mz/api/v2/wallets/115665/splits/100000/balance';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://clicpay.co.mz/api/v2/wallets/115665/splits/100000/balance'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (200):


{
    "data": {
        "wallet_split_id": 100001,
        "wallet_id": 123,
        "currency": "MZN",
        "available": "750.00",
        "accumulated": "900.00",
        "debits": "150.00",
        "max_amount": "5000.00",
        "remaining_capacity": "4100.00",
        "computed_at": "2026-06-03T15:42:11+00:00"
    }
}
 

Example response (401):


{
    "message": "Unauthenticated."
}
 

Example response (403):


{
    "message": "This action is unauthorized."
}
 

Request      

GET api/v2/wallets/{wallet_id}/splits/{walletSplit_id}/balance

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

wallet_id   integer     

The ID of the wallet. Example: 115665

walletSplit_id   integer     

The ID of the walletSplit. Example: 100000

wallet   integer     

ID da carteira mãe. Example: 123

walletSplit   integer     

ID da subcarteira. Example: 100001

Histórico cross-wallet de transacções. Devolve todas as transacções das carteiras a que o parceiro tem acesso.

requires authentication

Example request:
curl --request GET \
    --get "https://clicpay.co.mz/api/v2/transactions?filter%5Bwallet_id%5D=123&filter%5Bdate_from%5D=2026-01-01&filter%5Bdate_to%5D=2026-06-30&filter%5Bstatus%5D=SUCCESSFUL&filter%5Btype%5D=C2B&filter%5Bprovider%5D=mpesa&filter%5Bclicpay_reference%5D=CPAYEMOLAC2B...&filter%5Bprovider_reference%5D=PROV-12345&sort=-created_at&paginator=cursor&per_page=50" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"filter\": {
        \"date_from\": \"2026-09-15T00:58:45\",
        \"date_to\": \"2052-10-08\",
        \"status\": [
            \"FAILED\"
        ],
        \"type\": [
            \"TRANSFER_IN\"
        ],
        \"provider\": \"architecto\",
        \"clicpay_reference\": \"n\",
        \"provider_reference\": \"g\",
        \"wallet_id\": 16
    },
    \"sort\": \"amount\",
    \"paginator\": \"cursor\",
    \"per_page\": 22,
    \"page\": 67,
    \"cursor\": \"architecto\"
}"
const url = new URL(
    "https://clicpay.co.mz/api/v2/transactions"
);

const params = {
    "filter[wallet_id]": "123",
    "filter[date_from]": "2026-01-01",
    "filter[date_to]": "2026-06-30",
    "filter[status]": "SUCCESSFUL",
    "filter[type]": "C2B",
    "filter[provider]": "mpesa",
    "filter[clicpay_reference]": "CPAYEMOLAC2B...",
    "filter[provider_reference]": "PROV-12345",
    "sort": "-created_at",
    "paginator": "cursor",
    "per_page": "50",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "filter": {
        "date_from": "2026-09-15T00:58:45",
        "date_to": "2052-10-08",
        "status": [
            "FAILED"
        ],
        "type": [
            "TRANSFER_IN"
        ],
        "provider": "architecto",
        "clicpay_reference": "n",
        "provider_reference": "g",
        "wallet_id": 16
    },
    "sort": "amount",
    "paginator": "cursor",
    "per_page": 22,
    "page": 67,
    "cursor": "architecto"
};

fetch(url, {
    method: "GET",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://clicpay.co.mz/api/v2/transactions';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'filter[wallet_id]' => '123',
            'filter[date_from]' => '2026-01-01',
            'filter[date_to]' => '2026-06-30',
            'filter[status]' => 'SUCCESSFUL',
            'filter[type]' => 'C2B',
            'filter[provider]' => 'mpesa',
            'filter[clicpay_reference]' => 'CPAYEMOLAC2B...',
            'filter[provider_reference]' => 'PROV-12345',
            'sort' => '-created_at',
            'paginator' => 'cursor',
            'per_page' => '50',
        ],
        'json' => [
            'filter' => [
                'date_from' => '2026-09-15T00:58:45',
                'date_to' => '2052-10-08',
                'status' => [
                    'FAILED',
                ],
                'type' => [
                    'TRANSFER_IN',
                ],
                'provider' => 'architecto',
                'clicpay_reference' => 'n',
                'provider_reference' => 'g',
                'wallet_id' => 16,
            ],
            'sort' => 'amount',
            'paginator' => 'cursor',
            'per_page' => 22,
            'page' => 67,
            'cursor' => 'architecto',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://clicpay.co.mz/api/v2/transactions'
payload = {
    "filter": {
        "date_from": "2026-09-15T00:58:45",
        "date_to": "2052-10-08",
        "status": [
            "FAILED"
        ],
        "type": [
            "TRANSFER_IN"
        ],
        "provider": "architecto",
        "clicpay_reference": "n",
        "provider_reference": "g",
        "wallet_id": 16
    },
    "sort": "amount",
    "paginator": "cursor",
    "per_page": 22,
    "page": 67,
    "cursor": "architecto"
}
params = {
  'filter[wallet_id]': '123',
  'filter[date_from]': '2026-01-01',
  'filter[date_to]': '2026-06-30',
  'filter[status]': 'SUCCESSFUL',
  'filter[type]': 'C2B',
  'filter[provider]': 'mpesa',
  'filter[clicpay_reference]': 'CPAYEMOLAC2B...',
  'filter[provider_reference]': 'PROV-12345',
  'sort': '-created_at',
  'paginator': 'cursor',
  'per_page': '50',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, json=payload, params=params)
response.json()

Example response (200, Mesmo shape de /wallets/{wallet}/transactions):


{
    "data": [],
    "meta": {
        "pagination": {
            "type": "cursor",
            "per_page": 50,
            "count": 0,
            "next_cursor": null,
            "prev_cursor": null,
            "has_more": false
        }
    }
}
 

Example response (401):


{
    "message": "Unauthenticated."
}
 

Example response (422):


{
    "message": "Filter inválido.",
    "errors": {
        "filter.status.0": [
            "..."
        ]
    }
}
 

Request      

GET api/v2/transactions

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

filter[wallet_id]   integer  optional    

Restringe a uma carteira. Example: 123

filter[date_from]   string  optional    

Data inicial. Example: 2026-01-01

filter[date_to]   string  optional    

Data final. Example: 2026-06-30

filter[status]   string  optional    

Estado. Example: SUCCESSFUL

filter[type]   string  optional    

Tipo de operação. Example: C2B

filter[provider]   string  optional    

Slug do método de pagamento. Example: mpesa

filter[clicpay_reference]   string  optional    

string. Example: CPAYEMOLAC2B...

filter[provider_reference]   string  optional    

string. Example: PROV-12345

sort   string  optional    

string. Example: -created_at

paginator   string  optional    

cursor ou offset. Example: cursor

per_page   integer  optional    

1-100. Example: 50

Body Parameters

filter   object  optional    
date_from   string  optional    

Must be a valid date. Example: 2026-09-15T00:58:45

date_to   string  optional    

Must be a valid date. Must be a date after or equal to filter.date_from. Example: 2052-10-08

status   string[]  optional    
Must be one of:
  • PENDING
  • PROCESSING
  • SUCCESSFUL
  • FAILED
  • CANCELLED
  • REFUNDED
  • PARTIALLY_REFUNDED
  • REJECTED
  • AWAITING_ACTION
type   string[]  optional    
Must be one of:
  • C2B
  • B2C
  • DEPOSIT
  • WITHDRAWAL
  • WITHDRAWAL_SPLIT
  • TRANSFER_IN
  • TRANSFER_OUT
  • SUBSCRIPTION_PAYMENT
provider   string  optional    

The slug of an existing record in the payment_methods table. Example: architecto

clicpay_reference   string  optional    

Must not be greater than 64 characters. Example: n

provider_reference   string  optional    

Must not be greater than 128 characters. Example: g

wallet_id   integer  optional    

Example: 16

sort   string  optional    

Example: amount

Must be one of:
  • created_at
  • -created_at
  • completed_at
  • -completed_at
  • amount
  • -amount
paginator   string  optional    

Example: cursor

Must be one of:
  • cursor
  • offset
per_page   integer  optional    

Must be at least 1. Must not be greater than 100. Example: 22

page   integer  optional    

Must be at least 1. Example: 67

cursor   string  optional    

Example: architecto

Histórico de transacções de uma carteira.

requires authentication

Example request:
curl --request GET \
    --get "https://clicpay.co.mz/api/v2/wallets/115665/transactions?filter%5Bdate_from%5D=2026-01-01&filter%5Bdate_to%5D=2026-06-30&filter%5Bstatus%5D=SUCCESSFUL&filter%5Btype%5D=C2B&filter%5Bprovider%5D=mpesa&filter%5Bclicpay_reference%5D=CPAYEMOLAC2B...&filter%5Bprovider_reference%5D=PROV-12345&sort=-created_at&paginator=cursor&per_page=50&cursor=architecto" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"filter\": {
        \"date_from\": \"2026-09-15T00:58:45\",
        \"date_to\": \"2052-10-08\",
        \"status\": [
            \"REFUNDED\"
        ],
        \"type\": [
            \"SUBSCRIPTION_PAYMENT\"
        ],
        \"provider\": \"architecto\",
        \"clicpay_reference\": \"n\",
        \"provider_reference\": \"g\",
        \"wallet_id\": 16
    },
    \"sort\": \"-completed_at\",
    \"paginator\": \"offset\",
    \"per_page\": 22,
    \"page\": 67,
    \"cursor\": \"architecto\"
}"
const url = new URL(
    "https://clicpay.co.mz/api/v2/wallets/115665/transactions"
);

const params = {
    "filter[date_from]": "2026-01-01",
    "filter[date_to]": "2026-06-30",
    "filter[status]": "SUCCESSFUL",
    "filter[type]": "C2B",
    "filter[provider]": "mpesa",
    "filter[clicpay_reference]": "CPAYEMOLAC2B...",
    "filter[provider_reference]": "PROV-12345",
    "sort": "-created_at",
    "paginator": "cursor",
    "per_page": "50",
    "cursor": "architecto",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "filter": {
        "date_from": "2026-09-15T00:58:45",
        "date_to": "2052-10-08",
        "status": [
            "REFUNDED"
        ],
        "type": [
            "SUBSCRIPTION_PAYMENT"
        ],
        "provider": "architecto",
        "clicpay_reference": "n",
        "provider_reference": "g",
        "wallet_id": 16
    },
    "sort": "-completed_at",
    "paginator": "offset",
    "per_page": 22,
    "page": 67,
    "cursor": "architecto"
};

fetch(url, {
    method: "GET",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://clicpay.co.mz/api/v2/wallets/115665/transactions';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'filter[date_from]' => '2026-01-01',
            'filter[date_to]' => '2026-06-30',
            'filter[status]' => 'SUCCESSFUL',
            'filter[type]' => 'C2B',
            'filter[provider]' => 'mpesa',
            'filter[clicpay_reference]' => 'CPAYEMOLAC2B...',
            'filter[provider_reference]' => 'PROV-12345',
            'sort' => '-created_at',
            'paginator' => 'cursor',
            'per_page' => '50',
            'cursor' => 'architecto',
        ],
        'json' => [
            'filter' => [
                'date_from' => '2026-09-15T00:58:45',
                'date_to' => '2052-10-08',
                'status' => [
                    'REFUNDED',
                ],
                'type' => [
                    'SUBSCRIPTION_PAYMENT',
                ],
                'provider' => 'architecto',
                'clicpay_reference' => 'n',
                'provider_reference' => 'g',
                'wallet_id' => 16,
            ],
            'sort' => '-completed_at',
            'paginator' => 'offset',
            'per_page' => 22,
            'page' => 67,
            'cursor' => 'architecto',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://clicpay.co.mz/api/v2/wallets/115665/transactions'
payload = {
    "filter": {
        "date_from": "2026-09-15T00:58:45",
        "date_to": "2052-10-08",
        "status": [
            "REFUNDED"
        ],
        "type": [
            "SUBSCRIPTION_PAYMENT"
        ],
        "provider": "architecto",
        "clicpay_reference": "n",
        "provider_reference": "g",
        "wallet_id": 16
    },
    "sort": "-completed_at",
    "paginator": "offset",
    "per_page": 22,
    "page": 67,
    "cursor": "architecto"
}
params = {
  'filter[date_from]': '2026-01-01',
  'filter[date_to]': '2026-06-30',
  'filter[status]': 'SUCCESSFUL',
  'filter[type]': 'C2B',
  'filter[provider]': 'mpesa',
  'filter[clicpay_reference]': 'CPAYEMOLAC2B...',
  'filter[provider_reference]': 'PROV-12345',
  'sort': '-created_at',
  'paginator': 'cursor',
  'per_page': '50',
  'cursor': 'architecto',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, json=payload, params=params)
response.json()

Example response (200):


{
    "data": [
        {
            "id": 9876,
            "clicpay_reference": "CPAYEMOLAC2BABCDE12345",
            "provider_reference": "EMOLA-99887",
            "type": "C2B",
            "status": "SUCCESSFUL",
            "currency": "MZN",
            "amount": "500.00",
            "received_amount": "493.50",
            "customer_msisdn": "+258841234567",
            "description": "Pagamento de Serviço",
            "wallet": {
                "id": 123,
                "name": "Mpesa Principal",
                "payment_method": {
                    "name": "Mpesa",
                    "slug": "mpesa"
                }
            },
            "wallet_split": null,
            "initiated_at": "2026-06-03T15:01:00+00:00",
            "completed_at": "2026-06-03T15:01:18+00:00",
            "created_at": "2026-06-03T15:01:00+00:00"
        }
    ],
    "meta": {
        "pagination": {
            "type": "cursor",
            "per_page": 50,
            "count": 1,
            "next_cursor": null,
            "prev_cursor": null,
            "has_more": false
        }
    }
}
 

Example response (401):


{
    "message": "Unauthenticated."
}
 

Example response (403):


{
    "message": "This action is unauthorized."
}
 

Example response (422):


{
    "message": "Sort inválido.",
    "errors": {
        "sort": [
            "..."
        ]
    }
}
 

Request      

GET api/v2/wallets/{wallet_id}/transactions

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

wallet_id   integer     

The ID of the wallet. Example: 115665

wallet   integer     

ID da carteira. Example: 123

Query Parameters

filter[date_from]   string  optional    

Data inicial (YYYY-MM-DD ou ISO8601). Example: 2026-01-01

filter[date_to]   string  optional    

Data final. Example: 2026-06-30

filter[status]   string  optional    

Estado (ou múltiplos via filter[status][]=). Example: SUCCESSFUL

filter[type]   string  optional    

Tipo de operação. Example: C2B

filter[provider]   string  optional    

Slug do método de pagamento. Example: mpesa

filter[clicpay_reference]   string  optional    

Referência ClicPay (match exacto). Example: CPAYEMOLAC2B...

filter[provider_reference]   string  optional    

Referência do provedor. Example: PROV-12345

sort   string  optional    

Ordenação. Example: -created_at

paginator   string  optional    

cursor (default) ou offset. Example: cursor

per_page   integer  optional    

1-100. Example: 50

cursor   string  optional    

Cursor opaco devolvido em meta.pagination.next_cursor. Example: architecto

Body Parameters

filter   object  optional    
date_from   string  optional    

Must be a valid date. Example: 2026-09-15T00:58:45

date_to   string  optional    

Must be a valid date. Must be a date after or equal to filter.date_from. Example: 2052-10-08

status   string[]  optional    
Must be one of:
  • PENDING
  • PROCESSING
  • SUCCESSFUL
  • FAILED
  • CANCELLED
  • REFUNDED
  • PARTIALLY_REFUNDED
  • REJECTED
  • AWAITING_ACTION
type   string[]  optional    
Must be one of:
  • C2B
  • B2C
  • DEPOSIT
  • WITHDRAWAL
  • WITHDRAWAL_SPLIT
  • TRANSFER_IN
  • TRANSFER_OUT
  • SUBSCRIPTION_PAYMENT
provider   string  optional    

The slug of an existing record in the payment_methods table. Example: architecto

clicpay_reference   string  optional    

Must not be greater than 64 characters. Example: n

provider_reference   string  optional    

Must not be greater than 128 characters. Example: g

wallet_id   integer  optional    

Example: 16

sort   string  optional    

Example: -completed_at

Must be one of:
  • created_at
  • -created_at
  • completed_at
  • -completed_at
  • amount
  • -amount
paginator   string  optional    

Example: offset

Must be one of:
  • cursor
  • offset
per_page   integer  optional    

Must be at least 1. Must not be greater than 100. Example: 22

page   integer  optional    

Must be at least 1. Example: 67

cursor   string  optional    

Example: architecto

Histórico de transacções de uma subcarteira.

requires authentication

Example request:
curl --request GET \
    --get "https://clicpay.co.mz/api/v2/wallets/115665/splits/100000/transactions?filter%5Bdate_from%5D=2026-01-01&filter%5Bdate_to%5D=2026-06-30&filter%5Bstatus%5D=SUCCESSFUL&filter%5Btype%5D=C2B&filter%5Bprovider%5D=mpesa&paginator=cursor&per_page=50" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"filter\": {
        \"date_from\": \"2026-09-15T00:58:45\",
        \"date_to\": \"2052-10-08\",
        \"status\": [
            \"PARTIALLY_REFUNDED\"
        ],
        \"type\": [
            \"DEPOSIT\"
        ],
        \"provider\": \"architecto\",
        \"clicpay_reference\": \"n\",
        \"provider_reference\": \"g\",
        \"wallet_id\": 16
    },
    \"sort\": \"-amount\",
    \"paginator\": \"cursor\",
    \"per_page\": 22,
    \"page\": 67,
    \"cursor\": \"architecto\"
}"
const url = new URL(
    "https://clicpay.co.mz/api/v2/wallets/115665/splits/100000/transactions"
);

const params = {
    "filter[date_from]": "2026-01-01",
    "filter[date_to]": "2026-06-30",
    "filter[status]": "SUCCESSFUL",
    "filter[type]": "C2B",
    "filter[provider]": "mpesa",
    "paginator": "cursor",
    "per_page": "50",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "filter": {
        "date_from": "2026-09-15T00:58:45",
        "date_to": "2052-10-08",
        "status": [
            "PARTIALLY_REFUNDED"
        ],
        "type": [
            "DEPOSIT"
        ],
        "provider": "architecto",
        "clicpay_reference": "n",
        "provider_reference": "g",
        "wallet_id": 16
    },
    "sort": "-amount",
    "paginator": "cursor",
    "per_page": 22,
    "page": 67,
    "cursor": "architecto"
};

fetch(url, {
    method: "GET",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://clicpay.co.mz/api/v2/wallets/115665/splits/100000/transactions';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'filter[date_from]' => '2026-01-01',
            'filter[date_to]' => '2026-06-30',
            'filter[status]' => 'SUCCESSFUL',
            'filter[type]' => 'C2B',
            'filter[provider]' => 'mpesa',
            'paginator' => 'cursor',
            'per_page' => '50',
        ],
        'json' => [
            'filter' => [
                'date_from' => '2026-09-15T00:58:45',
                'date_to' => '2052-10-08',
                'status' => [
                    'PARTIALLY_REFUNDED',
                ],
                'type' => [
                    'DEPOSIT',
                ],
                'provider' => 'architecto',
                'clicpay_reference' => 'n',
                'provider_reference' => 'g',
                'wallet_id' => 16,
            ],
            'sort' => '-amount',
            'paginator' => 'cursor',
            'per_page' => 22,
            'page' => 67,
            'cursor' => 'architecto',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://clicpay.co.mz/api/v2/wallets/115665/splits/100000/transactions'
payload = {
    "filter": {
        "date_from": "2026-09-15T00:58:45",
        "date_to": "2052-10-08",
        "status": [
            "PARTIALLY_REFUNDED"
        ],
        "type": [
            "DEPOSIT"
        ],
        "provider": "architecto",
        "clicpay_reference": "n",
        "provider_reference": "g",
        "wallet_id": 16
    },
    "sort": "-amount",
    "paginator": "cursor",
    "per_page": 22,
    "page": 67,
    "cursor": "architecto"
}
params = {
  'filter[date_from]': '2026-01-01',
  'filter[date_to]': '2026-06-30',
  'filter[status]': 'SUCCESSFUL',
  'filter[type]': 'C2B',
  'filter[provider]': 'mpesa',
  'paginator': 'cursor',
  'per_page': '50',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, json=payload, params=params)
response.json()

Example response (200, Mesmo shape de /wallets/{wallet}/transactions):


{
    "data": [],
    "meta": {
        "pagination": {
            "type": "cursor",
            "per_page": 50,
            "count": 0,
            "next_cursor": null,
            "prev_cursor": null,
            "has_more": false
        }
    }
}
 

Example response (401):


{
    "message": "Unauthenticated."
}
 

Example response (403):


{
    "message": "This action is unauthorized."
}
 

Example response (404, Split não pertence à carteira indicada):


{
    "message": "No query results for model [App\\Models\\WalletSplit]."
}
 

Request      

GET api/v2/wallets/{wallet_id}/splits/{walletSplit_id}/transactions

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

wallet_id   integer     

The ID of the wallet. Example: 115665

walletSplit_id   integer     

The ID of the walletSplit. Example: 100000

wallet   integer     

ID da carteira mãe. Example: 123

walletSplit   integer     

ID da subcarteira. Example: 100001

Query Parameters

filter[date_from]   string  optional    

Data inicial. Example: 2026-01-01

filter[date_to]   string  optional    

Data final. Example: 2026-06-30

filter[status]   string  optional    

Estado. Example: SUCCESSFUL

filter[type]   string  optional    

Tipo. Example: C2B

filter[provider]   string  optional    

Slug. Example: mpesa

paginator   string  optional    

cursor ou offset. Example: cursor

per_page   integer  optional    

1-100. Example: 50

Body Parameters

filter   object  optional    
date_from   string  optional    

Must be a valid date. Example: 2026-09-15T00:58:45

date_to   string  optional    

Must be a valid date. Must be a date after or equal to filter.date_from. Example: 2052-10-08

status   string[]  optional    
Must be one of:
  • PENDING
  • PROCESSING
  • SUCCESSFUL
  • FAILED
  • CANCELLED
  • REFUNDED
  • PARTIALLY_REFUNDED
  • REJECTED
  • AWAITING_ACTION
type   string[]  optional    
Must be one of:
  • C2B
  • B2C
  • DEPOSIT
  • WITHDRAWAL
  • WITHDRAWAL_SPLIT
  • TRANSFER_IN
  • TRANSFER_OUT
  • SUBSCRIPTION_PAYMENT
provider   string  optional    

The slug of an existing record in the payment_methods table. Example: architecto

clicpay_reference   string  optional    

Must not be greater than 64 characters. Example: n

provider_reference   string  optional    

Must not be greater than 128 characters. Example: g

wallet_id   integer  optional    

Example: 16

sort   string  optional    

Example: -amount

Must be one of:
  • created_at
  • -created_at
  • completed_at
  • -completed_at
  • amount
  • -amount
paginator   string  optional    

Example: cursor

Must be one of:
  • cursor
  • offset
per_page   integer  optional    

Must be at least 1. Must not be greater than 100. Example: 22

page   integer  optional    

Must be at least 1. Example: 67

cursor   string  optional    

Example: architecto

Endpoints

GET api/v2/payment-cards

requires authentication

Example request:
curl --request GET \
    --get "https://clicpay.co.mz/api/v2/payment-cards" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://clicpay.co.mz/api/v2/payment-cards"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://clicpay.co.mz/api/v2/payment-cards';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://clicpay.co.mz/api/v2/payment-cards'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (401):

Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
 

{
    "message": "Unauthenticated."
}
 

Request      

GET api/v2/payment-cards

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

POST api/v2/wallets/{wallet_id}/payment-cards/setup

requires authentication

Example request:
curl --request POST \
    "https://clicpay.co.mz/api/v2/wallets/115665/payment-cards/setup" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"callback_url\": \"http:\\/\\/www.bailey.biz\\/quos-velit-et-fugiat-sunt-nihil-accusantium-harum.html\",
    \"from_app\": \"i\"
}"
const url = new URL(
    "https://clicpay.co.mz/api/v2/wallets/115665/payment-cards/setup"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "callback_url": "http:\/\/www.bailey.biz\/quos-velit-et-fugiat-sunt-nihil-accusantium-harum.html",
    "from_app": "i"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://clicpay.co.mz/api/v2/wallets/115665/payment-cards/setup';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'callback_url' => 'http://www.bailey.biz/quos-velit-et-fugiat-sunt-nihil-accusantium-harum.html',
            'from_app' => 'i',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://clicpay.co.mz/api/v2/wallets/115665/payment-cards/setup'
payload = {
    "callback_url": "http:\/\/www.bailey.biz\/quos-velit-et-fugiat-sunt-nihil-accusantium-harum.html",
    "from_app": "i"
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()

Example response (401):

Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
 

{
    "message": "Unauthenticated."
}
 

Request      

POST api/v2/wallets/{wallet_id}/payment-cards/setup

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

wallet_id   integer     

The ID of the wallet. Example: 115665

Body Parameters

callback_url   string  optional    

Must be a valid URL. Must not be greater than 255 characters. Example: http://www.bailey.biz/quos-velit-et-fugiat-sunt-nihil-accusantium-harum.html

from_app   string  optional    

Must not be greater than 150 characters. Example: i

POST api/v2/wallets/{wallet_id}/payment-cards/{paymentCard_id}/pay

requires authentication

Example request:
curl --request POST \
    "https://clicpay.co.mz/api/v2/wallets/115665/payment-cards/16/pay" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"amount\": 16,
    \"reference_description\": \"n\",
    \"callback_url\": \"http:\\/\\/crooks.biz\\/et-fugiat-sunt-nihil-accusantium\",
    \"from_app\": \"n\"
}"
const url = new URL(
    "https://clicpay.co.mz/api/v2/wallets/115665/payment-cards/16/pay"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "amount": 16,
    "reference_description": "n",
    "callback_url": "http:\/\/crooks.biz\/et-fugiat-sunt-nihil-accusantium",
    "from_app": "n"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://clicpay.co.mz/api/v2/wallets/115665/payment-cards/16/pay';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'amount' => 16,
            'reference_description' => 'n',
            'callback_url' => 'http://crooks.biz/et-fugiat-sunt-nihil-accusantium',
            'from_app' => 'n',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://clicpay.co.mz/api/v2/wallets/115665/payment-cards/16/pay'
payload = {
    "amount": 16,
    "reference_description": "n",
    "callback_url": "http:\/\/crooks.biz\/et-fugiat-sunt-nihil-accusantium",
    "from_app": "n"
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()

Example response (401):

Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
 

{
    "message": "Unauthenticated."
}
 

Request      

POST api/v2/wallets/{wallet_id}/payment-cards/{paymentCard_id}/pay

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

wallet_id   integer     

The ID of the wallet. Example: 115665

paymentCard_id   integer     

The ID of the paymentCard. Example: 16

Body Parameters

amount   number     

Must be at least 1. Example: 16

reference_description   string     

Must not be greater than 100 characters. Example: n

callback_url   string  optional    

Must be a valid URL. Must not be greater than 255 characters. Example: http://crooks.biz/et-fugiat-sunt-nihil-accusantium

from_app   string  optional    

Must not be greater than 150 characters. Example: n

card_number   string  optional    
cardNumber   string  optional    
pan   string  optional    
cvv   string  optional    
cvc   string  optional    
expiry_month   string  optional    
expiry_year   string  optional    
card_holder   string  optional    

GET api/v2/companies

requires authentication

Example request:
curl --request GET \
    --get "https://clicpay.co.mz/api/v2/companies" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://clicpay.co.mz/api/v2/companies"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://clicpay.co.mz/api/v2/companies';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://clicpay.co.mz/api/v2/companies'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (401):

Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
 

{
    "message": "Unauthenticated."
}
 

Request      

GET api/v2/companies

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Transações M-Pesa — B2C via Split

POST api/v2/wallets/{wallet_id}/splits/{walletSplit_id}/b2c/mpesa

requires authentication

Example request:
curl --request POST \
    "https://clicpay.co.mz/api/v2/wallets/115665/splits/100000/b2c/mpesa" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"msisdn\": \"841234567\",
    \"amount\": 500,
    \"reference_description\": \"Pagamento parceiro\",
    \"internal_notes\": \"Split B2C mensal\"
}"
const url = new URL(
    "https://clicpay.co.mz/api/v2/wallets/115665/splits/100000/b2c/mpesa"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "msisdn": "841234567",
    "amount": 500,
    "reference_description": "Pagamento parceiro",
    "internal_notes": "Split B2C mensal"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://clicpay.co.mz/api/v2/wallets/115665/splits/100000/b2c/mpesa';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'msisdn' => '841234567',
            'amount' => 500.0,
            'reference_description' => 'Pagamento parceiro',
            'internal_notes' => 'Split B2C mensal',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://clicpay.co.mz/api/v2/wallets/115665/splits/100000/b2c/mpesa'
payload = {
    "msisdn": "841234567",
    "amount": 500,
    "reference_description": "Pagamento parceiro",
    "internal_notes": "Split B2C mensal"
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()

Example response (200):


{
    "message": "Transação iniciada com sucesso",
    "clicpay_reference": "CPAYMPESAB2CABCDE12345",
    "status": "pending",
    "transaction_id": 790,
    "wallet_split_id": 7
}
 

Example response (403):


{
    "message": "Este split não tem permissão para realizar transações B2C."
}
 

Example response (422):


{
    "message": "Saldo insuficiente no split."
}
 

Request      

POST api/v2/wallets/{wallet_id}/splits/{walletSplit_id}/b2c/mpesa

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

wallet_id   integer     

The ID of the wallet. Example: 115665

walletSplit_id   integer     

The ID of the walletSplit. Example: 100000

wallet   integer     

ID da carteira M-Pesa mãe. Example: 123456

walletSplit   integer     

ID do WalletSplit. Example: 7

Body Parameters

msisdn   string     

Número do destinatário. Example: 841234567

amount   number     

Valor a enviar (1–50000 MZN). Example: 500

reference_description   string     

Descrição (3–32 caracteres). Example: Pagamento parceiro

internal_notes   string  optional    

optional Notas internas (máx 255). Example: Split B2C mensal

Transações Mkesh — B2C via Split

POST api/v2/wallets/{wallet_id}/splits/{walletSplit_id}/b2c/mkesh

requires authentication

Example request:
curl --request POST \
    "https://clicpay.co.mz/api/v2/wallets/115665/splits/100000/b2c/mkesh" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"msisdn\": \"841234567\",
    \"amount\": 500,
    \"reference_description\": \"Pagamento parceiro\",
    \"internal_notes\": \"Split B2C mensal\"
}"
const url = new URL(
    "https://clicpay.co.mz/api/v2/wallets/115665/splits/100000/b2c/mkesh"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "msisdn": "841234567",
    "amount": 500,
    "reference_description": "Pagamento parceiro",
    "internal_notes": "Split B2C mensal"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://clicpay.co.mz/api/v2/wallets/115665/splits/100000/b2c/mkesh';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'msisdn' => '841234567',
            'amount' => 500.0,
            'reference_description' => 'Pagamento parceiro',
            'internal_notes' => 'Split B2C mensal',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://clicpay.co.mz/api/v2/wallets/115665/splits/100000/b2c/mkesh'
payload = {
    "msisdn": "841234567",
    "amount": 500,
    "reference_description": "Pagamento parceiro",
    "internal_notes": "Split B2C mensal"
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()

Example response (200):


{
    "message": "Transação iniciada com sucesso",
    "clicpay_reference": "CPAYMKESHB2CABCDE12345",
    "status": "pending",
    "transaction_id": 791,
    "wallet_split_id": 7
}
 

Example response (403):


{
    "message": "Este split não tem permissão para realizar transações B2C."
}
 

Example response (422):


{
    "message": "Saldo insuficiente no split."
}
 

Request      

POST api/v2/wallets/{wallet_id}/splits/{walletSplit_id}/b2c/mkesh

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

wallet_id   integer     

The ID of the wallet. Example: 115665

walletSplit_id   integer     

The ID of the walletSplit. Example: 100000

wallet   integer     

ID da carteira Mkesh mãe. Example: 123456

walletSplit   integer     

ID do WalletSplit. Example: 7

Body Parameters

msisdn   string     

Número do destinatário. Example: 841234567

amount   number     

Valor a enviar (1–50000 MZN). Example: 500

reference_description   string     

Descrição (3–32 caracteres). Example: Pagamento parceiro

internal_notes   string  optional    

optional Notas internas (máx 255). Example: Split B2C mensal

Transações eMola — B2C via Split

POST api/v2/wallets/{wallet_id}/splits/{walletSplit_id}/b2c/emola

requires authentication

Example request:
curl --request POST \
    "https://clicpay.co.mz/api/v2/wallets/115665/splits/100000/b2c/emola" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"msisdn\": \"841234567\",
    \"amount\": 500,
    \"reference_description\": \"Pagamento parceiro\",
    \"internal_notes\": \"Split B2C mensal\"
}"
const url = new URL(
    "https://clicpay.co.mz/api/v2/wallets/115665/splits/100000/b2c/emola"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "msisdn": "841234567",
    "amount": 500,
    "reference_description": "Pagamento parceiro",
    "internal_notes": "Split B2C mensal"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://clicpay.co.mz/api/v2/wallets/115665/splits/100000/b2c/emola';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'msisdn' => '841234567',
            'amount' => 500.0,
            'reference_description' => 'Pagamento parceiro',
            'internal_notes' => 'Split B2C mensal',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://clicpay.co.mz/api/v2/wallets/115665/splits/100000/b2c/emola'
payload = {
    "msisdn": "841234567",
    "amount": 500,
    "reference_description": "Pagamento parceiro",
    "internal_notes": "Split B2C mensal"
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()

Example response (200):


{
    "message": "Transação iniciada com sucesso",
    "clicpay_reference": "CPAYEMOLAB2CABCDE12345",
    "status": "pending",
    "transaction_id": 789,
    "wallet_split_id": 7
}
 

Example response (403):


{
    "message": "Este split não tem permissão para realizar transações B2C."
}
 

Example response (422):


{
    "message": "Saldo insuficiente no split.",
    "needed": 530,
    "available": 200,
    "missing": 330,
    "wallet_split_id": 7
}
 

Request      

POST api/v2/wallets/{wallet_id}/splits/{walletSplit_id}/b2c/emola

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

wallet_id   integer     

The ID of the wallet. Example: 115665

walletSplit_id   integer     

The ID of the walletSplit. Example: 100000

wallet   integer     

ID da carteira eMola mãe. Example: 123456

walletSplit   integer     

ID do WalletSplit. Example: 7

Body Parameters

msisdn   string     

Número do destinatário. Example: 841234567

amount   number     

Valor a enviar (1–50000 MZN). Example: 500

reference_description   string     

Descrição (3–32 caracteres). Example: Pagamento parceiro

internal_notes   string  optional    

optional Notas internas (máx 255). Example: Split B2C mensal

Transações — Split Collect

Iniciar cobrança com split collect

requires authentication

Idempotência. Envie Idempotency-Key com um valor único por tentativa de pagamento (UUID v4 recomendado, máximo 128 caracteres). Repetir o pedido com a mesma chave e o mesmo corpo devolve a resposta guardada, com o mesmo estado HTTP e o mesmo clicpay_reference, acompanhada do cabeçalho Idempotent-Replayed: true, sem contactar o operador e sem criar uma segunda transacção. A chave é privada da sua conta e vale 48 horas. Sem o cabeçalho, o comportamento é o de sempre.

Em 409, outro pedido com essa chave ainda está a ser processado: espere o Retry-After e repita com a mesma chave. Gerar uma chave nova nesse momento é o caminho para o pagamento duplicado.

Example request:
curl --request POST \
    "https://clicpay.co.mz/api/v2/wallets/115665/split/collect" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Idempotency-Key: 9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"msisdn\": \"841234567\",
    \"amount\": 1000,
    \"reference_description\": \"Pagamento de serviços\",
    \"internal_notes\": \"Pedido #9001\",
    \"splits\": [
        \"architecto\"
    ]
}"
const url = new URL(
    "https://clicpay.co.mz/api/v2/wallets/115665/split/collect"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Idempotency-Key": "9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "msisdn": "841234567",
    "amount": 1000,
    "reference_description": "Pagamento de serviços",
    "internal_notes": "Pedido #9001",
    "splits": [
        "architecto"
    ]
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://clicpay.co.mz/api/v2/wallets/115665/split/collect';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Idempotency-Key' => '9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'msisdn' => '841234567',
            'amount' => 1000.0,
            'reference_description' => 'Pagamento de serviços',
            'internal_notes' => 'Pedido #9001',
            'splits' => [
                'architecto',
            ],
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://clicpay.co.mz/api/v2/wallets/115665/split/collect'
payload = {
    "msisdn": "841234567",
    "amount": 1000,
    "reference_description": "Pagamento de serviços",
    "internal_notes": "Pedido #9001",
    "splits": [
        "architecto"
    ]
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Idempotency-Key': '9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()

Example response (200):


{
    "message": "Transação iniciada com sucesso",
    "clicpay_reference": "CPAY...",
    "status": "pending",
    "transaction_id": 789,
    "split_summary": {
        "direct": [],
        "collect": []
    }
}
 

Example response (401):


{
    "message": "Unauthenticated."
}
 

Example response (409, Pedido anterior com a mesma chave ainda em curso):


{
    "error": "idempotency_request_in_progress",
    "message": "Um pedido com esta Idempotency-Key ainda está a ser processado. Aguarde e repita com a MESMA chave.",
    "idempotency_key": "9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11",
    "retry_after_seconds": 12
}
 

Example response (422, Erro de validação):


{
    "errors": {
        "splits.0.wallet_split_id": [
            "O split não pertence a esta carteira ou não é dynamic_load."
        ]
    }
}
 

Example response (422, Idempotency-Key reutilizada com um corpo diferente):


{
    "error": "idempotency_key_reused_with_different_payload",
    "message": "Esta Idempotency-Key já foi usada com um corpo diferente.",
    "idempotency_key": "9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11"
}
 

Example response (422, Idempotency-Key com formato inválido):


{
    "error": "idempotency_key_invalid",
    "message": "O cabeçalho Idempotency-Key deve ter entre 1 e 128 caracteres.",
    "max_length": 128
}
 

Request      

POST api/v2/wallets/{wallet_id}/split/collect

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Idempotency-Key        

Example: 9f1c2c1e-6a7c-4e1a-9c2a-7f0c2b3a5d11

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

wallet_id   integer     

The ID of the wallet. Example: 115665

wallet   integer     

ID da carteira mãe. Example: 12

Body Parameters

msisdn   string     

MSISDN do pagador. Example: 841234567

amount   number     

Valor total a cobrar (1–150 000 MZN). Example: 1000

reference_description   string     

Descrição visível ao pagador (3–32 caracteres). Example: Pagamento de serviços

internal_notes   string  optional    

optional Notas internas (máx. 255 caracteres). Example: Pedido #9001

splits   string[]  optional    

optional Alocações dinâmicas adicionais para sub-carteiras do tipo dynamic_load. Combinam com os splits estáticos da carteira — os splits estáticos processam primeiro, os dinâmicos processam com o que sobrar.

wallet_split_id   integer     

ID do WalletSplit dynamic_load. Example: 42

value_type   string     

percentage ou amount. Example: percentage

value   number     

Percentagem (0–100) ou montante fixo em MZN. Example: 30

recipients   string[]  optional    

optional Com recipients → B2C Direct. Sem recipients → Wallet Collect. Percentagens devem somar 100.

identifier   string     

MSISDN do destinatário. Example: 841234567

percentage   number     

Percentagem (0.01–100). Example: 100