# SPEI transaction

Process an online SPEI purchase or payout using pay by bank.

## Overview

You can submit a SPEI transaction in these ways:

- **Purchase (deposit):** Create a pay-by-bank transaction with `apmProvider` set to `Spei` and `intent` set to `Purchase`. Redirect the shopper to `fundingData.payByBank.redirectUrl` so they can complete the transfer.
- **Payout (withdrawal), new bank account:** Create a Pay by bank transaction with `intent` set to `Payout` and supply `bankAccountNumber`, `bankCode`, and `accountType`. Capture `stateData.gatewayTokenId` from the response to reuse the destination later.
- **Payout (withdrawal), stored bank account:** Create a payout and supply `gatewaytokenid` from an earlier accepted payout instead of resending bank details.


SPEI supports `MXN` only and shoppers in Mexico (`countryCode` `MX`). Treat merchant webhooks as the authoritative final outcome. Don't treat the shopper's browser return from the hosted page as payment confirmation. [Learn more about webhooks](/guides/get-started/about-webhooks).

## Initiate a SPEI transaction

/v1/transactions

### Request examples

Purchase
Use the following request to start a SPEI deposit. Send the shopper to the `redirectUrl` returned in the response.

```json
{
  "merchant": "MERCHANT-1",
  "site": "SITE-1",
  "merchantTransactionId": "SPEI-TXN-001",
  "merchantTransactionDate": "2024-01-27 08:51:02.826445+00:00",
  "transactionMethod": {
    "intent": "Purchase",
    "entryType": "Ecom",
    "fundingType": "PayByBank"
  },
  "fundingData": {
    "payByBank": {
      "apmProvider": "Spei",
      "language": "ES"
    }
  },
  "amounts": {
    "transaction": 100.00,
    "currencyCode": "MXN"
  },
  "shopper": {
    "id": "Shopper_MX_01",
    "firstName": "Juan",
    "lastName": "Garcia",
    "dateOfBirth": "1990-01-01",
    "email": "juan.garcia@example.com",
    "countryCode": "MX",
    "documentType": "TaxIdNumber",
    "documentNumber": "HEGJ850101ABC",
    "phoneNumber": "+5215555555555"
  }
}
```

| Parameter | Description |
|  --- | --- |
| `merchant`string (≤ 20 characters) | Your unique merchant identifier, as assigned by PXP. |
| `site`string (≤ 20 characters) | Your unique site identifier, as assigned by PXP. |
| `merchantTransactionId`string (≤ 50 characters) | A unique identifier for this transaction. |
| `merchantTransactionDate`date-time | The date and time when the transaction happened, in ISO 8601 format. |
| `transactionMethod`object | Details about the transaction method. |
| `transactionMethod.entryType`string | The entry type. For e-commerce SPEI transactions, this is always `Ecom`. |
| `transactionMethod.fundingType`string | The funding type. For SPEI, this is always `PayByBank`. |
| `transactionMethod.intent`string | The payment intent. For a SPEI deposit, set this to `Purchase`. [Learn more about intents](/guides/transactions/how-it-works#intents). |
| `amounts`object | Details about the transaction amount. |
| `amounts.transaction`number | The transaction amount. The numbers after the decimal will be zero padded if they are less than the expected `currencyCode` exponent. For example, GBP 1.1 = GBP 1.10, EUR 1 = EUR 1.00, or BHD 1.3 = 1.300. The transaction will be rejected if numbers after the decimal are greater than the expected `currencyCode` exponent (e.g., GBP 1.234), or if a decimal is supplied when the `currencyCode` exponent does not require it (e.g., JPY 1.0). |
| `amounts.currencyCode`string (1-3 characters) | The currency code associated with the transaction, in ISO 4217 format. For SPEI, this must be `MXN`. |
| `fundingData`object | Details about the payment method used for the transaction. For SPEI, use the Pay by bank funding shape only. |
| `fundingData.payByBank`object | Pay by bank funding details for SPEI. |
| `fundingData.payByBank.apmProvider`string | The APM provider. For SPEI, this must be `Spei`. |
| `fundingData.payByBank.language`string (2 characters) | The language code for the hosted SPEI experience, in ISO 639-1 format. Defaults to `ES`. Purchase only. |
| `fundingData.payByBank.bankAccountNumber`string | An optional destination CLABE or bank account number for the purchase. |
| `fundingData.payByBank.bankCode`string | An optional destination bank code for the purchase. |
| `fundingData.payByBank.successRedirectUrl`string (URI) | An optional HTTPS URL where the shopper is returned after a successful hosted SPEI purchase. |
| `fundingData.payByBank.failureRedirectUrl`string (URI) | An optional HTTPS URL where the shopper is returned after a failed hosted SPEI purchase. |
| `shopper`object | Details about the shopper making the payment. |
| `shopper.countryCode`string (2 characters) | The shopper's country, in ISO 3166-1 alpha-2 format. For SPEI, this must be `MX`. |
| `shopper.documentType`string | The shopper identity document type. For SPEI, use `TaxIdNumber` (RFC) or `CivilRegisterId` (CURP). When supplied, `documentNumber` is also required. |
| `shopper.documentNumber`string | The shopper identity document number. Exactly 13 alphanumeric characters for `TaxIdNumber`, or exactly 18 for `CivilRegisterId`. |
| `shopper.phoneNumber`string | The shopper's phone number in E.164 format (e.g., `+5215555555555`). |


Payout (new bank account)
Use the following request to start a SPEI withdrawal when you supply the destination bank account for the first time. Capture `stateData.gatewayTokenId` from the response so you can reuse the same destination later.

```json
{
  "merchant": "MERCHANT-1",
  "site": "SITE-1",
  "merchantTransactionId": "SPEI-PAYOUT-001",
  "merchantTransactionDate": "2024-01-27 08:51:02.826445+00:00",
  "transactionMethod": {
    "intent": "Payout",
    "entryType": "Ecom",
    "fundingType": "PayByBank"
  },
  "fundingData": {
    "payByBank": {
      "apmProvider": "Spei",
      "bankAccountNumber": "012180001234567890",
      "bankCode": "012",
      "accountType": "Clabe"
    }
  },
  "amounts": {
    "transaction": 100,
    "currencyCode": "MXN"
  },
  "shopper": {
    "id": "Shopper_MX_01",
    "firstName": "Juan",
    "lastName": "Garcia",
    "dateOfBirth": "1990-01-01",
    "email": "juan.garcia@example.com",
    "countryCode": "MX",
    "documentType": "TaxIdNumber",
    "documentNumber": "HEGJ850101ABC",
    "phoneNumber": "+5215555555555"
  }
}
```

| Parameter | Description |
|  --- | --- |
| `merchant`string (≤ 20 characters) | Your unique merchant identifier, as assigned by PXP. |
| `site`string (≤ 20 characters) | Your unique site identifier, as assigned by PXP. |
| `merchantTransactionId`string (≤ 50 characters) | A unique identifier for this transaction. |
| `merchantTransactionDate`date-time | The date and time when the transaction happened, in ISO 8601 format. |
| `transactionMethod`object | Details about the transaction method. |
| `transactionMethod.entryType`string | The entry type. For e-commerce SPEI transactions, this is always `Ecom`. |
| `transactionMethod.fundingType`string | The funding type. For SPEI, this is always `PayByBank`. |
| `transactionMethod.intent`string | The payment intent. For a SPEI withdrawal, set this to `Payout`. [Learn more about intents](/guides/transactions/how-it-works#intents). |
| `amounts`object | Details about the transaction amount. |
| `amounts.transaction`number | The transaction amount. The numbers after the decimal will be zero padded if they are less than the expected `currencyCode` exponent. For example, GBP 1.1 = GBP 1.10, EUR 1 = EUR 1.00, or BHD 1.3 = 1.300. The transaction will be rejected if numbers after the decimal are greater than the expected `currencyCode` exponent (e.g., GBP 1.234), or if a decimal is supplied when the `currencyCode` exponent does not require it (e.g., JPY 1.0). |
| `amounts.currencyCode`string (1-3 characters) | The currency code associated with the transaction, in ISO 4217 format. For SPEI, this must be `MXN`. |
| `fundingData`object | Details about the payment method used for the transaction. For SPEI, use the Pay by bank funding shape only. |
| `fundingData.payByBank`object | Pay by bank funding details for SPEI. |
| `fundingData.payByBank.apmProvider`string | The APM provider. For SPEI, this must be `Spei`. |
| `fundingData.payByBank.bankAccountNumber`string | The destination CLABE or bank account number. Required with `bankCode` and `accountType` when `gatewaytokenid` isn't supplied. |
| `fundingData.payByBank.bankCode`string | The destination bank code. Required with `bankAccountNumber` and `accountType` when `gatewaytokenid` isn't supplied. |
| `fundingData.payByBank.accountType`string | The destination bank account type. Possible values: `Savings`, `Current`, `Clabe`. Required when `gatewaytokenid` isn't supplied. |
| `shopper`object | Details about the shopper receiving the payout. |
| `shopper.countryCode`string (2 characters) | The shopper's country, in ISO 3166-1 alpha-2 format. For SPEI, this must be `MX`. |
| `shopper.documentType`string | The shopper identity document type. For SPEI, use `TaxIdNumber` (RFC) or `CivilRegisterId` (CURP). When supplied, `documentNumber` is also required. |
| `shopper.documentNumber`string | The shopper identity document number. Exactly 13 alphanumeric characters for `TaxIdNumber`, or exactly 18 for `CivilRegisterId`. |
| `shopper.phoneNumber`string | The shopper's phone number in E.164 format (e.g., `+5215555555555`). |


Payout (stored bank account)
Use the following request to start a SPEI withdrawal when you already have a `gatewaytokenid` from an earlier accepted payout. You don't need to resend bank account details.

```json
{
  "merchant": "MERCHANT-1",
  "site": "SITE-1",
  "merchantTransactionId": "SPEI-PAYOUT-002",
  "merchantTransactionDate": "2024-01-27 08:51:02.826445+00:00",
  "transactionMethod": {
    "intent": "Payout",
    "entryType": "Ecom",
    "fundingType": "PayByBank"
  },
  "fundingData": {
    "payByBank": {
      "apmProvider": "Spei",
      "gatewaytokenid": "b6e2f1a4c3d84f7ab1e9d2c3f4a5b6c7"
    }
  },
  "amounts": {
    "transaction": 100,
    "currencyCode": "MXN"
  },
  "shopper": {
    "id": "Shopper_MX_01",
    "firstName": "Juan",
    "lastName": "Garcia",
    "dateOfBirth": "1990-01-01",
    "email": "juan.garcia@example.com",
    "countryCode": "MX",
    "documentType": "TaxIdNumber",
    "documentNumber": "HEGJ850101ABC",
    "phoneNumber": "+5215555555555"
  }
}
```

| Parameter | Description |
|  --- | --- |
| `merchant`string (≤ 20 characters) | Your unique merchant identifier, as assigned by PXP. |
| `site`string (≤ 20 characters) | Your unique site identifier, as assigned by PXP. |
| `merchantTransactionId`string (≤ 50 characters) | A unique identifier for this transaction. |
| `merchantTransactionDate`date-time | The date and time when the transaction happened, in ISO 8601 format. |
| `transactionMethod`object | Details about the transaction method. |
| `transactionMethod.entryType`string | The entry type. For e-commerce SPEI transactions, this is always `Ecom`. |
| `transactionMethod.fundingType`string | The funding type. For SPEI, this is always `PayByBank`. |
| `transactionMethod.intent`string | The payment intent. For a SPEI withdrawal, set this to `Payout`. [Learn more about intents](/guides/transactions/how-it-works#intents). |
| `amounts`object | Details about the transaction amount. |
| `amounts.transaction`number | The transaction amount. The numbers after the decimal will be zero padded if they are less than the expected `currencyCode` exponent. For example, GBP 1.1 = GBP 1.10, EUR 1 = EUR 1.00, or BHD 1.3 = 1.300. The transaction will be rejected if numbers after the decimal are greater than the expected `currencyCode` exponent (e.g., GBP 1.234), or if a decimal is supplied when the `currencyCode` exponent does not require it (e.g., JPY 1.0). |
| `amounts.currencyCode`string (1-3 characters) | The currency code associated with the transaction, in ISO 4217 format. For SPEI, this must be `MXN`. |
| `fundingData`object | Details about the payment method used for the transaction. For SPEI, use the Pay by bank funding shape only. |
| `fundingData.payByBank`object | Pay by bank funding details for SPEI. |
| `fundingData.payByBank.apmProvider`string | The APM provider. For SPEI, this must be `Spei`. |
| `fundingData.payByBank.gatewaytokenid`string | The reference to a stored PXP payment account for the destination bank account. Use the `stateData.gatewayTokenId` value from an earlier accepted SPEI payout response. |
| `shopper`object | Details about the shopper receiving the payout. |
| `shopper.countryCode`string (2 characters) | The shopper's country, in ISO 3166-1 alpha-2 format. For SPEI, this must be `MX`. |
| `shopper.documentType`string | The shopper identity document type. For SPEI, use `TaxIdNumber` (RFC) or `CivilRegisterId` (CURP). When supplied, `documentNumber` is also required. |
| `shopper.documentNumber`string | The shopper identity document number. Exactly 13 alphanumeric characters for `TaxIdNumber`, or exactly 18 for `CivilRegisterId`. |
| `shopper.phoneNumber`string | The shopper's phone number in E.164 format (e.g., `+5215555555555`). |


### Response examples

If your request is successful, you'll receive a `200` response. For a successful SPEI purchase initiation, expect a `Pending` state and a populated `fundingData.payByBank.redirectUrl`. For a successful SPEI payout initiation, expect `Pending` state with no `redirectUrl`, and `stateData.gatewayTokenId` when the payout is accepted.

The final outcome is delivered by a SPEI merchant webhook (e.g., `spei-transaction-order-executed`). [Learn more about webhooks](/guides/get-started/about-webhooks).

Always use the `systemTransactionId` for later PXP API calls against the same transaction. Provider payment identifiers (`providerTransactionId`, `fundingData.payByBank.paymentId`, and `fundingData.payByBank.processorPaymentId`) are for reconciliation and support only.

Purchase
```json
{
  "state": "Pending",
  "systemTransactionId": "1ed768bb-e88a-4636-91ae-67927ccbb02b",
  "merchantTransactionId": "SPEI-TXN-001",
  "providerTransactionId": "9a4c7e21-3f5d-4b8e-8a1c-2d3e4f5a6b7c",
  "fundingData": {
    "payByBank": {
      "apmProvider": "Spei",
      "redirectUrl": "https://hosted-payment-page.example/spei/...",
      "paymentId": "6f2b6d0a-8b1a-4e2b-9c3d-0a1b2c3d4e5f",
      "processorPaymentId": "9a4c7e21-3f5d-4b8e-8a1c-2d3e4f5a6b7c"
    }
  }
}
```

Payout
```json
{
  "state": "Pending",
  "systemTransactionId": "1ed768bb-e88a-4636-91ae-67927ccbb02b",
  "merchantTransactionId": "SPEI-PAYOUT-001",
  "fundingData": {
    "payByBank": {
      "apmProvider": "Spei",
      "paymentId": "7c1d8e32-4a6b-4f9c-b2d3-1e2f3a4b5c6d"
    }
  },
  "stateData": {
    "gatewayTokenId": "b6e2f1a4c3d84f7ab1e9d2c3f4a5b6c7"
  }
}
```