> Chytapay is a bank-transfer payments platform in Argentina. This page is part of the Integration API docs: https://chytapay.com.ar/api/
> Recommended reconciliation: by CUIL. Environments: test (https://integration-api.test.chytapay.com.ar) and production (https://integration-api.chytapay.com.ar).
> Page: "Getting started" (https://chytapay.com.ar/api/en/getting-started/), updated on 2026-10-09.
> Full index for AI assistants: https://chytapay.com.ar/llms.txt

# Getting started

From sign-up in the portal to your first event in your backend, all in Sandbox: credentials, a connected merchant account, a charge, a simulated payment and the webhook.

By the end you will have a Sandbox charge paid with a simulated payment and the `payment_request.payment_received` event in your backend. No real money moves.



1. [Sign up and set up](https://chytapay.com.ar/api/en/getting-started/#credenciales): Portal and webhook
2. [Get a test merchant account](https://chytapay.com.ar/api/en/getting-started/#conectar): Sandbox token
3. [Create a charge](https://chytapay.com.ar/api/en/getting-started/#crear-cobro): POST /payment-request
4. [Simulate the payment](https://chytapay.com.ar/api/en/getting-started/#simular-pago): Sandbox only
5. [Receive the event](https://chytapay.com.ar/api/en/getting-started/#recibir-evento): webhook in your backend

## Before you begin

- A **public HTTPS URL** for webhooks. During development, a tunnel works.
- `curl`, Node 18 or later, or Python 3 with `requests`.



Set the Sandbox API URL in your terminal. The Production one is in [Operations and errors](https://chytapay.com.ar/api/en/operacion/#ambientes).

```bash
export API=https://integration-api.test.chytapay.com.ar
```

## 1. Sign up and set up

You sign up yourself in the portal, with no one to wait for. You start in Sandbox, the test environment.



1. Go to [chytapay.com.ar/portal/login](https://chytapay.com.ar/portal/login), choose **Crear cuenta** (Create account), confirm your email and fill in your company details. When you finish, the portal shows your Sandbox `clientId` and `clientSecret`.
2. Store them in your secrets manager. The `clientSecret` is shown only once: if you lose it, rotate it under [**Credenciales**](https://chytapay.com.ar/portal/credentials) (Credentials). You don't use them in this walkthrough: they are for OAuth with real merchant accounts.
3. Add your HTTPS webhook URL under [**Configuración**](https://chytapay.com.ar/portal/settings) (Settings). The validation token is optional, at least 16 characters long, and arrives in the `validation-token` header.



## 2. Get a test merchant account

The Integration API takes as Bearer the `idToken` of a merchant account linked to your integration. It lasts 1 hour.

### Sandbox shortcut: a test merchant account

In Sandbox you don't need OAuth: the portal gives you the token of a test merchant account that is already linked. Go to [**Cuentas de comercio**](https://chytapay.com.ar/portal/users) (Merchant accounts), choose **Generar tokens de prueba** (Generate test tokens) and store the `idToken` as `COMMERCE_TOKEN`. It lasts 1 hour: when it expires, generate another. To check which merchant the token belongs to, [call `GET /me`](https://chytapay.com.ar/api/en/conectar-comercios/#confirmar-comercio).

### The real flow: OAuth

In Production, each merchant account authorizes your integration with OAuth: authorize, return to your `redirect_uri` with `code` and `state`, and exchange for tokens. The `redirect_uri` [is not the webhook URL](https://chytapay.com.ar/api/en/conectar-comercios/#redirect-uri-vs-webhook). See [how to connect merchant accounts with OAuth](https://chytapay.com.ar/api/en/conectar-comercios/).

## 3. Create a charge

In your backend, create the charge with the merchant account token and a due date between tomorrow and 35 days out. Send `"conciliationType": "cuil"` and the payer's CUIL or DNI in `customer.taxDocument`: the payment is matched by the CUIL of whoever transfers ([why CUIL](https://chytapay.com.ar/api/en/conciliacion/#conciliar-cuil)).

**cURL**

```bash
DUE_DATE=$(date -d '+7 days' +%F 2>/dev/null || date -v+7d +%F)

curl -X POST "$API/payment-request" \
  -H "Authorization: Bearer $COMMERCE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "referenceId": "test-0001",
    "amount": 1500,
    "description": "Test charge",
    "dueDates": ["'"$DUE_DATE"'"],
    "conciliationType": "cuil",
    "sendWhatsappNotification": false,
    "sendEmailNotification": false,
    "customer": { "name": "Test payer", "taxDocument": "20123456786" }
  }'
```

**Node**

```js
const dueDate = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10);

const res = await fetch(`${process.env.API}/payment-request`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.COMMERCE_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    referenceId: 'test-0001',
    amount: 1500,
    description: 'Test charge',
    dueDates: [dueDate],
    conciliationType: 'cuil',
    sendWhatsappNotification: false,
    sendEmailNotification: false,
    customer: { name: 'Test payer', taxDocument: '20123456786' },
  }),
});
const charge = await res.json();
console.log(res.status, charge.state, charge.CVU);
```

**Python**

```python
from datetime import date, timedelta

due_date = (date.today() + timedelta(days=7)).isoformat()

res = requests.post(
    f"{os.environ['API']}/payment-request",
    headers={"Authorization": f"Bearer {os.environ['COMMERCE_TOKEN']}"},
    json={
        "referenceId": "test-0001",
        "amount": 1500,
        "description": "Test charge",
        "dueDates": [due_date],
        "conciliationType": "cuil",
        "sendWhatsappNotification": False,
        "sendEmailNotification": False,
        "customer": {"name": "Test payer", "taxDocument": "20123456786"},
    },
)
charge = res.json()
print(res.status_code, charge["state"], charge["CVU"])
```

**Response**

```json
{
  "type": "standard",
  "paymentRequestId": "00000000-0000-0000-0000-000000000000",
  "referenceId": "test-0001",
  "amount": 1500,
  "description": "Test charge",
  "dueDates": ["2026-10-07"],
  "state": "pending",
  "sendWhatsappNotification": false,
  "sendEmailNotification": false,
  "customer": { "name": "Test payer", "taxDocument": "20123456786" },
  "CVU": "0000000000000000000000",
  "bankAccountInfo": { "accountHolderName": "...", "accountHolderTaxId": "...", "bankName": "..." }
}
```

You get a `201` with the charge in `pending`. Store the `CVU` in the `CVU` variable for [stage 4](https://chytapay.com.ar/api/en/getting-started/#simular-pago).

- `referenceId` is 8 to 100 characters (letters, numbers, `-` and `_`) and unique per integration and merchant account, canceled charges included. A repeat returns `409` `ReferenceIdAlreadyExists`: to test again, change it.
- With `amount`, `sendWhatsappNotification` and `sendEmailNotification` are required. In Sandbox, `false`.
- Amounts in pesos, with up to 2 decimal places.

The other fields, surcharges, drafts and batches are in [Create charges](https://chytapay.com.ar/api/en/crear-cobros/).

## 4. Simulate the payment

Simulate full payment in the Portal, under [**Simulador de pagos**](https://chytapay.com.ar/portal/simulate) (Payment simulator): enter the charge's CVU, the amount and the payer's details: source CVU, source name and, as the source CUIL, the charge's.

- With the charge's CUIL, the payment is matched and `payment_request.payment_received` arrives.
- With a different CUIL it does not reconcile and the event is `payment.unmatched`.
- If the event doesn't arrive, check that it is enabled under [**Webhooks**](https://chytapay.com.ar/portal/notifications) and that you have a URL set under [**Configuración**](https://chytapay.com.ar/portal/settings).

> **Warning:** **`payment.unmatched` is off by default.** Enable it in [**Webhooks**](https://chytapay.com.ar/portal/notifications): without it you never learn about unmatched payments, such as a third party paying with a different CUIL.

## 5. Receive the event

Chytapay sends a `POST` to your webhook URL. Return a `2xx` within 5 seconds or it retries.

| Header                  | Purpose                                                                          |
| ----------------------- | -------------------------------------------------------------------------------- |
| `X-Chytapay-Signature`  | HMAC-SHA256 signature, `t=<unix>,v1=<hex>`. Verify it before you trust the event |
| `X-Chytapay-Webhook-Id` | Same across all retries: deduplicate by this ID                                  |
| `validation-token`      | The token you set with the URL                                                   |

The body, trimmed:

```json
{
  "event": "payment_request.payment_received",
  "stateType": "total_payment",
  "livemode": false,
  "referenceId": "test-0001",
  "requestedAmount": 1500,
  "paidAmount": 1500,
  "thisPaymentAmount": 1500,
  "remainingAmount": 0,
  "reconciledPayerCuil": 20123456786
}
```

Route on `event` and decide on `stateType`: `total_payment` or `partial_payment`. `livemode` is `false` in Sandbox.

The example server, full signature verification and retries are in [Webhooks](https://chytapay.com.ar/api/en/webhooks/). To test only your endpoint, [**Webhooks**](https://chytapay.com.ar/portal/notifications) has a button that sends a test `payment.unmatched`. It does not exist in production.



## Go to production

It is the same integration: you request Production under [**Credenciales**](https://chytapay.com.ar/portal/credentials) (Credentials), and if the automatic check approves it you generate the production credentials with the environment selector on Production. If not, the request goes to review. What to check before you collect is in [Operations and errors](https://chytapay.com.ar/api/en/operacion/#produccion).

## Next steps

- [Connect merchant accounts](https://chytapay.com.ar/api/en/conectar-comercios/): OAuth, tokens and unlinking.
- [Create charges](https://chytapay.com.ar/api/en/crear-cobros/): Fields, states and batches.
- [Webhooks](https://chytapay.com.ar/api/en/webhooks/): Signature, retries and deduplication.
