# Quickstart Guide

# About Monato

Monato is a financial technology company specializing in payment services in Mexico. We provide secure, fast, and reliable payment solutions for businesses, enabling seamless bank transfers through our API and platform. Our mission is to simplify digital payments, ensuring efficiency and compliance with the highest security standards.

# Authentication

## Retrieve Credentials

Retrieve your `client_secret` which will be used afterwards for getting an `access_token`.

**Endpoint**:
`GET v1/clients/{{clientId}}/credentials/`

**Request**
**Headers**

* **x-api-key**: `Contact us at support@monato.com so we can provide you with a testing API Key`


**Path parameters**:

* **clientId**: `c2d1d1e3-3340-4170-980e-e9269bbbc551`


**Query Parameters**: none

**Response**

**Status Code**: 200 OK
**Response Body**:


```json
{
    "data": [
        {
            "id": "e981c6d8-4d49-45f2-a7ee-f956dca15500",
            "client_id": "c2d1d1e3-3340-4170-980e-e9269bbbc551",
            "client_secret": "Ui9gx7AXIpRqSkwSMQ35Ag1N5NXvm_7e4OEZESNMLQ29SbsvsXI1KKfIsGlZ70h_DfIPX2EWlysRlEKz8bXMsA",
            "environment": "staging",
            "status": "ACTIVE",
            "created_at": "2025-03-05 10:27:36.888241-06:00",
            "updated_at": "2025-03-05 10:27:36.888241-06:00",
            "deleted_at": "None"
        }
    ]
}
```

## Generate an Access Token

An access token will serve for requesting Finch API in a secure and controlled environment.
In the previous [section](#retrieve-credentials), you got a `client_secret` in the response body, you will use that value as your `client_secret` in the following request.

**Endpoint**:
`POST v1/clients/{{clientId}}/auth/credential-tokens`

**Request**
**Headers**

* **x-api-key**: `Contact us at support@monato.com so we can provide you with a testing API Key`


**Path parameters**: none

**Query Parameters**: none
**Request Body**:


```json
{
   "client_id": "c2d1d1e3-3340-4170-980e-e9269bbbc551",
   "client_secret": "Ui9gx7AXIpRqSkwSMQ35Ag1N5NXvm_7e4OEZESNMLQ29SbsvsXI1KKfIsGlZ70h_DfIPX2EWlysRlEKz8bXMsA"
}
```

**Response**
**Status Code**: 200 OK
**Response Body**:


```json
{
    "id": "1307f4e3-3960-4b98-9a14-0b6839245cc9",
    "client_id": "c2d1d1e3-3340-4170-980e-e9269bbbc551",
    "client_credential_id": "e981c6d8-4d49-45f2-a7ee-f956dca15500",
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRfaWQiOiJjMmQxZDFlMy0zMzQwLTQxNzAtOTgwZS1lOTI2OWJiYmM1NTEiLCJleHAiOjE3NDEyODE0MTl9.ziSqMClLqwUVfyM15bqUF_7-PINY0ZiWkH01s8pO3gA",
    "status": "ACTIVE",
    "expires_at": "2025-03-06 11:16:59.491631",
    "created_at": "2025-03-05 11:16:59.488685-06:00",
    "updated_at": "2025-03-05 11:16:59.488685-06:00",
    "deleted_at": "None"
}
```

From now you should send the following value in the header `Authorization`


```javascript
"Bearer " + token
```

Using the data in the response body in this example, your value is:


```
Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRfaWQiOiJjMmQxZDFlMy0zMzQwLTQxNzAtOTgwZS1lOTI2OWJiYmM1NTEiLCJleHAiOjE3NDEyODE0MTl9.ziSqMClLqwUVfyM15bqUF_7-PINY0ZiWkH01s8pO3gA
```

*(Disclaimer: this access token won't work in your environment and that is expected)*

# Concepts

## Centralizing Account

This account can send and receive money. Any deposit made to the Private Accounts that you created, will be automatically moved to this account.

## Private Account

A type of account that can only receive money in form of deposits. It has an automatically assigned CLABE, that your clients can set up in their banks to send money.

## Instrument

Instruments are Monato's specialized payment methods that allow you and your end-customers to interact with the financial system. Think of instruments as different "doors" into the same room (the account). Each door has its own unique properties and security features, but they all provide access to the same underlying funds.

An instrument is always owned either by:

- **The client** (for example, your Centralizing Account), or
- **A customer** (one of your end-users / business units).


This ownership is reflected in the response fields:

- `ownerId` – the entity that owns the instrument (client or customer)
- `customerId` – present only when the instrument belongs to a customer


For Money Out and Internal Transactions, you will reference these instruments via their IDs (`source_instrument_id` and `destination_instrument_id`).

# Create Private Accounts

## Prerequisites

Your account is ready for creating `private accounts` from the start, as Monato team has already set up your account with a default `Centralizing Account` and `Instrument`."

## Retrieve your Centralizing Account

By default, you have a Centralizing Account associated with your Client, you will need to have the following information handy for operations you will execute later:

* `id`: this is your `Centralizing Account` ID
* `instrumentId`: This is your default `Instrument` ID (the one we refer to in section [Instrument](#instrument))
* `bankId`: You will need this value to create Private Accounts and it's given to you as well
* `clientBankAdapterId`: You will need this value to create `Private Accounts`


**Endpoint**:
`GET v1/clients/{{clientId}}/accounts`

**Request**
**Path parameters**:

* **clientId**: `c2d1d1e3-3340-4170-980e-e9269bbbc551`


**Query Parameters**: none
**Request Body**: none

**Response**
**Status Code**: 200 OK
**Response Body**:


```json
{
    "currentPage": 1,
    "perPage": 50,
    "totalItem": 1,
    "data": [
        {
            "id": "24a726ac-180d-48df-82bc-711f2788a46f",
            "bankId": "9d84b03a-28d1-4898-a69c-38824239e2b1",
            "clientId": "c2d1d1e3-3340-4170-980e-e9269bbbc551",
            "clientBankAdapterId": "5b3a1b67-ab59-4cc1-8fc6-1d558b32b237",
            "accountId": "00000000-0000-0000-0000-000000000000",
            "instrumentId": "709448c3-7cbf-454d-a87e-feb23801269a",
            "ownerId": "c2d1d1e3-3340-4170-980e-e9269bbbc551",
            "ownerType": "CLIENT",
            "accountNumber": "000001000004",
            "clabeNumber": "734180000001000004",
            "availableBalance": "0.00",
            "accountType": "CENTRALIZING_ACCOUNT",
            "accountStatus": "ACTIVE",
            "audit": {
                "createdAt": "2025-03-11 11:00:56.264527-06:00",
                "updatedAt": "2025-03-11 11:00:56.264527-06:00",
                "deletedAt": "None",
                "blockedAt": "None",
                "activatedAt": "None",
                "suspendedAt": "None"
            },
            "bankAdapter": "SIES"
        }
    ]
}
```

### Collecting Information

The response will have an array with all your accounts, including any *Private Account* you already created. Search for the account with `accountType`= `CENTRALIZING_ACCOUNT` and take note of the values for the attributes, in this example the values are:

* `id`:  `24a726ac-180d-48df-82bc-711f2788a46f`
* `instrumentId`: `709448c3-7cbf-454d-a87e-feb23801269a`
* `bankId`: `9d84b03a-28d1-4898-a69c-38824239e2b1`
* `clientBankAdapterId`: `5b3a1b67-ab59-4cc1-8fc6-1d558b32b237`


## Create a Private Account

**Endpoint:**
`POST v1/clients/{{clientId}}/private_accounts`

**Request**
**Path parameters**:

* **clientId**: `c2d1d1e3-3340-4170-980e-e9269bbbc551`


**Query Parameters**: none
**Request Body**:


```json
{
    "bank_id": "9d84b03a-28d1-4898-a69c-38824239e2b1",
    "owner_id": "c2d1d1e3-3340-4170-980e-e9269bbbc551",
    "client_bank_adapter_id": "5b3a1b67-ab59-4cc1-8fc6-1d558b32b237",
    "client_id":"c2d1d1e3-3340-4170-980e-e9269bbbc551",
    "account_id":"24a726ac-180d-48df-82bc-711f2788a46f"
}
```

For this request, the values for `bank_id`, `client_bank_adapter_id` and `account_id` were taken from the [previous request](#collecting-information) where you got your `Centralizing Account` details. The values for `owner_id` and `client_id` are your Client Id.
Note: `owner_id` and `client_id` seem repeatable, but we will use them in the near future for other products. Bear in mind that for now, use both equally.

**Response**
**Status Code**: 200 OK
**Response Body**:


```json
{
    "id": "8d3e1f2a-5c7b-4d29-a1b9-0e9f8c7d6a5b",
    "bankId": "f2c4a6e8-1b3d-4f7a-9c5e-6b2a8d0e4f7c",
    "clientId": "9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d",
    "clientBankAdapterId": "3c5e7f9a-1b2d-4e6f-8a0b-9c8d7e6f5a4b",
    "accountId": "00000000-0000-0000-0000-000000000000",
    "instrumentId": "7e6d5c4b-3a29-4f8e-9d2c-1b0a9f8e7d6c",
    "ownerId": "9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d",
    "ownerType": "CLIENT",
    "accountNumber": "000700000004",
    "clabeNumber": "734180000700000004",
    "availableBalance": "5914.17",
    "accountType": "CENTRALIZING_ACCOUNT",
    "accountStatus": "ACTIVE",
    "audit": {
        "createdAt": "2025-06-13 10:56:22.888849-06:00",
        "updatedAt": "2025-06-13 10:56:22.888849-06:00",
        "deletedAt": "None",
        "blockedAt": "None"
    }
}
```

## Next steps

After creating a private account, you can manage its customer-facing lifecycle through the API.

Supported lifecycle actions include:

- Blocking a private account temporarily
- Reactivating a previously blocked private account
- Cancelling a private account permanently


See **Private Account Lifecycle** for details.

## Money Out

You may need to move funds from your Centralizing Account to an external bank account. To do this, you must first register an Instrument with the destination bank account details.

### Create an Instrument

**Endpoint**

`POST v1/clients/{{clientId}}/instruments`

#### Request

**Path parameters**

- `clientId`: `c2d1d1e3-3340-4170-980e-e9269bbbc551`


**Query parameters**

- none


**Request body**


```json
{
  "source_bank_id": "9d84b03a-28d1-4898-a69c-38824239e2b1",
  "client_id": "{{client_id}}",
  "customer_id": "{{customer_id}}", 
  "type": "SENDER_RECEIVER",
  "rfc": "XAXX010101000",
  "alias": "",
  "virtual_clabe": {
    "account_number": "064871131141",
    "clabe_number": "021180064871131141",
    "holder_name": "Martha Patricia de los Angeles Perez de Leon Ibarguengoitia",
    "destination_bank_id": "3114d179-8a10-40b9-b040-20ff464b50e0"
  }
}
```

Note: `holder_name` must have a maxLength of 40.

In this example we are using the `destination_bank_id` for Banamex, you can use the v1/banks endpoint to search for other Banks. Consider using URL parameters to get better results.

**Field notes**

- `customer_id` (string, optional)
  - If provided, the instrument will be owned by this customer.
  - If omitted, the instrument belongs to the client itself.
- `type` (string, required)
Instrument direction:
  - `RECEIVER` – Only receives funds.
  - `SENDER_RECEIVER` – Can be used for both sending and receiving (where supported).
- `rfc` (string, required)
Tax identifier of the account holder. If you don't have it, you can send `"ND"`.


**Response**
**Status Code**: 200 OK
**Response Body**:


```json
{
  "id": "d3fdb481-2058-46c8-807d-4eaf866ae1ec",
  "bankId": "3054ff18-32a0-478d-b9fe-b5261f9a6e1f",
  "clientId": "c2d1d1e3-3340-4170-980e-e9269bbbc551",
  "ownerId": "c2d1d1e3-3340-4170-980e-e9269bbbc551",
  "alias": "Instrumento A",
  "type": "SENDER_RECEIVER",
  "instrumentDetail": {
    "accountNumber": "None",
    "clabeNumber": "002180000000001801",
    "holderName": "John Smith"
  },
  "audit": {
    "createdAt": "2025-03-05 18:54:04.127190-06:00",
    "updatedAt": "2025-03-05 18:54:04.127190-06:00",
    "deletedAt": "None",
    "blockedAt": "None"
  },
  "rfc": "ND",
  "customerId": "bb1e8fde-e68e-48e9-a483-d32153c752c2"
}
```

**Response field notes**

`customerId` (string, optional) – Present when the instrument belongs to a customer. Omitted for client-level instruments.

**Error handling**

- If `client_id` does not exist:
  - `400` – `DATA_ERROR` with message similar to:
"No client found for id: {client_id}"
- If `customer_id` does not exist or does not belong to `client_id`:
  - `404` – `RESOURCE_NOT_FOUND` with message similar to:
`Customer not found`


## Money Out transaction

With the instrument associated to the recipient's Bank Account, and the default Instrument associated with your Centralizing Account, we have all the required data to initiate Money Out transactions.

> This endpoint supports **Idempotency** via the `Idempotency-Key` header.
TTL: 24 hours. Reuse the same key **with the exact same body** for safe retries.
If the body changes with the same key ⇒ `409 Conflict`.
Near-simultaneous duplicates ⇒ `409 Conflict` (“operation … in progress”).
See: **Guides → Idempotency** for details and code snippets.


Endpoint
`POST v1/transactions/money_out`

**Request**
**Path parameters**: none
**Query Parameters**: none
**Headers**:
`Authorization: Bearer <token>`
`Content-Type: application/json`
`Idempotency-Key: <uuid-v5>` *(optional but recommended)*
**Request Body**:


```json
{
  "client_id": "c2d1d1e3-3340-4170-980e-e9269bbbc551",
  "source_instrument_id":  "709448c3-7cbf-454d-a87e-feb23801269a",
  "destination_instrument_id":"d3fdb481-2058-46c8-807d-4eaf866ae1ec",
  "transaction_request": {
    "external_reference":"1234567",
    "description":"lorem ipsum dolor sit amet",
    "amount":"1.95",
    "currency":"MXN"
  }
}
```

The value for `source_instrument_id` is your default [instrument](#collecting-information)
The value for `destination_instrument_id` is from the previous [request](#create-an-instrument)

**Response**
**Status Code**: 200 OK
**Response Body**:


```json
{
 "id": "16811ee8-1ef9-4dd4-8d84-9c2df89cf302",
 "bankId": "9d84b03a-28d1-4898-a69c-38824239e2b1",
 "clientId": "c2d1d1e3-3340-4170-980e-e9269bbbc551",
 "externalReference": "1234567",
 "trackingId": "20250306FINCHVLIKQ5SKUM",
 "description": "lorem ipsum dolor sit amet",
 "amount": "1.95",
 "currency": "MXN",
 "category": "DEBIT_TRANS",
 "subCategory": "SPEI_DEBIT",
 "transactionStatus": "INITIALIZED",
 "audit": {
  "createdAt": "2025-03-06 11:57:55.408000-06:00",
  "updatedAt": "2025-03-06 11:57:55.408000-06:00",
  "deletedAt": "None",
  "blockedAt": "None"
 }
}
```

### Idempotency — common outcomes

**Invalid key format** (not UUID v5) → `400 Bad Request`
**Key–body mismatch** (same key, different body) → `409 Conflict`
**Duplicate while first is in-flight** → `409 Conflict` (“operation … in progress”)
**Identical retry** (same key + same body within 24h) → `200 OK` *(same payload, served from cache)*

## Notes & Limitations

**Transfers to Monato (Finco) accounts are not supported via Money Out.**
For these cases, please use the **Internal Transaction API**

Example error response when attempting to transfer to a Monato account:


```json
{
  "code": 13,
  "message": "API Error",
  "details": [
    {
      "@type": "type.googleapis.com/google.rpc.ErrorInfo",
      "reason": "FAILED_PRECONDITION",
      "domain": "CORE",
      "metadata": {
        "error_detail": "SPEI transfers between Finco accounts are not allowed. Please use the internal transaction option instead.",
        "http_code": "400",
        "module": "Transactions",
        "method_name": "money_out",
        "error_code": "10-E4120"
      }
    }
  ]
}
```

⚠️ **Disclaimer -** We plan to unify the APIs in the future so that both external Money Out (SPEI) and internal transactions (between Monato accounts) are supported through a single endpoint. For now, please use the endpoints separately as documented.