> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gr4vy.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Monato - SPEI

> Configure SPEI via Monato as a payment method in Gr4vy.

Monato supports SPEI as a redirect payment method in Mexico.

## Setup

Monato does not provide self-service sandbox sign-up. Contact [Monato](https://www.monato.com/) to create your account and enable SPEI.

## Credentials

When you configure Monato SPEI in the dashboard, provide the following credentials.

* **Client ID** (`client_id`): Monato client ID.
* **Client Secret** (`client_secret`): Monato client secret.
* **API Key** (`api_key`): API key for Monato credential token access.
* **Approval URL** (`approval_url`, optional): Custom URL for the approval experience when you pass `connection_options`.

If you do not provide `approval_url`, Gr4vy uses the hosted approval page.

## Supported countries

Monato supports transactions from buyers in `MX`.

## Supported currencies

Monato supports processing payments in `MXN`.

## Integration

Monato SPEI uses a redirect flow.

### Redirect integration

Create a transaction with the required fields.

<CodeGroup>
  ```csharp C# theme={"system"}
  var transaction = await client.Transactions.CreateAsync(
    transactionCreate: new TransactionCreate()
    {
      Amount = 1299,
      Currency = "MXN",
      Country = "MX",
      PaymentMethod =
        TransactionCreatePaymentMethod.CreateCheckoutSessionWithUrlPaymentMethodCreate(
          new RedirectPaymentMethodCreate()
          {
            Method = "spei",
            RedirectUrl = "https://example.com/callback",
          }
        ),
    }
  );
  ```

  ```go Go theme={"system"}
  amount := int64(1299)
  currency := "MXN"
  country := "MX"
  method := "spei"
  redirectUrl := "https://example.com/callback"

  redirectPaymentMethodCreate := components.RedirectPaymentMethodCreate{
    Method: method,
    RedirectUrl: redirectUrl,
  }
  paymentMethod := components.CreateTransactionCreatePaymentMethodRedirectPaymentMethodCreate(redirectPaymentMethodCreate)

  transactionCreate := components.TransactionCreate{
    Amount:        amount,
    Currency:      currency,
    Country:       &country,
    PaymentMethod: &paymentMethod,
  }

  transaction, err := client.Transactions.Create(ctx, transactionCreate, nil, nil)
  ```

  ```java Java theme={"system"}
  CreateTransactionResponse transactionResponse = gr4vyClient.transactions().create()
    .transactionCreate(TransactionCreate.builder()
      .amount(1299L)
      .currency("MXN")
      .country("MX")
      .paymentMethod(TransactionCreatePaymentMethod.of(RedirectPaymentMethodCreate.builder()
        .method("spei")
        .redirectUrl("https://example.com/callback")
        .build()))
      .build())
    .call();

  Transaction transaction = transactionResponse.transaction().orElse(null);
  ```

  ```php PHP theme={"system"}
  $transactionCreate = new TransactionCreate(
    amount: 1299,
    currency: 'MXN',
    country: 'MX',
    paymentMethod: new RedirectPaymentMethodCreate(
      method: 'spei',
      redirectUrl: 'https://example.com/callback'
    )
  );
  $response = self::$sdk->transactions->create($transactionCreate);
  $transaction = $response->transaction;
  ```

  ```python Python theme={"system"}
  transaction: models.Transaction = client.transactions.create(
    amount=1299,
    currency="MXN",
    country="MX",
    payment_method={
      "method": "spei",
      "redirect_url": "https://example.com/callback",
    }
  )
  ```

  ```ts TypeScript theme={"system"}
  const transaction = await gr4vy.transactions.create({
    amount: 1299,
    currency: "MXN",
    country: "MX",
    paymentMethod: {
      method: "spei",
      redirectUrl: "https://example.com/callback"
    }
  })
  ```
</CodeGroup>

After you create a transaction, the API response includes `payment_method.approval_url` and a `processing` status.

```json theme={"system"}
{
  "type": "transaction",
  "status": "processing",
  "payment_method": {
    "type": "payment-method",
    "approval_url": "https://..."
  },
  "method": "spei"
}
```

Use `payment_method.approval_url` to show the approval UI in a popup, iframe, or redirect. Approval links expire after 7 days.

### Recurring payments

Monato SPEI supports payment method tokenization for recurring payments.

To set up recurring payments:

* Store the payment method during the first SPEI transaction by setting `store: true`.
* Create subsequent charges with the stored `payment_method.id` and set `is_subsequent_payment`, `merchant_initiated`, and `payment_source`.

Use the following pattern for subsequent recurring charges.

<CodeGroup>
  ```csharp C# theme={"system"}
  var transaction = await client.Transactions.CreateAsync(
    transactionCreate: new TransactionCreate()
    {
      Amount = 1299,
      Currency = "MXN",
      Country = "MX",
      Intent = TransactionCreate.IntentEnum.Capture,
      PaymentMethod = TransactionCreatePaymentMethod.CreatePaymentMethodIdRequest(
        new PaymentMethodIdRequest()
        {
          Method = PaymentMethodIdRequest.MethodEnum.Id,
          Id = "f758d736-9a81-4bd0-85a9-2d3ee361b863"
        }
      ),
      IsSubsequentPayment = true,
      MerchantInitiated = true,
      PaymentSource = TransactionCreate.PaymentSourceEnum.Recurring
    }
  );
  ```

  ```go Go theme={"system"}
  amount := int64(1299)
  currency := "MXN"
  country := "MX"
  paymentSource := "recurring"

  paymentMethodIdRequest := components.PaymentMethodIdRequest{
    Method: components.PaymentMethodIdRequestMethodID,
    ID:     "f758d736-9a81-4bd0-85a9-2d3ee361b863",
  }
  paymentMethod := components.CreateTransactionCreatePaymentMethodPaymentMethodIdRequest(paymentMethodIdRequest)

  transactionCreate := components.TransactionCreate{
    Amount:              amount,
    Currency:            currency,
    Country:             &country,
    Intent:              components.CreateTransactionIntentCapture,
    PaymentMethod:       &paymentMethod,
    IsSubsequentPayment: gr4vy.Bool(true),
    MerchantInitiated:   gr4vy.Bool(true),
    PaymentSource:       &paymentSource,
  }

  transaction, err := client.Transactions.Create(ctx, transactionCreate, nil, nil)
  ```

  ```java Java theme={"system"}
  CreateTransactionResponse transactionResponse = gr4vyClient.transactions().create()
    .transactionCreate(TransactionCreate.builder()
      .amount(1299L)
      .currency("MXN")
      .country("MX")
      .intent(Intent.CAPTURE)
      .paymentMethod(TransactionCreatePaymentMethod.of(PaymentMethodIdRequest.builder()
        .method(PaymentMethodIdRequest.Method.ID)
        .id("f758d736-9a81-4bd0-85a9-2d3ee361b863")
        .build()))
      .isSubsequentPayment(true)
      .merchantInitiated(true)
      .paymentSource(PaymentSource.RECURRING)
      .build())
    .call();

  Transaction transaction = transactionResponse.transaction().orElse(null);
  ```

  ```php PHP theme={"system"}
  $transactionCreate = new TransactionCreate(
    amount: 1299,
    currency: 'MXN',
    country: 'MX',
    intent: Intent::Capture,
    paymentMethod: new PaymentMethodIdRequest(
      method: PaymentMethodIdRequestMethod::ID,
      id: 'f758d736-9a81-4bd0-85a9-2d3ee361b863'
    ),
    isSubsequentPayment: true,
    merchantInitiated: true,
    paymentSource: PaymentSource::Recurring
  );
  $response = self::$sdk->transactions->create($transactionCreate);
  $transaction = $response->transaction;
  ```

  ```python Python theme={"system"}
  transaction: models.Transaction = client.transactions.create(
    amount=1299,
    currency="MXN",
    country="MX",
    intent=models.Intent.CAPTURE,
    payment_method=models.PaymentMethodIdRequest(
      method=models.PaymentMethodIdRequestMethod.ID,
      id="f758d736-9a81-4bd0-85a9-2d3ee361b863"
    ),
    is_subsequent_payment=True,
    merchant_initiated=True,
    payment_source=models.PaymentSource.RECURRING
  )
  ```

  ```ts TypeScript theme={"system"}
  const transaction = await gr4vy.transactions.create({
    amount: 1299,
    currency: "MXN",
    country: "MX",
    intent: "capture",
    paymentMethod: {
      method: "id",
      id: "f758d736-9a81-4bd0-85a9-2d3ee361b863"
    },
    isSubsequentPayment: true,
    merchantInitiated: true,
    paymentSource: "recurring"
  })
  ```
</CodeGroup>

Because this connector requires webhooks, confirm webhook delivery is active before you rely on recurring status updates.

#### Recurring caveats

When you implement recurring payments with Monato SPEI, keep these caveats in mind.

1. For one-off transactions, `payment_service_transaction_id` is the CLABE value.
2. For recurring transactions, `payment_service_transaction_id` is the CLABE plus the Gr4vy transaction ID. This combination gives each recurring transaction a unique value, because SPEI does not provide a stable unique transaction ID.
3. Because of this format, Gr4vy can not automatically reconcile recurring webhooks from SPEI. You should proxy `MONEY_IN` events, find the matching transaction in Gr4vy, and then include `transaction_id` in the webhook body you send to Gr4vy.

Use the following payload pattern when you proxy `MONEY_IN` for recurring transactions.

```json theme={"system"}
{
  "id_msg": "a7a126e8-fa74-411c-ad2b-b000f277bb0d",
  "msg_name": "MONEY_IN",
  "msg_date": "2029-04-02",
  "body": {
    "id": "0196da9a-8947-703e-9a3b-bf8c7d9f6059",
    "beneficiary_account": "646180529600044117",
    "beneficiary_name": "John Smith",
    "beneficiary_rfc": "XYZ123456789",
    "payer_account": "137180210044008609",
    "payer_name": "Juan Perez",
    "payer_rfc": "XYZ987654321",
    "payer_institution": "40002",
    "amount": "123.00",
    "transaction_date": "20250402",
    "tracking_key": "50118609TBRNZ00I07219647",
    "payment_concept": "Payment for invoice 4567",
    "numeric_reference": "2504021",
    "transaction_id": "f0894971-7898-4c70-a10e-a7aa65d515b8"
  }
}
```

## Custom expiration date

By default, Monato SPEI approval links expire after 7 days. You can set a custom expiration per transaction using the top-level `approval_expires_at` field on the transaction request. The value must be a future datetime in ISO 8601 format.

<Note>
  Monato SPEI does not pass the expiration date to the PSP. The value is stored in Gr4vy and used to manage the transaction lifecycle on the platform side.
</Note>

<CodeGroup>
  ```csharp C# highlight={6} theme={"system"}
  var transaction = await client.Transactions.CreateAsync(
    transactionCreate: new TransactionCreate()
    {
      Amount = 1299,
      Currency = "MXN",
      ApprovalExpiresAt = DateTimeOffset.Parse("2026-04-10T23:59:59Z"),
      PaymentMethod =
        TransactionCreatePaymentMethod.CreateCheckoutSessionWithUrlPaymentMethodCreate(
          new RedirectPaymentMethodCreate()
          {
            Method = "spei",
            RedirectUrl = "https://example.com/callback",
          }
        ),
    }
  );
  ```

  ```go Go highlight={6} theme={"system"}
  transactionCreate := components.TransactionCreate{
    Amount:            amount,
    Currency:          currency,
    Country:           &country,
    PaymentMethod:     &paymentMethod,
    ApprovalExpiresAt: gr4vy.Time(time.Date(2026, 4, 10, 23, 59, 59, 0, time.UTC)),
  }

  transaction, err := client.Transactions.Create(ctx, transactionCreate, nil, nil)
  ```

  ```java Java highlight={5} theme={"system"}
  CreateTransactionResponse transactionResponse = gr4vyClient.transactions().create()
    .transactionCreate(TransactionCreate.builder()
      .amount(1299L)
      .currency("MXN")
      .approvalExpiresAt(OffsetDateTime.parse("2026-04-10T23:59:59Z"))
      .paymentMethod(TransactionCreatePaymentMethod.of(RedirectPaymentMethodCreate.builder()
        .method("spei")
        .redirectUrl("https://example.com/callback")
        .build()))
      .build())
    .call();
  ```

  ```php PHP highlight={5} theme={"system"}
  $transactionCreate = new TransactionCreate(
    amount: 1299,
    currency: 'MXN',
    country: 'MX',
    approvalExpiresAt: new \DateTime('2026-04-10T23:59:59Z'),
    paymentMethod: new RedirectPaymentMethodCreate(
      method: 'spei',
      redirectUrl: 'https://example.com/callback'
    )
  );
  $response = self::$sdk->transactions->create($transactionCreate);
  ```

  ```python Python highlight={5} theme={"system"}
  transaction: models.Transaction = client.transactions.create(
    amount=1299,
    currency="MXN",
    country="MX",
    approval_expires_at=datetime(2026, 4, 10, 23, 59, 59, tzinfo=timezone.utc),
    payment_method={
      "method": "spei",
      "redirect_url": "https://example.com/callback",
    }
  )
  ```

  ```ts TypeScript highlight={5} theme={"system"}
  const transaction = await gr4vy.transactions.create({
    amount: 1299,
    currency: "MXN",
    country: "MX",
    approvalExpiresAt: new Date("2026-04-10T23:59:59Z"),
    paymentMethod: {
      method: "spei",
      redirectUrl: "https://example.com/callback"
    }
  })
  ```
</CodeGroup>

## Webhooks

This connector requires webhooks. Contact Monato support to configure webhook delivery.

Monato sends `MONEY_IN` when a payment is captured.

## Testing

Contact Monato support and request a SPEI test transaction (`MONEY_IN`) using the CLABE from the payment session flow.
