Authentication
The credential of your machine is the pair client_id and client_secret. Exchange the two for an OAuth2 token (client_credentials) and send the token in Authorization: Bearer on every call to /v2/. The token is valid for 900 seconds.
The API only accepts calls from the IPs of your server registered on your credential. You generate the client_secret and enter the outbound IPs in the dashboard, in The secret and the IPs in the dashboard.
Token #
POST /oauth/token
The client_id and the client_secret go in HTTP Basic. That is what curl -u does:
curl -u "loja01:SEU_CLIENT_SECRET" -d "grant_type=client_credentials" -d "scope=cob.write cob.read pix.read ex.saldo.read ex.config.read" https://api.amunpay.com/oauth/token
POST /oauth/token
Authorization: Basic base64(client_id:client_secret)
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&scope=cob.write cob.read pix.read ex.saldo.read ex.config.read
→ 200
{
"access_token": "eyJhbGciOiJFUzI1NiIsImtpZCI6IjAxSjEifQ...",
"token_type": "Bearer",
"expires_in": 900,
"scope": "cob.write cob.read pix.read ex.saldo.read ex.config.read"
}
| Field | Type | Required | Description |
|---|---|---|---|
grant_type |
string | yes | Always client_credentials. |
scope |
string | no | Scopes separated by spaces, at most 10, within the granted ones. If omitted, the token carries all granted scopes. |
As an alternative to Basic, client_id and client_secret may go in the form body. Sending both in both forms with different values responds 400 invalid_request.
The token is only issued for, and only valid on, calls coming from the registered IPs: from another IP, the token request and every call respond 403 origem_nao_permitida. With no IP registered, no call goes through.
The secret and the IPs in the dashboard #
The manager of your company generates the client_secret in the dashboard, under Integration, in the Credentials tab, with the second factor code. The secret appears once, next to the client_id, each with a copy button, and is never shown again. If you lose it, generate another one: the previous one stops working immediately. Tokens already issued remain valid until they expire, except when you flag a suspected leak, which revokes them too.
| When | What happens |
|---|---|
| First credential | You enter at least one outbound IP, and the IPs take effect immediately. |
| Generate again | A new secret. The scopes and the IPs stay. |
| Remove an IP | Takes effect immediately. |
| Add an IP | Takes effect right away, with an email to the technical and financial contacts of your company. If AmunPay turns on the IP wait for your account, it takes effect 24 hours later: the screen shows the time it takes effect, and you can cancel before then. |
The dashboard accepts a public IP, with a prefix up to /24 (IPv4) or /48 (IPv6), up to 20 IPs. Every action on the credential is emailed to the contacts of your company, without the secret. With no technical or financial contact registered, the dashboard neither generates the secret nor adds an IP.
Only the manager generates the secret and changes the IPs. The other users see the client_id and the IPs. If AmunPay turns on the second-factor wait for your account, a manager who has just enabled the second factor, who was promoted or reactivated, or whose password was reset by someone else, waits 24 hours to generate it. The credential of a sub-account with its own credential is generated by the holder company.
If the screen says the feature is not enabled for your account, talk to AmunPay. AmunPay can also generate the secret and register the IPs for you, and through AmunPay a new IP takes effect immediately.
First call #
GET /v2/ex/config
GET /v2/ex/config
→ 200
{
"conta": { "status": "ATIVA", "desde": "2026-09-18T09:20:23Z" },
"capacidades": {
"pix": true,
"subcontas": true,
"split": true,
"baas": false
},
"recebedor": { "chave": "01J8Z3QK5W7R2N4M6P8T0V2X4Y" },
"custodia": { "tipo": "PROPRIA", "custodiante": "Conta PI", "recusaAntesDoCredito": true },
"depositoPorChave": { "modo": "RECUSAR" }
}
| Field | Type | Description |
|---|---|---|
conta.status |
string | ATIVA is the only status that operates. |
capacidades |
object | What this account can use. Read it before assuming anything. |
recebedor.chave |
string | Identifier of your account, which goes in the chave of your charges. Do not publish it as a Pix key: always receive through a charge, with the pixCopiaECola. A Pix without a txid does not become balance, except when depositoPorChave.modo is ACEITAR. |
custodia.tipo |
string | PROPRIA: the account is held by this institution. PARCEIRA: a nominal account at another payment institution. |
custodia.recusaAntesDoCredito |
boolean | true: a rejected Pix does not enter the account. false: it enters and goes back to the payer through a refund. |
depositoPorChave.modo |
string | RECUSAR: a Pix without a charge is rejected or refunded. ACEITAR: it becomes a charge and is credited. |
Scopes #
| Scope | What it grants |
|---|---|
cob.read, cob.write |
Charges. |
pix.read, pix.write |
Received Pix and refunds. |
ex.pix.send, ex.pix.send.read |
Payouts. |
ex.saldo.read, ex.extrato.read |
Balance, statement, transactions and summary. |
ex.webhook.read, ex.webhook.write, ex.eventos.read |
Webhooks and the event feed. |
ex.subcontas.read, ex.subcontas.write |
Sub-accounts. |
ex.limites.read, ex.limites.write, ex.bloqueios.read |
Limits and balance holds. |
ex.med.read |
Disputes. |
ex.inquilinos.read, ex.inquilinos.write |
Own credentials for sub-accounts. |
ex.config.read |
GET /v2/ex/config. |
Token errors #
POST /oauth/token responds in the format { "error", "error_description" }.
| Status | error |
When |
|---|---|---|
| 401 | invalid_client |
Wrong secret, unknown client_id or suspended credential (the response does not say which), or no credential sent. |
| 400 | invalid_request |
Missing grant_type, Basic that does not decode, or Basic and body that differ. |
| 400 | unsupported_grant_type |
grant_type other than client_credentials. |
| 400 | invalid_scope |
A scope outside the granted ones, or more than 10. |
| 403 | origem_nao_permitida |
The source IP is not among the IPs in effect on the credential. An IP added through the dashboard with the IP wait turned on only takes effect 24 hours later. |
| 429 | invalid_client |
Five wrong secrets in a row from the same IP. Wait for the Retry-After; an attempt during the wait is not checked. |
| 429 | limite_requisicoes |
More than 2 requests per second from the same IP (burst of 20). Wait for the Retry-After. |
| 413 | corpo_grande_demais |
The body is larger than 4 KiB. |
Errors on calls #
| Status | title |
When |
|---|---|---|
| 401 | acesso_negado |
Call without Authorization: Bearer. |
| 401 | token_invalido |
Invalid or expired token. Renew it. |
| 401 | token_revogado |
The token was revoked before it expired (secret rotation, change of scopes or suspension). Request another token once, with the current secret; if the request is refused, talk to support. |
| 403 | origem_nao_permitida |
The source IP is not among the IPs in effect on the credential. Renewing does not help. An IP added through the dashboard with the IP wait turned on only takes effect 24 hours later. |
| 403 | escopo_insuficiente |
The token does not have the scope of the route. Request a token with it, or without scope. If it is not among the granted ones, talk to support. |
| 403 | merchant_nao_provisionado |
The client_id does not have an account yet. |
| 403 | conta_bloqueada |
The account is not ATIVA. |