Mono Colombia

Authentication

How to authenticate Core API requests with an API key or an OAuth 2.0 access token.

Every request to the Core API must prove that it comes from your company. You can prove it with a long-lived API key, or with a short-lived access token that your server requests on its own. Mono accepts both on every Core endpoint, so you can choose the one that fits your security practices.

A credential belongs to one service. Core credentials work only on the Core API, and a Banking credential sent to a Core endpoint is rejected.

Before you start

You will need:

  • A Mono organization with Core enabled, and access to its Mono Dashboard.
  • An HTTPS client. Mono refuses requests that do not use TLS.
  • A safe place for secrets, such as a secrets manager. Never commit credentials to source control.

The conventions shared by every Mono product, such as the header format and environments, are in Authentication standards.

Choose a credential

API keyOAuth 2.0 access token
How long it lastsUntil you revoke it30 minutes, then you request a new one
What it can doWhat its roles allowWhat its scopes allow
How you get itCreated in the Mono DashboardRequested by your server with a client ID and secret
Where it goesAuthorization: Bearer <key>Authorization: Bearer <access_token>

A role is a named set of permissions, such as "Admin" or "Viewer", attached to an API key. A scope is a single permission, such as payouts:readonly, attached to an access token. Mono maps each role permission to the scopes that grant the same action, so an endpoint accepts either credential for the same operation.

Option 1: API keys

An API key is a secret string that stays valid until you revoke it. To create or revoke keys, sign in to the Mono Dashboard and open the API key management section.

When you create a key, choose its roles. The key can do exactly what those roles allow.

Send the key in the Authorization header of every request:

curl https://api.cuentamono.com/v1/ledger/accounts \
  -H "Authorization: Bearer $MONO_API_KEY"

Keys do not expire, so rotating them is your responsibility: create a new key, deploy it, then revoke the old one.

Option 2: OAuth 2.0 access tokens

OAuth 2.0 is an industry standard for issuing temporary credentials. Mono uses its client credentials flow, designed for server-to-server integrations. Your server exchanges a permanent client ID and client secret for an access token that lasts 30 minutes. Think of it as trading an employee badge for a day pass: the pass expires, the badge stays in the safe.

Create a credential

In the Mono Dashboard, open your organization's Credentials section and create a credential:

  1. Choose the scopes the credential may request. You can change them later.
  2. Copy the client ID and client secret. The dashboard shows the secret only once.
  3. Store both in your secrets manager.

You do not choose between Core and Banking: a Core organization always gets Core credentials. From the same section you can also disable, enable, or delete a credential.

Request an access token

Call the Core token endpoint with grant_type=client_credentials, your client ID and secret, and the scopes you need, separated by spaces:

curl https://api.cuentamono.com/v1/core/oauth/token \
  -d grant_type=client_credentials \
  -d client_id="$MONO_CLIENT_ID" \
  -d client_secret="$MONO_CLIENT_SECRET" \
  -d scope="ledger:readonly payouts"

The endpoint accepts application/x-www-form-urlencoded, as above, or the same fields as JSON. In sandbox, use https://api.sandbox.cuentamono.com.

{
  "access_token": "<access_token>",
  "token_type": "Bearer",
  "expires_in": 1800,
  "refresh_token": "<refresh_token>",
  "scope": "ledger:readonly payouts"
}

Always send scope. If you leave it out, Mono still issues a token, but with no scopes, and every endpoint then answers 403. If you ask for a scope your credential does not have, the whole request fails with 400 invalid_scope; Mono never returns a token with only part of what you asked for.

Call the API

Send the access token in the Authorization header, exactly like an API key:

curl https://api.cuentamono.com/v1/ledger/accounts \
  -H "Authorization: Bearer $MONO_ACCESS_TOKEN"

Renew the token

expires_in is the token's remaining lifetime in seconds: 1800 when it is issued. Request a new token before it runs out. You have two ways:

  • Request a new token with your client credentials, exactly as above. This is the simplest option for a server that always holds its secret.
  • Use the refresh token. The response also carries a refresh_token, valid for one day. Exchange it for a new access token:
curl https://api.cuentamono.com/v1/core/oauth/token \
  -d grant_type=refresh_token \
  -d client_id="$MONO_CLIENT_ID" \
  -d client_secret="$MONO_CLIENT_SECRET" \
  -d refresh_token="$MONO_REFRESH_TOKEN"

Each refresh returns a new refresh token. Use the new one next time and discard the old one.

Check or revoke a token

Two more endpoints take your client ID and secret plus the token itself:

  • Introspect (grant_type=introspect) tells you whether a token is still active, when it expires, and which scopes it carries. An expired or unknown token returns {"active": false}.
  • Revoke (grant_type=revoke) invalidates an access token or a refresh token at once. It answers 200 even if the token had already expired.

Revoke tokens you no longer need, for example when you retire a server. The endpoint contracts are in the Core authentication reference.

Scopes

Request the narrowest scopes your integration needs. Two rules apply across the catalog:

  • A bare scope, such as cards, grants every action on that resource, including the specific actions listed below it.
  • A :readonly scope grants reads only. It does not include the specific actions: cards:readonly does not grant cards:details.
ScopeGrants
ledgerAll permissions for ledger resources, and reading their programs
ledger:readonlyRead ledger resources and their programs
payinsAll permissions for payins, their templates, and their intents, and reading brands and settlement batches
payins:readonlyRead payins, their templates, their intents, brands, and settlement batches
payoutsAll permissions for payouts, Bre-B target resolution, and the bank catalog
payouts:readonlyRead payouts and the bank catalog
feesAll permissions for fees and the policies that charge them
fees:readonlyRead fees and their policies
fx_ratesRead the exchange rates of the supported currencies
fx_rates:readonlyRead the exchange rates of the supported currencies
cardsAll permissions for cards
cards:readonlyRead cards
cards:detailsRead a card's sensitive details: number, security code, expiry
spending_controlsAll permissions for card spending controls
spending_controls:readonlyRead card spending controls

Bre-B is Colombia's instant payment system, operated by the central bank. Target resolution turns a Bre-B key, such as a phone number, into the account it points to.

Failures

The token, introspect, and revoke endpoints answer errors in the OAuth format, with error and error_description fields. For example, 400 invalid_scope means you asked for a scope your credential does not have.

Every other endpoint answers with the standard error envelope:

StatusCodeWhat happened
401expired_tokenThe token expired, was revoked, or belongs to another service, such as Banking.
403not_authorizedThe credential is valid, but its scopes or roles do not allow this endpoint.
403not_authorizedA ledger endpoint was called by an organization that is not a Core organization.

A Banking token sent to a Core endpoint gets the same 401 expired_token as an expired token. If a fresh token is rejected that way, check that it came from /v1/core/oauth/token, not from /v1/oauth/token.

Next steps

On this page