# Tilopay Developer and AI Agent Portal — full text
> Tilopay technical documentation (SDK, API, webhooks, testing) in Markdown, with nothing normative locked inside images.
Language: English. Index: https://tilopay.com/en/llms.txt
## Machine-readable artifacts
- [openapi.json](https://tilopay.com/developers/openapi.json): OpenAPI 3.1 spec of the Tilopay API, source of truth for endpoints, parameters and responses.
- [openapi.yaml](https://tilopay.com/developers/openapi.yaml): Same spec, in YAML.
- [mcp.json](https://tilopay.com/developers/mcp.json): Catalog of the tools of the Tilopay MCP server, with parameters, outputs and access level.
- [api-bancario/openapi.json](https://tilopay.com/developers/api-bancario/openapi.json): OpenAPI 3.0.3 spec of the Tilopay Banking API (BaaS), version 1.0.0, a separate artifact from the acquiring API.
- [api-bancario/openapi.yaml](https://tilopay.com/developers/api-bancario/openapi.yaml): Same spec, in YAML.
- [skills/index.md](https://tilopay.com/en/developers/skills/index.md)
- [cierre-de-caja/SKILL.md](https://tilopay.com/developers/skills/cierre-de-caja/SKILL.md)
- [cobrar-por-whatsapp/SKILL.md](https://tilopay.com/developers/skills/cobrar-por-whatsapp/SKILL.md)
- [rechazos-y-recuperacion/SKILL.md](https://tilopay.com/developers/skills/rechazos-y-recuperacion/SKILL.md)
- [conciliacion-mensual/SKILL.md](https://tilopay.com/developers/skills/conciliacion-mensual/SKILL.md)
- [cfo-de-bolsillo/SKILL.md](https://tilopay.com/developers/skills/cfo-de-bolsillo/SKILL.md)
- [catalogo-y-cobros-fijos/SKILL.md](https://tilopay.com/developers/skills/catalogo-y-cobros-fijos/SKILL.md)
---
# Tilopay for developers
> The four integration paths, the field contract, the SDK reference, the API and webhooks.
- kind: guide
- status: stable
- last_verified: 2026-08-29
- url: https://tilopay.com/en/developers
Step 0: there are no shared sandbox credentials. Every developer registers and receives their own at https://tilopay.com/en/developers/registro
## Four integration paths
- **No code** — extensions and plugins for existing platforms: /en/developers/sin-codigo
- **Hosted payment page** — your server requests a URL from the API and redirects the customer to a Tilopay page: /en/developers/hosted-payment-page
- **JavaScript SDK** — the card fields live in your page and the SDK sends them straight to Tilopay; it accepts cards, SINPE Móvil and Apple Pay: /en/developers/sdk
- **Server-to-server API** — restricted to PCI-certified merchants; the URL is provisioned per merchant: /en/developers/server-to-server
## Reference
- OpenAPI 3.1 spec: /developers/openapi.json
- Acquiring API: /en/developers/api/autenticacion
- Webhooks: /en/developers/api/webhooks
- Form fields: /en/developers/sdk/campos-del-formulario
- Apple Pay with the SDK: /en/developers/sdk/apple-pay
- Banking API (restricted access): /en/developers/api-bancario
- Banking API OpenAPI 3.0.3 spec: /developers/api-bancario/openapi.json
---
# Developer registration
> How to get sandbox credentials to test Tilopay integrations.
- kind: guide
- status: stable
- last_verified: 2026-08-29
- url: https://tilopay.com/en/developers/registro
There are no shared or public sandbox credentials: every developer registers and receives their own. This is the step before any of the four integration paths.
## How to get them
1. Complete the developer registration at https://tilopay.com/en/developers/registro
2. Tilopay enables a test account and issues that merchant's credentials.
3. With those credentials you obtain the API token (/en/developers/api/autenticacion) or the SDK token.
## Test and production
There is no separate sandbox host: test mode is switched from the merchant account. See /en/developers/entornos
---
# No-code integration
> No-code integration: plugins and connectors for Shopify, WooCommerce, Wix, VTEX and hotel PMS.
- kind: guide
- status: stable
- last_verified: 2026-08-29
- url: https://tilopay.com/en/developers/sin-codigo
This is the lowest-friction path: the merchant installs the plugin or connector for their platform and configures Tilopay as a payment method from that platform's admin. No code is written and card data never passes through the merchant.
## Platforms with a plugin or connector
The directory lists 83 platforms, each linking to its setup guide when one exists.
### E-commerce
- **Shopify** — La única integración nativa en Centroamérica certificada por Shopify desde 2022. Activa Tilopay en tu tienda, recibe tarjetas de cualquier banco y expande tus ventas por la región sin límites. (https://tilopay.com/plataformas/shopify)
- **Wix** — Integra el plug-in nativo más confiable de Centroamérica y el Caribe a tu página en Wix. Acepta tarjetas Mastercard, Visa y American Express sin complicaciones. (https://tilopay.com/plataformas/wix)
- **WooCommerce** — Integra el plug-in certificado de Tilopay por WooCommerce en tu página web. Acepta tarjetas Mastercard, Visa y American Express sin complicaciones. (https://tilopay.com/plataformas/woocommerce)
- **VTEX** — Acepta tarjetas Mastercard, Visa y American Express sin complicaciones en tu tienda online VTEX de Centroamérica y el Caribe. (https://tilopay.com/plataformas/vtex)
- **Avify** — La integración de Tilopay a Avify para cobrar con tarjeta por WhatsApp para Centroamérica y el Caribe. (https://tilopay.com/plataformas/avify)
- **Take.App** — Vende por WhatsApp con tu catálogo en línea de Take.App y cobra con tarjetas Mastercard, Visa y American Express mediante Tilopay.
- **Blume** — Acepta tarjetas Mastercard, Visa y American Express sin complicaciones en tu tienda online Blume de Centroamérica y el Caribe.
- **BigCommerce** — Acepta tarjetas Mastercard, Visa y American Express sin complicaciones en tu tienda online en BigCommerce de Centroamérica y el Caribe.
- **Adobe Commerce / Magento** — Extensión oficial de Tilopay para Adobe Commerce y Magento Open Source 2.4. Cobra con tarjeta dentro de tu propio checkout, con 3DS, cuotas Tasa 0, SINPE Móvil, Yappy y Apple Pay. (https://tilopay.com/plataformas/adobe-commerce-cloud)
- **Ecwid** — Acepta tarjetas Mastercard, Visa y American Express sin complicaciones en tu tienda online Ecwid de Centroamérica y el Caribe.
### Lodging and PMS
- **Cloudbeds** — Centraliza la gestión de tu hotel y acepta pagos de todo el mundo con tarjetas Mastercard, Visa y American Express de forma fluida a través de Cloudbeds. (https://tilopay.com/plataformas/cloudbeds)
- **Bookinglayer** — Acepta tarjetas Mastercard, Visa y American Express de todo el mundo, sin complicaciones a través de Bookinglayer. (https://tilopay.com/plataformas/bookinglayer)
- **Orbe Booking** — Acepta tarjetas Mastercard, Visa y American Express de todo el mundo en tus reservas, sin complicaciones utilizando el motor de reservas en línea Orbe. (https://tilopay.com/plataformas/orbe-booking)
- **Mangobeds** — Impulsa las reservas directas de tu alojamiento y acepta las principales tarjetas del mundo sin complicaciones utilizando el motor de Mangobeds.
- **ChargeAutomation** — Acepta tarjetas Mastercard, Visa y American Express de todo el mundo, sin complicaciones a través de ChargeAutomation. (https://tilopay.com/plataformas/chargeautomation)
- **ThinkReservations** — Aumenta tus reservas, simplifica operaciones y construye un negocio más rentable con nuestra integración en ThinkReservations.
- **SimpleBooking** — Acepta tarjetas Mastercard, Visa y American Express de todo el mundo en tus reservas, sin complicaciones utilizando el motor de reservas en línea SimpleBooking.
- **Avantio** — Acepta tarjetas Mastercard, Visa y American Express sin complicaciones en tu negocio en Avantio de Centroamérica y el Caribe.
- **Opera** — Optimiza la operación de tu hotel y procesa los pagos de tus huéspedes con tarjetas Mastercard, Visa y American Express de forma segura a través de Opera.
- **Booking Automation** — Integración disponible a través de ChargeAutomation.
- **Smoobu** — Integración disponible a través de ChargeAutomation.
- **Clock** — Integración disponible a través de ChargeAutomation.
- **Beds24** — Integración disponible a través de ChargeAutomation.
- **Guesty** — Integración disponible a través de ChargeAutomation.
- **Tokeet** — Integración disponible a través de ChargeAutomation.
- **Hostaway** — Integración disponible a través de ChargeAutomation.
- **Hostfully** — Integración disponible a través de ChargeAutomation.
- **OwnerRez** — Integración disponible a través de ChargeAutomation.
- **Hospitable** — Integración disponible a través de ChargeAutomation.
- **Godo** — Integración disponible a través de ChargeAutomation.
- **Hosthub (Syncbnb)** — Integración disponible a través de ChargeAutomation.
- **Hostify** — Integración disponible a través de ChargeAutomation.
- **Uplisting** — Integración disponible a través de ChargeAutomation.
- **Lodgify** — Integración disponible a través de ChargeAutomation.
- **BookingSync** — Integración disponible a través de ChargeAutomation.
- **myVR** — Integración disponible a través de ChargeAutomation.
- **Protel** — Integración disponible a través de ChargeAutomation.
- **AbodeBooking** — Integración disponible a través de ChargeAutomation.
- **Brillantez Solutions** — Integración disponible a través de ChargeAutomation.
- **GuestCentrix** — Integración disponible a través de ChargeAutomation.
- **Easyrez** — Integración disponible a través de ChargeAutomation.
- **eZee Absolute** — Integración disponible a través de ChargeAutomation.
- **eZee FrontDesk** — Integración disponible a través de ChargeAutomation.
- **FNSROOMS** — Integración disponible a través de ChargeAutomation.
- **Front2Go** — Integración disponible a través de ChargeAutomation.
- **Hotellinking** — Integración disponible a través de ChargeAutomation.
- **Hoteliga** — Integración disponible a través de ChargeAutomation.
- **Hoteltime Solutions** — Integración disponible a través de ChargeAutomation.
- **InnKey** — Integración disponible a través de ChargeAutomation.
- **Little Hotelier** — Integración disponible a través de ChargeAutomation.
- **Mews** — Integración disponible a través de ChargeAutomation.
- **MisterBooking** — Integración disponible a través de ChargeAutomation.
- **NewBook** — Integración disponible a través de ChargeAutomation.
- **Occupancy Plus** — Integración disponible a través de ChargeAutomation.
- **Preno** — Integración disponible a través de ChargeAutomation.
- **Resort Data Processing** — Integración disponible a través de ChargeAutomation.
- **Roomraccoon** — Integración disponible a través de ChargeAutomation.
- **Room Ranger** — Integración disponible a través de ChargeAutomation.
- **Shalom** — Integración disponible a través de ChargeAutomation.
- **Sirvoy** — Integración disponible a través de ChargeAutomation.
- **Ulyses Cloud** — Integración disponible a través de ChargeAutomation.
- **VHP** — Integración disponible a través de ChargeAutomation.
- **Winhms** — Integración disponible a través de ChargeAutomation.
- **W2** — Integración disponible a través de ChargeAutomation.
- **Zavia ERP** — Integración disponible a través de ChargeAutomation.
- **3RPMSa** — Integración disponible a través de ChargeAutomation.
- **Autoclerk** — Integración disponible a través de ChargeAutomation.
- **Hansaworld** — Integración disponible a través de ChargeAutomation.
- **Hotel Link Solutions** — Integración disponible a través de ChargeAutomation.
- **Ibelsa** — Integración disponible a través de ChargeAutomation.
- **Revenue Control Data** — Integración disponible a través de ChargeAutomation.
- **Roomer** — Integración disponible a través de ChargeAutomation.
- **Servo IT Solutions** — Integración disponible a través de ChargeAutomation.
- **Softmogul** — Integración disponible a través de ChargeAutomation.
- **Suitech** — Integración disponible a través de ChargeAutomation.
- **Thais Soft** — Integración disponible a través de ChargeAutomation.
- **TK Technology** — Integración disponible a través de ChargeAutomation.
- **Sympl** — Integración disponible a través de ChargeAutomation.
- **5Stelle** — Integración disponible a través de ChargeAutomation.
- **Planyo** — Integración disponible a través de ChargeAutomation.
### Services and bookings
- **Wstudio.app** — Acepta tarjetas Mastercard, Visa y American Express de todo el mundo, sin complicaciones a través de Wstudio.app. (https://tilopay.com/plataformas/wstudio-app)
- **SimplyBook** — Facilita la agenda de tus clientes y automatiza el cobro de tus citas con tarjetas Mastercard, Visa y American Express mediante SimplyBook.
### ERP and CRM
- **Odoo ERP & CRM** — Integra el software empresarial Odoo con Tilopay para aceptar pagos en diversos métodos.
---
# API · Authentication
> How to get the API token and the SDK token, how long each lasts, and how to send them on every call.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-10-20
- url: https://tilopay.com/en/developers/api/autenticacion
The whole API and the SDK live on a single host: `https://app.tilopay.com`. There is no
separate host for testing — see [environments](/en/developers/entornos).
## The two operations [#operaciones]
| Operation | Path | What for |
|---|---|---|
| API token | `POST /api/v1/login` | Server-to-server API calls |
| SDK token | `POST /api/v1/loginSdk` | The token passed to `Tilopay.Init()` |
## Get the API token [#token-api]
```bash
curl -X POST https://app.tilopay.com/api/v1/login \
-H "Content-Type: application/json" \
-d '{ "apiuser": "YOUR_APIUSER", "password": "YOUR_PASSWORD" }'
```
### Body [#cuerpo]
The merchant API user.
The merchant API password.
### Response [#respuesta]
The token to send on subsequent calls.
Always `bearer`.
Token lifetime as an **integer in seconds** (for example `86400`). The exact value comes in
this response: do not assume it on the client.
## Get the SDK token [#token-sdk]
```bash
curl -X POST https://app.tilopay.com/api/v1/loginSdk \
-H "Content-Type: application/json" \
-d '{ "apiuser": "YOUR_APIUSER", "password": "YOUR_PASSWORD", "key": "YOUR_API_KEY" }'
```
The resulting token is the one passed to the `token` parameter of
[`Tilopay.Init()`](/en/developers/sdk/reference/init).
## Lifetime [#vigencia]
- **API token: 24 hours.** `expires_in` arrives as an **integer in seconds** (for example
`86400`).
- **SDK token: 1 hour.** `expires_in` arrives as a **date-time string** (for example
`"2023-06-05 13:32:06"`).
The exact value always arrives in `expires_in`, in each operation's format. Cache it
server-side and renew on expiry.
## How it is sent [#envio]
```http
Authorization: bearer
```
## Revocation and limits [#revocacion]
- **Tokens cannot be revoked.** If a token leaks there is no operation to invalidate it:
treat the leak as an incident and rotate credentials with Tilopay.
- **There is no limit** on concurrent tokens per merchant. You can request one per process
without invalidating the previous ones.
## Where credentials come from [#credenciales]
`apiuser`, `password` and `key` are obtained in the merchant panel, at
[Admin panel · Platform integrations](https://admin.tilopay.com/platform-integrations).
If you do not have access yet, start with [developer registration](/en/developers/registro).
> **Warning:** Never put `apiuser` or `password` in the browser. The login runs on your server; only the
> SDK token reaches the browser.
---
# Hosted payment page
> The integration path where the customer pays on a page hosted by Tilopay and your server receives the result.
- kind: guide
- status: stable
- api_version: v1
- last_verified: 2026-08-28
- url: https://tilopay.com/en/developers/hosted-payment-page
## What it is [#que-es]
Your server requests a payment URL from the API, redirects the customer to that Tilopay page
and receives the result on your callback URL.
Card data is typed on a Tilopay page: **you never see a card number** and your
merchant server stays out of that flow.
The API operation for this path lives in [API · processPayment](/en/developers/api/hosted-payment-page/process-payment).
## Difference from a payment link [#diferencia-link]
- **Hosted payment page**: your server requests a payment URL via API and redirects the customer to it. Best for integrated checkout flows in your site or app.
- **Payment link**: a reusable URL created via API or the dashboard and shared by message, email, social media or QR. The customer pays when convenient; no redirect from your flow is needed.
- In short: HPP for integrated, one-time checkout; payment links for shared, low-front-end charges.
## Who it is for [#para-quien]
For teams that take payments with their own code but prefer not to build or maintain the card
form. What you need is backend work: request the URL and handle the callback.
## What you need before starting [#requisitos]
1. **Your own credentials.** There are no shared sandbox credentials: every developer gets
theirs through [developer registration](/en/developers/registro).
2. **API authentication.** See [authentication](/en/developers/api/autenticacion).
3. **A callback URL of yours** that can receive the transaction result.
## How to confirm the state of a charge [#confirmacion]
The result arriving on your callback is not the only signal available, and not every error
response travels with an HTTP 4xx:
- Read [how to read an error response](/en/developers/api/procesos-operativos/errors) before declaring success.
- Configure [webhooks](/en/developers/api/webhooks) for the events you care about.
- If a call fails without a clear response, resolve the state with
[safe retries](/en/developers/reintentos-seguros).
## Environments [#entornos]
Testing and production share the same host. See
[environments](/en/developers/entornos) before taking real money.
## Compliance [#cumplimiento]
Together with the no-code path, this is the one that exposes your infrastructure the least.
Confirm the applicable scope with your compliance team.
## If you prefer the form on your own site [#alternativa]
Use the [JavaScript SDK](/en/developers/sdk): the design is yours and the data still does not
pass through your server.
---
# Environments: testing and production
> Testing and production share one host. The mode is switched from the account and verified with the environment field returned by Init().
- kind: concept
- status: stable
- api_version: v1
- last_verified: 2026-10-21
- url: https://tilopay.com/en/developers/entornos
> **Warning:** There is no sandbox host. Testing and production use the same host:
> `app.tilopay.com`. The URL does not tell you which mode you are in.
## How the mode is switched [#como-se-cambia]
The mode is switched **from the account in the Tilopay portal**, not from the integration.
There is no parameter, header or alternate URL that changes it from code.
## How to verify it [#como-se-verifica]
`Tilopay.Init()` returns an **`environment`** field:
| Value | Meaning |
|---|---|
| `"PROD"` | Production |
| `"TEST"` | Testing |
That is the only signal available at runtime. Read it and surface it in your own checkout
while developing.
## The real risk [#riesgo]
> **Warning:** Because the host is the same, an integrator can believe they are testing while actually
> being in production, taking real money. Verify that `environment` is `"TEST"` before assuming
> you are testing; make an unexpected `"PROD"` fail loudly in development.
## Test cards [#tarjetas]
In testing mode you charge with the [test cards](/en/developers/tarjetas-de-prueba): each
one lists the number, brand, expected result and whether it opens the 3DS challenge screen.
---
# Test cards
> The 27 cards of the Tilopay testing environment, with the expected result and the 3DS friction of each one.
- kind: guide
- status: stable
- api_version: v1
- last_verified: 2026-10-21
- url: https://tilopay.com/en/developers/tarjetas-de-prueba
These cards only work when the account is in **testing mode**. The mode is switched from the
account and verified with the `environment` field returned by `Init()` (`"TEST"` in testing): see
[environments and testing](/en/developers/entornos).
## How to use them [#uso]
| Field | What to enter |
| --- | --- |
| Expiry date | Any date in the future |
| CVV | Any value |
| Code on the 3DS challenge screen | `3ds2` |
> **Warning:** On the 3DS challenge screen the code to enter is `3ds2`. There is no other code and nothing is
> sent over SMS in testing.
## Cards [#tarjetas]
The brand comes from the prefix: `4` Visa, `51`–`55` Mastercard, `34` American Express.
| Number | Brand | Expected result | Friction |
| --- | --- | --- | --- |
| `4111111111111111` | Visa | Approved | No friction |
| `4012000000020089` | Visa | Approved | No friction |
| `4012000000020006` | Visa | Approved | No friction |
| `4012010000020088` | Visa | Approved | No friction |
| `5100270000000072` | Mastercard | Approved | No friction |
| `5100270000000031` | Mastercard | Approved | No friction |
| `341111000000009` | American Express | Approved | No friction |
| `341111000000011` | American Express | Approved | No friction |
| `341112000000001` | American Express | Approved | No friction |
| `341111000000037` | American Express | Approved | No friction |
| `341112000008012` | American Express | Approved | No friction |
| `4012000000020071` | Visa | Approved | 3DS challenge |
| `4012010000020070` | Visa | Approved | 3DS challenge |
| `4012010000020005` | Visa | Approved | 3DS challenge |
| `5100270000000023` | Mastercard | Approved | 3DS challenge |
| `5100271000000120` | Mastercard | Approved | 3DS challenge |
| `4112613451591116` | Visa | Insufficient funds | 3DS challenge |
| `4523080346468525` | Visa | Incorrect CVV | No friction |
| `4549179990476733` | Visa | Restricted card | No friction |
| `4012000000020121` | Visa | Declined | No friction |
| `4111111111119999` | Visa | Declined | No friction |
| `4111111111110000` | Visa | Declined | No friction |
| `5100270000000056` | Mastercard | Declined | No friction |
| `5111111111113333` | Mastercard | Declined | No friction |
| `4666666666662222` | Visa | Declined | No friction |
| `5555666666662222` | Mastercard | Declined | No friction |
| `5100270000000098` | Mastercard | Declined | 3DS challenge |
Cards with **3DS challenge** friction open the authentication screen; **No friction** cards
resolve without it. The expected result is always the same: the card determines the response, not
the amount.
---
# Safe retries and orderNumber
> The acquiring API is not idempotent. Exactly what to do when a payment call dies on a timeout.
- kind: concept
- status: stable
- api_version: v1
- last_verified: 2026-10-20
- url: https://tilopay.com/en/developers/reintentos-seguros
> **Warning:** The Tilopay acquiring API is not idempotent. There is no idempotency key and no retry that returns the
> original transaction. If you come from other processors, this is the assumption to dismantle
> before writing code.
## `orderNumber` is unique forever [#ordernumber]
`orderNumber` is unique per merchant **across their entire operation**, forever. It does not
reset daily, monthly or seasonally.
If it repeats, **the new transaction is rejected** with the response **"Transacción
duplicada"** (duplicate transaction). It does not return the original transaction: it returns a
rejection.
## The timeout problem [#timeout]
When a payment call dies on a network error or timeout, you do not know whether the transaction
was created. And neither intuitive way out works:
| What you would do | What happens |
|---|---|
| Retry with the same `orderNumber` | Duplicate rejection, even if the first one went through |
| Retry with a new `orderNumber` | Risk of double charge |
**On a network timeout there is no safe retry.**
## What to do instead [#que-hacer]
Query the state before deciding:
1. Call `POST /api/v1/consult` with the original `orderNumber`.
2. If the transaction exists, use its result. Do not retry.
3. If it does not exist, then you can retry — and you can reuse the same `orderNumber`, because
it was not consumed.
```text
payment → timeout
│
└─→ consult(original orderNumber)
├─ exists → use that result
└─ not found → retry
```
## Design consequences [#diseno]
- Generate the `orderNumber` in your system **before** calling the payment and persist it. If you
generate it on the fly, after a timeout you have nothing to query with.
- Never derive the `orderNumber` from something that can repeat (recycled cart number, truncated
timestamp, resettable counter).
- A "Transacción duplicada" does not mean the charge failed: it means that `orderNumber` was
already used. Query before showing the customer an error.
---
# API · How to read an error response
> An HTTP 200 does not mean success. Where the issuer decline arrives and how to write error handling.
- kind: concept
- status: stable
- api_version: v1
- last_verified: 2026-10-22
- url: https://tilopay.com/en/developers/api/procesos-operativos/errors
## The issuer decline [#rechazo]
When the issuer declines a transaction, the response carries two fields:
The issuer decline code.
The decline text.
## An HTTP 200 does not mean success [#estado-http]
> **Warning:** There is no defined standard for when the API responds HTTP 4xx and when it responds HTTP 200
> with the error in the body. Both forms coexist, and there are five different error envelopes
> depending on the endpoint.
>
> Practical consequence: your error handling must always look at the body, not only the status
> code, and tolerate more than one body shape.
## Error body shapes [#formas-del-cuerpo]
`processModification` error (`type` 300 or 400):
```json
{"type":"400","message":"Order number: TYP974_172 does not exist"}
```
Five different envelopes, depending on the endpoint:
| Envelope | Endpoints |
|---|---|
| `{"error": "Unauthorized"}` | `login`, `loginSdk` |
| `{"type", "message"}` | `processPayment`, `processModification` |
| `{"type", "result"}` | `processRecurrentPayment`, `processTokenize` |
| `{"code", "description", "error"}` | server to server |
| `{"code", "description"}` | issuer decline |
## How to write error handling [#como-manejar]
- Treat `code` and `description` as data to log and display, not as an enumeration to branch on.
- Do not write `if (status === 200) success`. Check the body.
- Store the raw response of every decline: it is what lets you reconstruct your merchant's
decline pattern.
- To determine the real state of a transaction after a failure, use
[safe retries](/en/developers/reintentos-seguros).
---
# API · Four integration paths
> The four ways to take payments with Tilopay, and the difference that decides which one fits you: where the card data travels.
- kind: concept
- status: stable
- api_version: v1
- last_verified: 2026-10-20
- url: https://tilopay.com/en/developers/api/caminos-de-integracion
## Four paths [#cuatro-caminos]
There are four ways to take payments with Tilopay. They differ in two things: how much you
build yourself, and where the card fields appear. Pick one and follow its guide; all of them
start with your sandbox credentials, requested at [developer registration](/en/developers/registro).
### 1 · No code [#sin-codigo]
Extensions and plugins for existing platforms. You do not write a line of code.
[See path](/en/developers/sin-codigo)
### 2 · Hosted payment page [#hosted-payment-page]
Your server requests a URL from the API, redirects the customer to that Tilopay page and
receives the result on your callback URL.
[See path](/en/developers/hosted-payment-page)
### 3 · JavaScript SDK [#sdk-javascript]
The card fields live in your page; the SDK captures them and sends them straight to Tilopay.
[See path](/en/developers/sdk)
### 4 · Server-to-server API [#servidor-a-servidor]
Restricted access: a service exclusive to PCI-certified merchants. The URL is provisioned per
merchant and is not public.
[Requirements and request](/en/developers/server-to-server)
## How to choose [#como-elegir]
Choosing the wrong path is expensive. The difference that matters most is where the card data
travels.
| Path | Who builds the form | Where card data travels | What you need to know | Compliance implication |
| --- | --- | --- | --- | --- |
| 1 · No code | The platform | Never pass through your systems | Setup inside the platform admin | Check with your compliance team |
| 2 · Hosted payment page | Tilopay | Your customer types them on a secure Tilopay page; you never see a card number | Backend: request the URL and handle the callback | Check with your compliance team |
| 3 · JavaScript SDK | Your site | Typed on your page but sent from the browser straight to Tilopay; they do not pass through your server | JavaScript frontend, plus backend for credentials | Check with your compliance team |
| 4 · Server-to-server (restricted access) | Your site | Card data passes through your server | Requires your PCI certification and a URL provisioned by Tilopay | Check with your compliance team |
> **Warning:** Path 4 is not self-serve: it is exclusive to merchants holding PCI certification, and the URL
> is provisioned individually. It is also the only path that puts your server inside PCI DSS
> scope. Paths 2 and 3 avoid that cost and you can start them today.
## After you choose [#despues-de-elegir]
With the path picked, continue with [response conventions](/en/developers/api/convenciones) to
learn how amounts are typed, and [how to read an error response](/en/developers/api/procesos-operativos/errors)
before you put the code into production.
[Saved card payments reference](/en/developers/api/cobros-tarjetas-guardadas).
---
# API · Response conventions
> How amounts are typed, where a JSON payload hides inside a string and why the same entity changes shape between fetching one and listing many.
- kind: concept
- status: stable
- api_version: v1
- last_verified: 2026-10-20
- url: https://tilopay.com/en/developers/api/convenciones
The acquiring API responses have several details that you cannot infer by reading each
operation on its own, and that break typed integrations. They live here because they apply
to several operations at once.
For error handling, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
## Amounts come as strings, not numbers [#montos-cadena]
> **Warning:** Amounts, discounts and totals are serialized as strings: `"discount": "40.00"`,
> `"amount": "0.00"`, `"first_amount": "0.00"`, `"amount_max_daily": "1000.00"`.
Any typed deserialization that declares those fields as numbers fails. Declare them as
strings and convert them yourself, with your language's decimal type, not with floating
point.
It shows up, among others, in [get a coupon](/en/developers/api/recurrentes/cupones/get-coupon),
[list coupons](/en/developers/api/recurrentes/cupones/get-coupons),
[list plans](/en/developers/api/recurrentes/planes/get-plans) and
[subscriber payments](/en/developers/api/recurrentes/suscriptores/suscriptor-payments).
## There is a JSON payload inside a string [#doble-encoding]
In [subscriber payments](/en/developers/api/recurrentes/suscriptores/suscriptor-payments), the
`data` field of each payment **is not an object: it is a string containing JSON**.
```json
"data": "{\"first\":1,\"expire\":\"2024-12-28T19:05:29.572648Z\",\"amount\":0,\"activeAmount\":0,\"originalAmount\":0,\"key\":\"XXXX-XXXX-XXXX-XXXX-XXXX\"}"
```
You have to deserialize twice: first the response, then the contents of `data`. Treat that
second deserialization the way you treat any external input: wrap it and log the raw string
when it does not parse.
## The same entity changes shape between "get one" and "list" [#uno-vs-lista]
This is not a documentation slip: the two operations return different shapes of the same
coupon, and each needs its own mapping.
| | [`getCoupon`](/en/developers/api/recurrentes/cupones/get-coupon) (one) | [`getRepeatCoupons`](/en/developers/api/recurrentes/cupones/get-coupons) (list) |
| --- | --- | --- |
| Creation date | `created_at`, ISO format | `create`, `Y-m-d H:i:s` format |
| Other fields | includes `recurrent_id`, `updated_at` and `deleted_at` | does not include them |
The same happens in
[subscriber payments](/en/developers/api/recurrentes/suscriptores/suscriptor-payments), which
also uses `create` with the `Y-m-d H:i:s` format.
## Two ways of saying "not configured" [#no-configurado]
In [list plans](/en/developers/api/recurrentes/planes/get-plans), a plan's webhook fields come
as an empty string when they are not configured, while `return_url` comes as `null`. Those
are two representations of the same state in the same object: when checking whether a
webhook is configured, treat the empty string and `null` as the same case.
## `status` and `type` may be numbers or strings [#status-type]
In acquiring API responses, `status` and `type` may be numbers or strings. For example, [create payments](/en/developers/api/cobros-tarjetas-guardadas/set-payments) returns `"status": 200` in the success example and `"status": "400"` in the error example; [create a group](/en/developers/api/cobros-tarjetas-guardadas/set-group) returns `"type": "200"`. Accept both types when reading these indicators; do not assume a single type across all operations.
---
# API · Get API token
> API login operation: returns the bearer token that signs every other call.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-10-20
- url: https://tilopay.com/en/developers/api/autenticacion/token-api
```http
POST /api/v1/login
```
## What it does [#que-hace]
Returns the security token needed to consume the API services. The API user and password come from [Admin panel · Platform integrations](https://admin.tilopay.com/platform-integrations).
## Authentication [#autenticacion]
It does not require a token: this is the operation that issues it. See [authentication](/en/developers/api/autenticacion).
## Parameters [#parametros]
Merchant API user, obtained in Admin panel · Platform integrations.
Merchant API password, obtained in Admin panel · Platform integrations.
## Request example [#request]
The `<...>` values are placeholders: replace them with your own credentials and data.
```json
{
"apiuser": "",
"password": ""
}
```
## Response [#respuesta]
```json
{
"access_token": "",
"token_type": "bearer",
"expires_in": 86400
}
```
## Error responses [#respuestas-de-error]
Invalid credentials → HTTP 401:
```json
{
"error": "Unauthorized"
}
```
To interpret a response that is not a success, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
---
# API · processPayment
> Parameters, request example and response of processPayment, the operation that opens the payment form.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-10-20
- url: https://tilopay.com/en/developers/api/hosted-payment-page/process-payment
```http
POST /api/v1/processPayment
```
## What it does [#que-hace]
Returns the URL of the payment form for a purchase.
## Authentication [#autenticacion]
Requires the API bearer token in the `Authorization` header — see [authentication](/en/developers/api/autenticacion).
## Parameters [#parametros]
Site where you wait for the transaction response, for example `mywebsite.com`. It must support the **GET** method. Example response to the redirect: `mywebsite.com?code=1&description=Transaction%20is%20approved.&auth=123456&order=TPYS-881WROIBQA1405468&tpt=4300&crd=&tilopay-transaction=4300&OrderHash=b02927cb...&returnData=Tilopay-dataReturn123456789&form_update=ok`. When `code = 1` the transaction is approved; anything else is declined. `OrderHash` is a unique string per transaction: its algorithm is not public and is requested by writing to `soporte@tilopay.com`.
Key associated with the customer. Obtained in Admin panel · Platform integrations.
Purchase amount.
Purchase currency in ISO format, for example USD, CRC, GTQ.
Order number, it can be alphanumeric.
Capture and authorize: 1 yes, 0 no.
First name.
Last names.
Address.
Address 2.
City.
State in ISO format, for example CR-SJ (San José, Costa Rica) or US-CA (California, USA).
Post code.
Country in ISO Alpha-2 code, for example CR (Costa Rica), US (USA) or GT (Guatemala).
Telephone.
Buyer email.
First name.
Last names.
Address.
Address 2.
City.
State in ISO format, for example CR-SJ (San José, Costa Rica) or US-CA (California, USA).
Post code.
Country in ISO Alpha-2 code, for example CR (Costa Rica), US (USA) or GT (Guatemala).
Telephone.
1 to force the customer to save the card in Tilopay, 0 not to.
Name of the platform where the transaction is generated.
Value that Tilopay returns in the final response. Sending a base 64 string is recommended.
Only used when implementing hash verification. Possible values [V1, V2]; V1 by default.
Send as value "v2".
## Request example [#request]
The `<...>` values are placeholders: replace them with your own credentials and data.
```json
{
"redirect": "https://www.urlToRedirect.com",
"key": "",
"amount": "1.00",
"currency": "USD",
"orderNumber": "1212122",
"capture": "1",
"billToFirstName": "DEMO",
"billToLastName": "DEMO",
"billToAddress": "San Jose",
"billToAddress2": "Catedral",
"billToCity": "JS",
"billToState": "SJ",
"billToZipPostCode": "10061",
"billToCountry": "CR",
"billToTelephone": "88888888",
"billToEmail": "cliente@ejemplo.com",
"shipToFirstName": "DEMO",
"shipToLastName": "DEMO",
"shipToAddress": "San Jose",
"shipToAddress2": "Catedral",
"shipToCity": "JS",
"shipToState": "SJ",
"shipToZipPostCode": "10061",
"shipToCountry": "CR",
"shipToTelephone": "88888888",
"subscription": "0",
"platform": "api",
"returnData": "dXNlcl9pZD0xMg==",
"hashVersion": "V2",
"token_version": "v2"
}
```
## Response [#respuesta]
```json
{
"type": "100",
"html": "Use url redirect",
"url": "https://secure.tilopay.com/htmls/1212122_574572148file.html"
}
```
`"type": "100"` means the form URL was generated: redirect the customer to `url` so they can
complete the payment.
## Parameters that arrive at the redirect [#parametros-del-redirect]
When the customer finishes the payment, Tilopay redirects them to your `redirect` with these
parameters in the URL:
| Parameter | What it is |
|---|---|
| `code` | `1` = transaction approved; any other value = declined |
| `description` | Result text |
| `auth` | Authorization code |
| `order` | The `orderNumber` you sent |
| `tpt` and `tilopay-transaction` | Transaction id in Tilopay |
| `OrderHash` | Unique hash of the transaction |
| `returnData` | The value you sent in the request |
Before delivering the product or releasing the service, confirm the transaction status with
`POST /api/v1/consult` from your server — see [consult](/en/developers/api/procesos-operativos/consult).
## Error responses [#respuestas-de-error]
HTTP 300:
```json
{
"type": "300",
"message": "Message error"
}
```
HTTP 400:
```json
{
"type": "400",
"message": "Message error"
}
```
HTTP 402:
```json
{
"type": "402",
"message": "Message error"
}
```
HTTP 403:
```json
{
"type": "403",
"message": "Message error"
}
```
To interpret a response that is not a success, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
---
# API · Server-to-server
> A service exclusive to PCI-certified merchants. The URL is provisioned per merchant: it is not self-serve.
- kind: guide
- status: stable
- api_version: v1
- last_verified: 2026-10-20
- url: https://tilopay.com/en/developers/server-to-server
> **Warning:** Restricted access. This is not a self-serve path. You cannot start this integration on your own
> today: it requires merchant PCI certification and a URL provisioned individually by Tilopay.
## What it is [#que-es]
The path where card data passes through your server, which then sends it to the Tilopay
API.
## Who it is for [#para-quien]
- It is a **service exclusive to merchants holding PCI certification**.
- The **URL is customized per merchant**, with its own key. **It is not a public URL.**
That is why the examples on this page carry no real URL: the `Host` and the proxy key are delivered
to each approved merchant.
## Requirements [#requisitos]
1. Valid PCI certification for your company.
2. An active Tilopay account.
3. An approved request, with the URL and key provisioned by Tilopay for your merchant.
## How to request it [#solicitud]
Write to `soporte@tilopay.com` with your business name and the status of your PCI certification. The URL
and key are delivered directly to the approved merchant.
## Request reference [#referencia]
> **Warning:** The `Host` and the `tx-proxy-key` header are delivered by Tilopay to each approved merchant. There is
> no public URL: the examples use placeholders.
```http
POST / HTTP/1.1
Host: url provided by tilopay
```
### Headers [#encabezados]
`bearer {API token}` — see [authentication](/en/developers/api/autenticacion).
Transaction proxy key, provided by Tilopay.
### Parameters [#parametros]
Key tied to the merchant (required).
Card number (required).
Security code (required).
Expiration date in monthYear format, for example `1023` (required).
Cardholder first name (required).
Cardholder last name (required).
Customer phone (required).
Customer email (required).
Customer address (required).
Customer city (required).
State in ISO format, for example `CR-SJ` (San José, Costa Rica) or `US-CA` (California, USA) (required).
Postal code (required).
Country as ISO Alpha-2 code, for example `CR`, `US`, `GT` (required).
Purchase amount (required).
Currency in ISO format, for example `USD`, `CRC`, `GTQ` (required).
Order number (required).
`1` captures and authorizes, `0` only authorizes (required).
Response URL (required).
Optional shipping data: `shipToFirstName`, `shipToLastName`, `shipToAddress`,
`shipToAddress2`, `shipToCity`, `shipToState`, `shipToZipPostCode`, `shipToCountry`,
`shipToTelephone`.
### Request [#peticion]
```json
{
"key": "key",
"card": "card PAN",
"cvv": "CVV Number",
"expire": "1023",
"name": "firstname",
"lastname": "lastname",
"phone": "88888888",
"email": "email@user.com",
"address": "user address",
"city": "city",
"state": "state",
"zipcode": "zipcode",
"country": "country",
"shipToFirstName": "Nombre",
"shipToLastName": "Apellido",
"shipToAddress": "San Jose",
"shipToAddress2": "Escazu",
"shipToCity": "San Jose",
"shipToState": "SJ",
"shipToZipPostCode": "10101",
"shipToCountry": "CR",
"shipToTelephone": "88778877",
"amount": "amount",
"currency": "currency code",
"orderNumber": "Order Number",
"capture": 1,
"redirect": "url to redirect"
}
```
The collection includes two examples, **with 3DS** and **without 3DS**, sharing the same request body.
### Response [#respuesta]
Without 3DS:
```json
{
"code": "1",
"description": "Transaccion aprobada",
"auth": "123456",
"orderNumber": "12345",
"urlRedirect": "",
"error": ""
}
```
With 3DS:
```json
{
"code": "",
"description": "",
"auth": "",
"orderNumber": "12457",
"urlRedirect": "https://secure.tilopay.com/htmls/1026345966.html",
"error": ""
}
```
When the transaction requires 3DS authentication, the response carries the URL in `urlRedirect`; that
is where the cardholder is sent. To interpret `code`, `description` and `error`, see
[response conventions](/en/developers/api/convenciones) and
[how to read an error response](/en/developers/api/procesos-operativos/errors).
## Alternatives without PCI certification [#alternativas]
If you do not hold PCI certification, these paths avoid that scope entirely:
- [Hosted payment page](/en/developers/hosted-payment-page) — Tilopay hosts the form.
- [JavaScript SDK](/en/developers/sdk) — the form lives on your page, but the data travels from the
browser straight to Tilopay.
- [No code](/en/developers/sin-codigo) — a plugin or an already-integrated platform.
---
# API · Payment links
> Payment links operations of the Tilopay API, with parameters and examples.
- kind: api-index
- status: stable
- api_version: v1
- last_verified: 2026-08-29
- url: https://tilopay.com/en/developers/api/links-de-pago
## Operations [#operaciones]
- [Create payment link](/en/developers/api/links-de-pago/create-link-payment)
- [Payment link detail](/en/developers/api/links-de-pago/detail-link-payment)
- [Delete a payment link](/en/developers/api/links-de-pago/delete-link-payment)
- [List payment links](/en/developers/api/links-de-pago/payment-item-list)
- [Get a payment link by id](/en/developers/api/links-de-pago/payment-by-id)
Every operation lives on `https://app.tilopay.com` and, except for the login operations, requires the API token — see [authentication](/en/developers/api/autenticacion).
---
# API · Create payment link
> Payment link creation through the API, with response callback and webhook.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-08-29
- url: https://tilopay.com/en/developers/api/links-de-pago/create-link-payment
```http
POST /api/v1/createLinkPayment
```
## What it does [#que-hace]
Creates a payment link with amount, currency and usage behaviour.
## Authentication [#autenticacion]
Requires the API bearer token in the `Authorization` header — see [authentication](/en/developers/api/autenticacion).
## Parameters [#parametros]
Tilopay integration key.
Amount of the payment link.
Currency code in ISO 4217 format.
Reference of the payment link.
Link type: 0 unlimited, 1 single use.
Payment description.
Customer name. It only applies when `type` is 1.
Optional field. URL, over **GET**, the customer is redirected to with the response once the payment is completed. Example of the data sent: `code=Val&description=Val&auth=Val&tilopayLinkId=Val&orderNumber=Val&tilopayOrderId=Val&creditCardToken=Val&creditCardBrand=Val&last4CreditCardNumber=Val&orderHash=Val`
Optional field. URL to send the response webhook to once the payment is completed.
It must accept the **POST** method to receive the data. Example of the data sent:
```json
{
"code": "1",
"codeDescription": "Aprobada",
"auth": "123456",
"tilopayLinkId": 54421,
"orderNumber": "TPT123",
"tilopayOrderId": 12233,
"creditCardToken": "41111******11111",
"creditCardBrand": "Visa",
"last4CreditCardNumber": "1111",
"linkDescription": "Descripcion del link de pago",
"orderHash": ""
}
```
## Request example [#request]
The `<...>` values are placeholders: replace them with your own credentials and data.
```json
{
"key": "",
"amount": "10",
"currency": "USD",
"reference": "123456",
"type": 0,
"description": "Description",
"client": "Client name",
"callback_url": "",
"webhook_url": ""
}
```
## Response [#respuesta]
```json
{
"type": "200",
"message": "Success",
"url": "https://app.tilopay.com/link/MjMwMjQ=",
"id": 1
}
```
To interpret a response that is not a success, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
---
# API · Payment link detail
> Detail of a payment link and its payments, queried by id.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-08-29
- url: https://tilopay.com/en/developers/api/links-de-pago/detail-link-payment
```http
GET /api/v1/getDetailLinkPayment/{link_payment_id}/{api_key}
```
## What it does [#que-hace]
Returns the detail of a payment link and its associated payments. It takes no body: the data travels in the path.
## Authentication [#autenticacion]
Requires the API bearer token in the `Authorization` header — see [authentication](/en/developers/api/autenticacion).
## Parameters [#parametros]
Path parameters, in the order they appear in the URL:
Id of the payment link to query.
Merchant api key.
## Response [#respuesta]
```json
{
"type": "200",
"message": "Success",
"detail": {
"id": 6201,
"amount": "45.00",
"currency": "USD",
"reference": "Producto de prueba 1 TP-Shop",
"client": "NA",
"type": "Unlimited",
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
"callback_url": null,
"create": "2022-10-24 08:45:14"
},
"payments": []
}
```
To interpret a response that is not a success, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
---
# API · Delete a payment link
> Deletion of a payment link by id.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-08-29
- url: https://tilopay.com/en/developers/api/links-de-pago/delete-link-payment
```http
POST /api/v1/deleteLinkPayment
```
## What it does [#que-hace]
Deletes an existing payment link.
## Authentication [#autenticacion]
Requires the API bearer token in the `Authorization` header — see [authentication](/en/developers/api/autenticacion).
## Parameters [#parametros]
Tilopay integration key.
Payment link id.
## Request example [#request]
The `<...>` values are placeholders: replace them with your own credentials and data.
```json
{
"key": "",
"id": "35"
}
```
## Response [#respuesta]
```json
{
"type": "200",
"status": 1,
"message": "Success"
}
```
To interpret a response that is not a success, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
---
# API · List payment links
> Paginated listing of the merchant's payment links.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-08-29
- url: https://tilopay.com/en/developers/api/links-de-pago/payment-item-list
```http
GET /api/v1/getLinkPaymentList/{api_key}/{limit}
```
## What it does [#que-hace]
Returns the paginated list of the merchant's payment links. It takes no body: the data travels in the path.
## Authentication [#autenticacion]
Requires the API bearer token in the `Authorization` header — see [authentication](/en/developers/api/autenticacion).
## Parameters [#parametros]
Path parameters, in the order they appear in the URL:
Merchant api key.
Number of records per page.
## Response [#respuesta]
```json
{
"type": "200",
"message": "Success",
"data": {
"current_page": 1,
"first_page_url": "http://app.tilopay.com/api/v1/getLinkPaymentList//10?page=1",
"from": 1,
"last_page": 2,
"last_page_url": "http://app.tilopay.com/api/v1/getLinkPaymentList//10?page=2",
"next_page_url": "http://app.tilopay.com/api/v1/getLinkPaymentList//10?page=2",
"path": "http://app.tilopay.com/api/v1/getLinkPaymentList//10",
"per_page": 10,
"prev_page_url": null,
"to": 10,
"total": 16,
"payment_link": [
{
"id": 1,
"amount": "45.00",
"currency": "USD",
"reference": "Producto de prueba 1 TP-Shop",
"url": "https://admin.tilopay.com/link/3dNjE2MA3sdd==",
"callback_url": null,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
"times_used": null,
"picture": "https://storage.googleapis.com/tilo-uploads/items/51087219_.png",
"create": "2022-10-24 08:45:14"
},
{
"id": 2,
"amount": "35.00",
"currency": "USD",
"reference": "Producto de prueba 2",
"url": "https://admin.tilopay.com/link/dwNjE2see3MA==",
"callback_url": null,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
"times_used": null,
"picture": "https://storage.googleapis.com/tilo-uploads/items/64156766_.png",
"create": "2022-10-24 08:45:14"
},
{
"id": 3,
"amount": "45.00",
"currency": "USD",
"reference": "Producto de prueba 3",
"url": "https://admin.tilopay.com/link/f4NjE2MwsdA==",
"callback_url": null,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
"times_used": null,
"picture": "https://storage.googleapis.com/tilo-uploads/items/88435879_.png",
"create": "2022-10-24 08:45:14"
},
{
"id": 4,
"amount": "45.00",
"currency": "USD",
"reference": "test",
"url": "https://admin.tilopay.com/link/ceNjE2sxw2MA==",
"callback_url": null,
"description": "ddd",
"times_used": null,
"picture": "https://storage.googleapis.com/tilo-uploads/items/37716065_.png",
"create": "2022-10-24 08:45:14"
},
{
"id": 5,
"amount": "45.00",
"currency": "USD",
"reference": "test",
"url": "https://admin.tilopay.com/link/cweNjE2Mfd5A==",
"callback_url": null,
"description": "ddd",
"times_used": null,
"picture": "https://storage.googleapis.com/tilo-uploads/items/37716065_.png",
"create": "2022-10-24 08:45:14"
},
{
"id": 6,
"amount": "45.00",
"currency": "USD",
"reference": "test",
"url": "https://admin.tilopay.com/link/ce3NjE2fg5eMA==",
"callback_url": null,
"description": "ddd",
"times_used": null,
"picture": "https://storage.googleapis.com/tilo-uploads/items/37716065_.png",
"create": "2022-10-24 08:45:14"
},
{
"id": 7,
"amount": "45.00",
"currency": "USD",
"reference": "test",
"url": "https://admin.tilopay.com/link/dsNjE2MAd32==",
"callback_url": null,
"description": "ddd",
"times_used": null,
"picture": "https://storage.googleapis.com/tilo-uploads/items/37716065_.png",
"create": "2022-10-24 08:45:14"
},
{
"id": 8,
"amount": "45.00",
"currency": "USD",
"reference": "test",
"url": "https://admin.tilopay.com/link/NjE2sd32MA==",
"callback_url": null,
"description": "ddd",
"times_used": null,
"picture": "https://storage.googleapis.com/tilo-uploads/items/37716065_.png",
"create": "2022-10-24 08:45:14"
},
{
"id": 9,
"amount": "45.00",
"currency": "USD",
"reference": "test",
"url": "https://admin.tilopay.com/link/sd3NjE2MA==",
"callback_url": null,
"description": "ddd",
"times_used": null,
"picture": "https://storage.googleapis.com/tilo-uploads/items/37716065_.png",
"create": "2022-10-24 08:45:14"
},
{
"id": 10,
"amount": "45.00",
"currency": "USD",
"reference": "test",
"url": "https://admin.tilopay.com/link/d3dNjE2MA==",
"callback_url": null,
"description": "ddd",
"times_used": null,
"picture": "https://storage.googleapis.com/tilo-uploads/items/37716065_.png",
"create": "2022-10-24 08:45:14"
}
]
}
}
```
To interpret a response that is not a success, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
---
# API · Get a payment link by id
> Query of a single payment link by its id.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-08-29
- url: https://tilopay.com/en/developers/api/links-de-pago/payment-by-id
```http
GET /api/v1/getLinkPaymentById/{link_payment_id}/{api_key}
```
## What it does [#que-hace]
Returns a single payment link. It takes no body: the data travels in the path.
## Authentication [#autenticacion]
Requires the API bearer token in the `Authorization` header — see [authentication](/en/developers/api/autenticacion).
## Parameters [#parametros]
Path parameters, in the order they appear in the URL:
Id of the payment link to query.
Merchant api key.
## Response [#respuesta]
```json
{
"type": "200",
"message": "Success",
"data": {
"id": 1,
"amount": "45.00",
"currency": "USD",
"reference": "Producto de prueba 1 TP-Shop",
"url": "https://admin.tilopay.com/link/loNj8E2MA==",
"callback_url": null,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
"times_used": null,
"picture": "https://storage.googleapis.com/tilo-uploads/items/51087219_.png",
"create": "2022-10-24 08:45:14",
"payments": []
}
}
```
To interpret a response that is not a success, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
---
# API · Recurring charges
> Recurring charges operations of the Tilopay API, with parameters and examples.
- kind: api-index
- status: stable
- api_version: v1
- last_verified: 2026-08-29
- url: https://tilopay.com/en/developers/api/recurrentes
## Operations [#operaciones]
16 operations in three subgroups:
- [Plans](/en/developers/api/recurrentes/planes) — 5
- [Subscribers](/en/developers/api/recurrentes/suscriptores) — 7
- [Coupons](/en/developers/api/recurrentes/cupones) — 4
Every operation lives on `https://app.tilopay.com` and, except for the login operations, requires the API token — see [authentication](/en/developers/api/autenticacion).
---
# API · Recurring · Plans
> Recurring · Plans operations of the Tilopay API, with parameters and examples.
- kind: api-index
- status: stable
- api_version: v1
- last_verified: 2026-08-29
- url: https://tilopay.com/en/developers/api/recurrentes/planes
## Operations [#operaciones]
- [Create recurring plan](/en/developers/api/recurrentes/planes/create-plan)
- [Edit recurring plan](/en/developers/api/recurrentes/planes/edit-plan)
- [Get a recurring plan](/en/developers/api/recurrentes/planes/get-plan)
- [List recurring plans](/en/developers/api/recurrentes/planes/get-plans)
- [Delete recurring plan](/en/developers/api/recurrentes/planes/delete-plan)
Every operation lives on `https://app.tilopay.com` and, except for the login operations, requires the API token — see [authentication](/en/developers/api/autenticacion).
---
# API · Create recurring plan
> Recurring plan creation: frequencies, free trial, modalities and webhooks.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-10-22
- url: https://tilopay.com/en/developers/api/recurrentes/planes/create-plan
```http
POST /api/v1/createPlanRepeat
```
## What it does [#que-hace]
Creates a subscription plan: charge frequency, currency, trial period, modalities and webhooks.
## Authentication [#autenticacion]
Requires the API bearer token in the `Authorization` header — see [authentication](/en/developers/api/autenticacion).
## Parameters [#parametros]
Tilopay integration key.
Recurring plan title.
Plan description.
Charge frequency.
| Code | Value |
| --- | --- |
| 1 | Daily |
| 2 | Weekly |
| 3 | Monthly |
| 4 | Yearly |
| 5 | Fortnightly |
| 6 | Every two months |
| 7 | Quarterly |
| 8 | Every four months |
| 9 | Every six months |
Currency code in ISO 4217 format.
Initial payment amount.
Enables the free trial period: 0 no, 1 yes.
Days of the free trial period.
Number of retries for failed charges.
Array of plan modalities.
Optional field. The merchant's own thank-you URL; it must support the **GET** method.
Optional field. Webhook URL, over **POST**, that receives the callback in the request body when a customer successfully takes out a subscription. Example of the data sent: `{'id_plan' : 1, 'email' : 'email@email.com', 'modality' : 'ModalityName', 'amount' : 25, 'frequency' : '', 'coupon' : '5HT5W8YT', 'free_trial' : 1, 'next_payment_date' : '2023-02-25'}`
Optional field. Webhook URL, over **POST**, that receives the callback in the request body when the customer is charged successfully. Example of the data sent: `{'id_plan' : 1, 'email' : 'email@email.com', 'amount' : 25, 'auth' : '123456', 'orderNumber' : 'PRE123456'}`
Optional field. Webhook URL, over **POST**, that receives the callback in the request body when a payment fails. Example of the data sent: `{'id_plan' : 1, 'email' : 'email@email.com', 'amount' : 25}`
Optional field. Webhook URL, over **POST**, that receives the callback in the request body when a customer cancels the subscription to one of their plans. Example of the data sent: `{'id_plan' : 1, 'email' : 'email@email.com', 'expire' : '2023-02-25'}`
Optional field. Webhook URL, over **POST**, that receives the callback in the request body when a customer reactivates the subscription to one of their plans. Example of the data sent: `{'id_plan' : 1, 'email' : 'email@email.com', 'next_payment_date' : '2023-02-25'}`
End date of the recurring plan, `d-m-Y` format (for example 25-09-2022). When the plan has no end date, send it empty.
Set to 1 it adds the `notify_detail` and `notify_note` text to the notification email. Set to 0 it adds neither.
Detail text in Spanish. Optional when `notify` is 0.
Detail text in English. Optional when `notify` is 0.
Notes text in Spanish. Optional when `notify` is 0.
Notes text in English. Optional when `notify` is 0.
## Request example [#request]
The `<...>` values are placeholders: replace them with your own credentials and data.
```json
{
"key": "",
"title": "Plan title",
"description": "Plan description",
"frecuency": 1,
"currency": "USD",
"first_amount": 0,
"trial": 0,
"trial_days": 0,
"attempts": 1,
"modality": [
{
"title": "Basic",
"amount": 10
},
{
"title": "Premium",
"amount": 30
}
],
"thanks_url": "",
"webhook_subscribe": "",
"webhook_payment": "",
"webhook_rejected": "",
"webhook_unsubscribe": "",
"webhook_reactive": "",
"end_at": "25-10-2023",
"notify": 0,
"notify_detail_es": "",
"notify_detail_en": "",
"notify_note_es": "",
"notify_note_en": ""
}
```
## Response [#respuesta]
Plan URL on `https://tp.cr` or `https://app.tilopay.com`.
```json
{
"type": "200",
"status": 1,
"message": "Success",
"id": 624,
"url": "https://app.tilopay.com/link/TmpJMHwx"
}
```
To interpret a response that is not a success, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
---
# API · Edit recurring plan
> Editing a recurring plan and its status.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-10-22
- url: https://tilopay.com/en/developers/api/recurrentes/planes/edit-plan
```http
POST /api/v1/editPlanRepeat
```
## What it does [#que-hace]
Edits an existing plan, including its status.
## Authentication [#autenticacion]
Requires the API bearer token in the `Authorization` header — see [authentication](/en/developers/api/autenticacion).
## Parameters [#parametros]
Tilopay integration key.
Recurring plan id.
Recurring plan title.
Plan description.
Charge frequency.
| Code | Value |
| --- | --- |
| 1 | Daily |
| 2 | Weekly |
| 3 | Monthly |
| 4 | Yearly |
| 5 | Fortnightly |
| 6 | Every two months |
| 7 | Quarterly |
| 8 | Every four months |
| 9 | Every six months |
Currency code in ISO 4217 format.
Initial payment amount.
Enables the free trial period: 0 no, 1 yes.
Days of the free trial period.
Number of retries for failed charges.
Status of the recurring plan.
| Code | Value |
| --- | --- |
| 0 | Inactive |
| 1 | Active |
| 2 | Active but with no new sign-ups |
Optional field. The merchant's own thank-you URL; it must support the **GET** method.
Optional field. Webhook URL, over **POST**, that receives the callback in the request body when a customer successfully takes out a subscription. Example of the data sent: `{'id_plan' : 1, 'email' : 'email@email.com', 'modality' : 'ModalityName', 'amount' : 25, 'frequency' : '', 'coupon' : '5HT5W8YT', 'free_trial' : 1, 'next_payment_date' : '2023-02-25'}`
Optional field. Webhook URL, over **POST**, that receives the callback in the request body when the customer is charged successfully. Example of the data sent: `{'id_plan' : 1, 'email' : 'email@email.com', 'amount' : 25, 'auth' : '123456', 'orderNumber' : 'PRE123456'}`
Optional field. Webhook URL, over **POST**, that receives the callback in the request body when a payment fails. Example of the data sent: `{'id_plan' : 1, 'email' : 'email@email.com', 'amount' : 25}`
Optional field. Webhook URL, over **POST**, that receives the callback in the request body when a customer cancels the subscription to one of their plans. Example of the data sent: `{'id_plan' : 1, 'email' : 'email@email.com', 'expire' : '2023-02-25'}`
Optional field. Webhook URL, over **POST**, that receives the callback in the request body when a customer reactivates the subscription to one of their plans. Example of the data sent: `{'id_plan' : 1, 'email' : 'email@email.com', 'next_payment_date' : '2023-02-25'}`
End date of the recurring plan, `d-m-Y` format (for example 25-09-2022). When the plan has no end date, send it empty.
## Request example [#request]
The `<...>` values are placeholders: replace them with your own credentials and data.
```json
{
"key": "",
"id": 3,
"title": "Plan title",
"description": "Plan description",
"frecuency": 2,
"currency": "USD",
"first_amount": 0,
"trial": 0,
"trial_days": 0,
"attempts": 5,
"status": 1,
"thanks_url": "",
"webhook_subscribe": "",
"webhook_payment": "",
"webhook_rejected": "",
"webhook_unsubscribe": "",
"webhook_reactive": "",
"end_at": "25-10-2023"
}
```
## Response [#respuesta]
Plan URL on `https://tp.cr` or `https://app.tilopay.com`.
```json
{
"type": "200",
"status": 1,
"message": "Success",
"url": "https://app.tilopay.com/link/"
}
```
To interpret a response that is not a success, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
---
# API · Get a recurring plan
> Query of a recurring plan by id.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-08-29
- url: https://tilopay.com/en/developers/api/recurrentes/planes/get-plan
```http
POST /api/v1/getPlanRepeat
```
## What it does [#que-hace]
Returns a single recurring plan.
## Authentication [#autenticacion]
Requires the API bearer token in the `Authorization` header — see [authentication](/en/developers/api/autenticacion).
## Parameters [#parametros]
Tilopay integration key.
Recurring plan id.
## Request example [#request]
The `<...>` values are placeholders: replace them with your own credentials and data.
```json
{
"key": "",
"id": "3"
}
```
## Response [#respuesta]
```json
{
"type": "200",
"message": "Success",
"plan": {
"id": 232,
"title": "Prueba repeat",
"description": "Plan repeat de prueba mensual",
"frequency": 3,
"currency": "USD",
"first_amount": "5.00",
"trial": 0,
"trial_days": 0,
"attempts": 5,
"thanks_url": null,
"webhook_subscribe": null,
"webhook_payment": null,
"webhook_rejected": null,
"webhook_unsubscribe": null,
"webhook_reactive": null,
"modality": [
{
"id": 292,
"title": "Pago mensual prueba repeat modalidad",
"amount": "10.00"
}
],
"end_at": null
}
}
```
To interpret a response that is not a success, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
---
# API · List recurring plans
> Listing of the integration's recurring plans.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-10-20
- url: https://tilopay.com/en/developers/api/recurrentes/planes/get-plans
```http
POST /api/v1/getPlansRepeat
```
## What it does [#que-hace]
Returns the merchant's recurring plans.
## Authentication [#autenticacion]
Requires the API bearer token in the `Authorization` header — see [authentication](/en/developers/api/autenticacion).
## Parameters [#parametros]
Tilopay integration key.
## Request example [#request]
The `<...>` values are placeholders: replace them with your own credentials and data.
```json
{
"key": ""
}
```
## Response [#respuesta]
```json
{
"type": "200",
"message": "Success",
"data": [
{
"id": 276,
"title": "Plan test 1",
"description": "Plan",
"frequency": 1,
"currency": "USD",
"first_amount": "0.00",
"trial": 0,
"trial_days": 0,
"attempts": 1,
"status": 1,
"thanks_url": "",
"return_url": null,
"webhook_subscribe": "",
"webhook_payment": "",
"webhook_rejected": "",
"webhook_unsubscribe": "",
"webhook_reactive": "",
"modality": [
{
"id": 131,
"title": "Basic",
"amount": "10.00"
}
],
"end_at": "2022-10-25"
}
]
}
```
To interpret a response that is not a success, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
---
# API · Delete recurring plan
> Deletion of a recurring plan by id.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-08-29
- url: https://tilopay.com/en/developers/api/recurrentes/planes/delete-plan
```http
POST /api/v1/deletePlanRepeat
```
## What it does [#que-hace]
Deletes a recurring plan.
## Authentication [#autenticacion]
Requires the API bearer token in the `Authorization` header — see [authentication](/en/developers/api/autenticacion).
## Parameters [#parametros]
Tilopay integration key.
Recurring plan id.
## Request example [#request]
The `<...>` values are placeholders: replace them with your own credentials and data.
```json
{
"key": "",
"id": "625"
}
```
## Response [#respuesta]
```json
{
"type": "200",
"status": 1,
"message": "Success"
}
```
To interpret a response that is not a success, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
---
# API · Recurring · Subscribers
> Recurring · Subscribers operations of the Tilopay API, with parameters and examples.
- kind: api-index
- status: stable
- api_version: v1
- last_verified: 2026-08-29
- url: https://tilopay.com/en/developers/api/recurrentes/suscriptores
## Operations [#operaciones]
- [Subscribers of a plan](/en/developers/api/recurrentes/suscriptores/get-suscriptor-plan)
- [Edit subscriber](/en/developers/api/recurrentes/suscriptores/edit-suscriptor-plan)
- [Pause subscriber](/en/developers/api/recurrentes/suscriptores/pause-suscriptor-plan)
- [Reactivate subscriber](/en/developers/api/recurrentes/suscriptores/reactive-suscriptor-plan)
- [Delete subscriber](/en/developers/api/recurrentes/suscriptores/delete-suscriptor-plan)
- [Registration and renewal URL](/en/developers/api/recurrentes/suscriptores/consult-url)
- [Subscriber payments](/en/developers/api/recurrentes/suscriptores/suscriptor-payments)
Every operation lives on `https://app.tilopay.com` and, except for the login operations, requires the API token — see [authentication](/en/developers/api/autenticacion).
---
# API · Subscribers of a plan
> Query of the subscribers of a recurring plan.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-08-29
- url: https://tilopay.com/en/developers/api/recurrentes/suscriptores/get-suscriptor-plan
```http
POST /api/v1/getSuscriptorRepeat
```
## What it does [#que-hace]
Returns the subscribers associated with a recurring plan.
## Authentication [#autenticacion]
Requires the API bearer token in the `Authorization` header — see [authentication](/en/developers/api/autenticacion).
## Parameters [#parametros]
Tilopay integration key.
Recurring plan id.
## Request example [#request]
The `<...>` values are placeholders: replace them with your own credentials and data.
```json
{
"key": "",
"id": "2"
}
```
## Response [#respuesta]
```json
{
"type": "200",
"message": "Success",
"suscriptor": [
{
"id": 360,
"name": "Jhon 1",
"lastname": "D",
"email": "customer1@example.com",
"modality": "Pago mensual prueba repeat modalidad",
"amount": "10.00",
"expire": "2023-03-26",
"coupon": "",
"status": "Delete",
"create": "2022-10-19 12:48:59"
},
{
"id": 33364,
"name": "Jhon 2",
"lastname": "D",
"email": "customer2@example.com",
"modality": "Pago mensual prueba repeat modalidad",
"amount": "10.00",
"expire": "2023-08-05",
"coupon": "",
"status": "Active",
"create": "2023-06-05 14:24:18"
}
]
}
```
To interpret a response that is not a success, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
---
# API · Edit subscriber
> Editing the status and expiration of a subscriber.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-10-20
- url: https://tilopay.com/en/developers/api/recurrentes/suscriptores/edit-suscriptor-plan
```http
POST /api/v1/editSuscriptorRepeat
```
## What it does [#que-hace]
Changes the status or the expiration date of a subscriber.
## Authentication [#autenticacion]
Requires the API bearer token in the `Authorization` header — see [authentication](/en/developers/api/autenticacion).
## Parameters [#parametros]
Tilopay integration key.
Subscriber id.
Status of the subscriber.
| Code | Value |
| --- | --- |
| 1 | Active |
| 3 | Paused |
| 4 | Deleted |
Plan expiration date, `Y-m-d` format (for example 2023-10-25).
## Request example [#request]
The `<...>` values are placeholders: replace them with your own credentials and data.
```json
{
"key": "",
"id": "2",
"status": "3",
"expire": "2023-10-25"
}
```
## Response [#respuesta]
```json
{
"type": "200",
"status": 1,
"message": "Success"
}
```
To interpret a response that is not a success, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
---
# API · Pause subscriber
> Pausing a subscriber's subscription.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-08-29
- url: https://tilopay.com/en/developers/api/recurrentes/suscriptores/pause-suscriptor-plan
```http
POST /api/v1/pauseSuscriptorRepeat
```
## What it does [#que-hace]
Pauses a subscriber's subscription.
## Authentication [#autenticacion]
Requires the API bearer token in the `Authorization` header — see [authentication](/en/developers/api/autenticacion).
## Parameters [#parametros]
Tilopay integration key.
Subscriber id.
## Request example [#request]
The `<...>` values are placeholders: replace them with your own credentials and data.
```json
{
"key": "",
"id_suscriptor": "1"
}
```
## Response [#respuesta]
```json
{
"type": "200",
"status": 1,
"message": "Success"
}
```
To interpret a response that is not a success, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
---
# API · Reactivate subscriber
> Reactivation of a subscriber's subscription.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-08-29
- url: https://tilopay.com/en/developers/api/recurrentes/suscriptores/reactive-suscriptor-plan
```http
POST /api/v1/reactiveSuscriptorRepeat
```
## What it does [#que-hace]
Reactivates a paused subscriber's subscription.
## Authentication [#autenticacion]
Requires the API bearer token in the `Authorization` header — see [authentication](/en/developers/api/autenticacion).
## Parameters [#parametros]
Tilopay integration key.
Subscriber id.
## Request example [#request]
The `<...>` values are placeholders: replace them with your own credentials and data.
```json
{
"key": "",
"id_suscriptor": "1"
}
```
## Response [#respuesta]
```json
{
"type": "200",
"status": 1,
"message": "Success"
}
```
To interpret a response that is not a success, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
---
# API · Delete subscriber
> Deletion of a subscriber from a recurring plan.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-08-29
- url: https://tilopay.com/en/developers/api/recurrentes/suscriptores/delete-suscriptor-plan
```http
POST /api/v1/deleteSuscriptorRepeat
```
## What it does [#que-hace]
Deletes a subscriber from a recurring plan.
## Authentication [#autenticacion]
Requires the API bearer token in the `Authorization` header — see [authentication](/en/developers/api/autenticacion).
## Parameters [#parametros]
Tilopay integration key.
Subscriber id.
## Request example [#request]
The `<...>` values are placeholders: replace them with your own credentials and data.
```json
{
"key": "",
"id_suscriptor": "1"
}
```
## Response [#respuesta]
```json
{
"type": "200",
"status": 1,
"message": "Success"
}
```
To interpret a response that is not a success, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
---
# API · Registration and renewal URL
> Registration or renewal URL of a recurring plan for a given email.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-08-29
- url: https://tilopay.com/en/developers/api/recurrentes/suscriptores/consult-url
```http
POST /api/v1/recurrentUrl
```
## What it does [#que-hace]
Returns the registration URL of a recurring plan for a new user, or the renewal URL when the email is already registered.
## Authentication [#autenticacion]
Requires the API bearer token in the `Authorization` header — see [authentication](/en/developers/api/autenticacion).
## Parameters [#parametros]
Tilopay integration key.
Recurring plan id.
Email of the user the registration link is created for.
## Request example [#request]
The `<...>` values are placeholders: replace them with your own credentials and data.
```json
{
"key": "",
"id": "1",
"email": "email@user.com"
}
```
## Response [#respuesta]
```json
{
"type": "200",
"message": "",
"url_register": "https://app.tilopay.com/admin/recurrent/register/MjMy?email=email@user.com",
"url_renew": ""
}
```
To interpret a response that is not a success, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
---
# API · Subscriber payments
> Payment history of the subscribers of a recurring plan.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-10-20
- url: https://tilopay.com/en/developers/api/recurrentes/suscriptores/suscriptor-payments
```http
POST /api/v1/getSuscriptorPayments
```
## What it does [#que-hace]
Returns the payments of the subscribers of a recurring plan.
## Authentication [#autenticacion]
Requires the API bearer token in the `Authorization` header — see [authentication](/en/developers/api/autenticacion).
## Parameters [#parametros]
Tilopay integration key.
Recurring plan id.
## Request example [#request]
The `<...>` values are placeholders: replace them with your own credentials and data.
```json
{
"key": "",
"id": "1"
}
```
## Response [#respuesta]
```json
{
"type": "200",
"message": "Success",
"data": [
{
"id": 150,
"commerce_id": 37,
"suscriptor_id": 86,
"reference": "0",
"currency": "USD",
"amount": "0.00",
"status": 0,
"data": "{\"first\":1,\"expire\":\"2024-12-28T19:05:29.572648Z\",\"amount\":0,\"activeAmount\":0,\"originalAmount\":0,\"key\":\"XXXX-XXXX-XXXX-XXXX-XXXX\"}",
"create": "2024-12-13 13:05:06"
}
]
}
```
To interpret a response that is not a success, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
---
# API · Recurring · Coupons
> Recurring · Coupons operations of the Tilopay API, with parameters and examples.
- kind: api-index
- status: stable
- api_version: v1
- last_verified: 2026-08-29
- url: https://tilopay.com/en/developers/api/recurrentes/cupones
## Operations [#operaciones]
- [Create coupon](/en/developers/api/recurrentes/cupones/create-coupon)
- [List coupons of a plan](/en/developers/api/recurrentes/cupones/get-coupons)
- [Get a coupon](/en/developers/api/recurrentes/cupones/get-coupon)
- [Delete coupon](/en/developers/api/recurrentes/cupones/delete-coupon)
Every operation lives on `https://app.tilopay.com` and, except for the login operations, requires the API token — see [authentication](/en/developers/api/autenticacion).
---
# API · Create coupon
> Creation of discount coupons for recurring plans.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-10-20
- url: https://tilopay.com/en/developers/api/recurrentes/cupones/create-coupon
```http
POST /api/v1/createCoupon
```
## What it does [#que-hace]
Creates a discount coupon for a recurring plan: discount type, expiration, user and email permissions, and usage limits.
## Authentication [#autenticacion]
Requires the API bearer token in the `Authorization` header — see [authentication](/en/developers/api/autenticacion).
## Parameters [#parametros]
Tilopay integration key.
Recurring plan id.
User permission.
| Code | Value |
| --- | --- |
| 0 | Allow new users only |
| 1 | Allow already registered users |
Discount type.
| Code | Value |
| --- | --- |
| 1 | Percentage |
| 2 | Fixed amount |
Numeric value of the discount.
Coupon expiration date, `Y-m-d` format (for example 2025-10-20).
Email permission.
| Code | Value |
| --- | --- |
| 1 | Specific emails |
| 2 | Any email |
Comma-separated list of emails. Required when `email_group` is sent as 1.
Total number of uses.
Total number of valid renewals.
Total uses by the same user.
## Request example [#request]
The `<...>` values are placeholders: replace them with your own credentials and data.
```json
{
"key": "",
"planId": 10,
"active_users": 1,
"type_discount": 1,
"discount": 40,
"expire": "2025-10-20",
"email_group": 1,
"email": "cliente@ejemplo.com, cliente@ejemplo.com",
"usage": 1,
"renews": 2,
"renews_by_user": 2
}
```
## Response [#respuesta]
```json
{
"type": "200",
"status": 1,
"message": "Success",
"id": 10788,
"code": "E6RMS339"
}
```
To interpret a response that is not a success, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
---
# API · List coupons of a plan
> Listing of the coupons of a recurring plan.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-10-20
- url: https://tilopay.com/en/developers/api/recurrentes/cupones/get-coupons
```http
POST /api/v1/getRepeatCoupons
```
## What it does [#que-hace]
Returns the coupons associated with a recurring plan.
## Authentication [#autenticacion]
Requires the API bearer token in the `Authorization` header — see [authentication](/en/developers/api/autenticacion).
## Parameters [#parametros]
Tilopay integration key.
Recurring plan id.
## Request example [#request]
The `<...>` values are placeholders: replace them with your own credentials and data.
```json
{
"key": "",
"id": "1"
}
```
## Response [#respuesta]
```json
{
"type": "200",
"message": "Success",
"data": [
{
"id": 10787,
"code": "TK7DPCHY",
"active_users": 1,
"type_discount": 1,
"discount": "30.00",
"expire": "2026-06-12",
"email_group": 2,
"email": null,
"usage": 1,
"renews": 1,
"renews_by_user": 1,
"usage_counter": 0,
"create": "2026-06-12 15:17:34"
}
]
}
```
To interpret a response that is not a success, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
---
# API · Get a coupon
> Query of a recurring coupon by id.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-10-20
- url: https://tilopay.com/en/developers/api/recurrentes/cupones/get-coupon
```http
POST /api/v1/getCoupon
```
## What it does [#que-hace]
Returns a single coupon.
## Authentication [#autenticacion]
Requires the API bearer token in the `Authorization` header — see [authentication](/en/developers/api/autenticacion).
## Parameters [#parametros]
Tilopay integration key.
Coupon id.
## Request example [#request]
The `<...>` values are placeholders: replace them with your own credentials and data.
```json
{
"key": "",
"id": "1"
}
```
## Response [#respuesta]
```json
{
"type": "200",
"message": "Success",
"data": {
"id": 10788,
"recurrent_id": 10,
"code": "E6RMS339",
"active_users": 1,
"type_discount": 1,
"discount": "40.00",
"expire": "2026-10-20",
"email_group": 1,
"email": "cliente@ejemplo.com, otro@ejemplo.com",
"usage": 1,
"renews": 2,
"renews_by_user": 2,
"usage_counter": 0,
"created_at": "2026-09-02T20:12:01.000000Z",
"updated_at": "2026-09-02T20:12:01.000000Z",
"deleted_at": null
}
}
```
To interpret a response that is not a success, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
---
# API · Delete coupon
> Deletion of a recurring coupon by id.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-10-20
- url: https://tilopay.com/en/developers/api/recurrentes/cupones/delete-coupon
```http
POST /api/v1/deleteCoupon
```
## What it does [#que-hace]
Deletes a coupon.
## Authentication [#autenticacion]
Requires the API bearer token in the `Authorization` header — see [authentication](/en/developers/api/autenticacion).
## Parameters [#parametros]
Tilopay integration key.
Coupon id.
## Request example [#request]
The `<...>` values are placeholders: replace them with your own credentials and data.
```json
{
"key": "",
"id": "1"
}
```
## Response [#respuesta]
```json
{
"type": "200",
"status": 1,
"message": "Success"
}
```
To interpret a response that is not a success, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
---
# API · Credential on File (CoF)
> Credential on File (CoF) operations of the Tilopay API, with parameters and examples.
- kind: api-index
- status: stable
- api_version: v1
- last_verified: 2026-08-29
- url: https://tilopay.com/en/developers/api/cof
## Operations [#operaciones]
3 operations:
- [Tokenize card](/en/developers/api/cof/process-tokenize) — 1
- [Remove card](/en/developers/api/cof/remove-card) — 1
- [Charge](/en/developers/api/cof/realizar-cobro) — 1
Every operation lives on `https://app.tilopay.com` and, except for the login operations, requires the API token — see [authentication](/en/developers/api/autenticacion).
---
# API · processTokenize
> Card tokenization with processTokenize: parameters, request and response.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-10-22
- url: https://tilopay.com/en/developers/api/cof/process-tokenize
```http
POST /api/v1/processTokenize
```
## What it does [#que-hace]
Tokenizes a card: returns the URL of the tokenization form.
## Authentication [#autenticacion]
Requires the API bearer token in the `Authorization` header — see [authentication](/en/developers/api/autenticacion).
## Parameters [#parametros]
Site where you wait for the transaction response.
Key associated with the merchant.
Cardholder email.
Language [es, en].
Cardholder first name.
Cardholder last name.
Send as value "v2".
## Request example [#request]
The `<...>` values are placeholders: replace them with your own credentials and data.
```json
{
"redirect": "https://urlToRedirect.com",
"key": "",
"email": "email@user.com",
"language": "es",
"firstname": "name",
"lastname": "lastname",
"token_version": "v2"
}
```
## Response [#respuesta]
```json
{
"type": "100",
"url": "https://secure.tilopay.com/htmls/TOK-5063-740506121440_1648145457file.html"
}
```
## Error responses [#respuestas-de-error]
## Redirect parameters [#parametros-del-redirect]
`token`, `code`, `description`, `auth`, `crd`, `order`, `tpt`, `brand`, `last-digits`, `tilopay-transaction`, `OrderHash`, `returnData`.
The card token travels in `token` and `crd`; store it with the customer email. Use `brand` and `last-digits` to display the saved card. `crd` only has a value when the card was saved with `code = 1`.
HTTP 300:
```json
{
"type": "300",
"result": "Message error"
}
```
HTTP 402:
```json
{
"type": "402",
"result": "Message error"
}
```
To interpret a response that is not a success, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
---
# API · Remove card
> Removal of a saved card token from the merchant's private vault.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-10-20
- url: https://tilopay.com/en/developers/api/cof/remove-card
```http
POST /api/v1/user/card-remove
```
## What it does [#que-hace]
Removes a saved card token. **Requirement:** the merchant must have a private token vault.
## Authentication [#autenticacion]
Requires the API bearer token in the `Authorization` header — see [authentication](/en/developers/api/autenticacion).
## Parameters [#parametros]
Key associated with the merchant.
Customer email associated with the token.
Token to remove.
## Request example [#request]
The `<...>` values are placeholders: replace them with your own credentials and data.
```json
{
"key": "1234-1234-1234-1234-1234",
"email": "email@card.com",
"token": "411111.......1111"
}
```
## Response [#respuesta]
```json
{
"type": "200",
"status": 1,
"message": "Success"
}
```
To interpret a response that is not a success, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
---
# API · CoF · Charge
> Server-to-server charge with a v2 card token through Credential on File.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-10-20
- url: https://tilopay.com/en/developers/api/cof/realizar-cobro
```http
POST /api/v1/processRecurrentPayment
```
## What it does [#que-hace]
Processes a charge with an already tokenized card, without a form.
## Authentication [#autenticacion]
Requires the API bearer token in the `Authorization` header — see [authentication](/en/developers/api/autenticacion).
## Parameters [#parametros]
Key associated with the customer. Obtained in Admin panel · Platform integrations.
Purchase amount.
Purchase currency in ISO format, for example USD, CRC, GTQ.
Order number, it can be alphanumeric.
Capture and authorize: 1 yes, 0 no.
Cardholder email.
Card token. It must be the v2 token.
Only if you implement hash verification. Values V1 or V2; defaults to V1.
## Request example [#request]
The `<...>` values are placeholders: replace them with your own credentials and data.
```json
{
"key": "",
"amount": "10.00",
"currency": "USD",
"orderNumber": "1213",
"capture": "1",
"email": "myemail@exapmle.com",
"card": "511111_00GOB1111"
}
```
## Response [#respuesta]
```json
{
"type": "200",
"response": "1",
"description": "Transacción aprobada",
"auth": "123456",
"tpt": 734329,
"order_id": "12135",
"tilopayTransaction": 734329,
"orderHash": "f3ad85046d249bc7a781eed5285a5ded92045a2e11108063504deec72ec9b338"
}
```
## Error responses [#respuestas-de-error]
HTTP 300:
```json
{
"type": "300",
"result": "Message error"
}
```
HTTP 400:
```json
{
"type": "400",
"result": "Message error"
}
```
To interpret a response that is not a success, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
---
# API · Operational processes
> Operational processes operations of the Tilopay API, with parameters and examples.
- kind: api-index
- status: stable
- api_version: v1
- last_verified: 2026-08-29
- url: https://tilopay.com/en/developers/api/procesos-operativos
## Operations [#operaciones]
- [processModification](/en/developers/api/procesos-operativos/process-modification)
- [consult](/en/developers/api/procesos-operativos/consult)
- [consultTransactions](/en/developers/api/procesos-operativos/consult-transactions)
- [Split settlement](/en/developers/api/procesos-operativos/split)
These operations are cross-cutting: they work for any of the four [integration paths](/en/developers), no matter how the charge was originated.
To interpret a response that is not a success, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
Every operation lives on `https://app.tilopay.com` and, except for the login operations, requires the API token — see [authentication](/en/developers/api/autenticacion).
---
# API · processModification
> Capture, refund and reversal of a transaction with processModification.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-10-22
- url: https://tilopay.com/en/developers/api/procesos-operativos/process-modification
```http
POST /api/v1/processModification
```
## What it does [#que-hace]
Modifies an already processed transaction: capture, refund or reversal.
## Authentication [#autenticacion]
Requires the API bearer token in the `Authorization` header — see [authentication](/en/developers/api/autenticacion).
## Parameters [#parametros]
Number of the order sent in the original charge.
Type of modification.
| Code | Value |
| --- | --- |
| 1 | Capture |
| 2 | Refund |
| 3 | Reversal |
Amount to modify.
Key associated with the customer. Obtained in Admin panel · Platform integrations.
## Request example [#request]
The `<...>` values are placeholders: replace them with your own credentials and data.
```json
{
"orderNumber": "1214352",
"type": "2",
"amount": "1.00",
"key": ""
}
```
## Response [#respuesta-modificacion]
`type: "100"` means the modification was processed; its outcome is in `ReasonCode` and `ReasonCodeDescription`. `1101` = approved.
Approved:
```json
{"type":"100","transactionId":954183,"ReasonCode":"1101","ReasonCodeDescription":"Transaccion aprobada","OrderHash":""}
```
Rejected:
```json
{"type":"100","transactionId":954183,"ReasonCode":"3","ReasonCodeDescription":"Invalid Retrieval reference number","OrderHash":""}
```
Error (`type` 300 or 400):
```json
{"type":"400","message":"Order number: TYP974_172 does not exist"}
```
`"100"` indicates that the modification was processed.
Transaction identifier.
Result code of the modification.
Result text.
Order hash. See the note about `orderHash` in [webhooks](/en/developers/api/webhooks#verificacion).
To interpret a response that is not a success, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
---
# API · consult
> Query the status and processed amount of a single transaction.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-10-20
- url: https://tilopay.com/en/developers/api/procesos-operativos/consult
```http
POST /api/v1/consult
```
## What it does [#que-hace]
Queries a specific transaction: returns the processed amount and the status of the transaction.
## Authentication [#autenticacion]
Requires the API bearer token in the `Authorization` header — see [authentication](/en/developers/api/autenticacion).
## Parameters [#parametros]
Tilopay integration key.
Order number being queried.
Merchant id.
## Request example [#request]
The `<...>` values are placeholders: replace them with your own credentials and data.
```json
{
"key": "",
"orderNumber": "1212122",
"merchantId": ""
}
```
## Response [#respuesta]
```json
{
"type": "200",
"message": "",
"response": [
{
"id_tilopay": 734312,
"orderNumber": "1212122",
"amount": "5.00",
"currency": "USD",
"merchantId": "88803956",
"code": "1",
"response": "Transacción aprobada",
"auth": "123456",
"commission": 0.18,
"iva_commission": 0.02,
"retention_iva": 0.27,
"retention_rent": 0.09,
"cost": 0.35,
"cost_iva": 0.05,
"net_to_liquidate": "4.04",
"capture": "Capture",
"card": "4021",
"last": "5221",
"environment": "Test",
"type": "Payment",
"date": "2024-07-31 16:59:20"
}
]
}
```
To interpret a response that is not a success, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
---
# API · consultTransactions
> Bulk transaction query by date range, currency, order or email.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-08-29
- url: https://tilopay.com/en/developers/api/procesos-operativos/consult-transactions
```http
POST /api/v1/consultTransactions
```
## What it does [#que-hace]
Queries transactions by date range, with optional filters.
## Authentication [#autenticacion]
Requires the API bearer token in the `Authorization` header — see [authentication](/en/developers/api/autenticacion).
## Parameters [#parametros]
Tilopay integration key.
Start date, `Y-m-d H:i:s` format — for example "2022-01-15 00:00:00".
End date, `Y-m-d H:i:s` format — for example "2022-08-01 23:59:59".
Whether to return only approved transactions.
| Code | Value |
| --- | --- |
| 0 | Any |
| 1 | Approved only |
Environment of the transactions to return.
| Code | Value |
| --- | --- |
| 0 | Production |
| 1 | Test |
Array of currencies to return, for example ["USD", "CRC"].
Merchant id.
Order number.
Customer email.
Authorization number.
## Request example [#request]
The `<...>` values are placeholders: replace them with your own credentials and data.
```json
{
"key": "",
"startDate": "2023-06-01 00:00:00",
"endDate": "2023-06-30 23:59:59",
"onlyAproved": 1,
"environment": 1,
"currency": [
"USD",
"CRC"
],
"merchantId": "",
"orderNumber": "12135",
"email": "customer@example.com",
"auth": "123456"
}
```
## Response [#respuesta]
```json
{
"type": "200",
"message": "",
"response": [
{
"id": 734329,
"orderNumber": "12135",
"amount": "5.00",
"taxes": "0.00",
"discount": "0.00",
"discount_name": "",
"currency": "USD",
"merchantId": "",
"code": "1",
"response": "Transacción aprobada",
"auth": "123456",
"card": "4021",
"last": "5221",
"email": "customer@example.com",
"commission": 0.18,
"iva_commission": 0.02,
"retention_iva": 0.27,
"retention_rent": 0.09,
"cost": 0.35,
"cost_iva": 0.05,
"net_to_liquidate": 4.04,
"capture": "Capture",
"type": "Payment",
"environment": "Production",
"date": "2024-07-31 16:59:20"
},
{
"id": 734330,
"orderNumber": "12136",
"amount": "5.00",
"taxes": "0.00",
"discount": "0.00",
"discount_name": "",
"currency": "USD",
"merchantId": "",
"code": "1",
"response": "Transacción aprobada",
"auth": "123456",
"card": "4021",
"last": "5221",
"email": "customer@example.com",
"commission": 0.18,
"iva_commission": 0.02,
"retention_iva": 0.27,
"retention_rent": 0.09,
"cost": 0.35,
"cost_iva": 0.05,
"net_to_liquidate": 4.04,
"capture": "Capture",
"type": "Payment",
"environment": "Production",
"date": "2024-07-31 17:25:35"
}
]
}
```
To interpret a response that is not a success, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
---
# API · Split settlement
> Splitting the settlement of an order among several facilitated merchants.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-10-20
- url: https://tilopay.com/en/developers/api/procesos-operativos/split
```http
POST /api/v1/orders/liquidation/split
```
## What it does [#que-hace]
Splits the settlement of an order among several merchants. It only applies to merchants that use Tilopay as a payment facilitator, and the resulting orders are identified by the `SL|` prefix.
Rules:
- The merchants must be approved and be from the same country.
- If the split is lower than the total amount of the order, the remainder is assigned to the merchant that made the original transaction.
- It only applies to fully approved orders.
## Authentication [#autenticacion]
Requires the API bearer token in the `Authorization` header — see [authentication](/en/developers/api/autenticacion).
## Parameters [#parametros]
Id of the order approved in Tilopay.
Associative array with the `email` and `amount` keys of every merchant the settlement is divided with. Including the owner merchant is optional: when its amount is not specified the remainder of the split is assigned to it, and when it is included and there is a remainder, the remainder is added to it.
Request language.
## Request example [#request]
The `<...>` values are placeholders: replace them with your own credentials and data.
```json
{
"order_id": "1",
"commerces": [
{
"email": "commerce-1@example.com",
"amount": "7.5"
},
{
"email": "commerce-2@example.com",
"amount": "5.5"
}
],
"lang": "en"
}
```
## Response [#respuesta]
```json
{
"type": "200",
"message": "Great",
"description": "Order splitted successfully",
"response": {
"total_order_splitted": 3,
"order_id": 1,
"order_number": "PFC000069-TYP785237_313",
"order_key": "",
"order_currency": "USD",
"order_amount": "33.00",
"splitted_orders": [
{
"id": 1,
"amount": 20,
"commerce_name": "Commerce owner name",
"commerce_email": "owner@example.com"
},
{
"id": 2,
"amount": 7.5,
"commerce_name": "Commerce name",
"commerce_email": "commerce-1@example.com"
},
{
"id": 3,
"amount": 5.5,
"commerce_name": "Commerce name",
"commerce_email": "commerce-2@example.com"
}
]
}
}
```
To interpret a response that is not a success, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
---
# Saved card payments
> Saved card payments: enrollment, groups and immediate or scheduled payment batches; 10 POST operations.
- kind: api-index
- status: stable
- api_version: v1
- last_verified: 2026-10-20
- url: https://tilopay.com/en/developers/api/cobros-tarjetas-guardadas
## Flow [#flujo]
1. Create a group (optional).
2. Create an individual or group enrollment URL and share it.
3. The customer registers their card at that URL and becomes an affiliate, with daily and monthly maximum amounts.
4. Create immediate or date-scheduled charges to affiliates and/or groups.
5. Query the batches and their detail.
The acquiring API is not idempotent: repeating `set/payments` creates another charge. [Safe retries](/en/developers/reintentos-seguros).
## Authentication [#autenticacion]
All operations are POST on `https://app.tilopay.com` and require the API bearer token and the integration key (`key`) in the body.
## Operations [#operaciones]
- [List groups](/en/developers/api/cobros-tarjetas-guardadas/get-groups) — `POST /api/v1/collect/get/groups`
- [List affiliates](/en/developers/api/cobros-tarjetas-guardadas/get-affiliates) — `POST /api/v1/collect/get/affiliates`
- [List payment batches](/en/developers/api/cobros-tarjetas-guardadas/get-massive) — `POST /api/v1/collect/get/massive`
- [Get batch detail](/en/developers/api/cobros-tarjetas-guardadas/get-massive-detail) — `POST /api/v1/collect/get/massive/detail`
- [Create group](/en/developers/api/cobros-tarjetas-guardadas/set-group) — `POST /api/v1/collect/set/group`
- [Create individual enrollment URL](/en/developers/api/cobros-tarjetas-guardadas/set-url-affiliate) — `POST /api/v1/collect/set/urlaffiliate`
- [Create group enrollment URL](/en/developers/api/cobros-tarjetas-guardadas/set-url-group) — `POST /api/v1/collect/set/urlgroup`
- [Edit affiliate](/en/developers/api/cobros-tarjetas-guardadas/edit-affiliate) — `POST /api/v1/collect/edit/affiliate`
- [Edit group](/en/developers/api/cobros-tarjetas-guardadas/edit-group) — `POST /api/v1/collect/edit/group`
- [Create payments](/en/developers/api/cobros-tarjetas-guardadas/set-payments) — `POST /api/v1/collect/set/payments`
---
# API · List groups
> List groups: POST /api/v1/collect/get/groups.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-10-20
- url: https://tilopay.com/en/developers/api/cobros-tarjetas-guardadas/get-groups
```http
POST /api/v1/collect/get/groups
```
## What it does [#que-hace]
List groups.
## Authentication [#autenticacion]
Host: `https://app.tilopay.com`. Requires the API bearer token in `Authorization: Bearer ` and the integration key in the body (`key`).
[Get the API token](/en/developers/api/autenticacion/token-api).
## Parameters [#parametros]
Integration key.
## Request example [#ejemplo-request]
`` is the placeholder for your integration key.
```json
{
"key": ""
}
```
## Response [#respuesta]
groups: amount is the group default amount, as text.
`status`.
`errors`.
`groups`.
```json
{
"status": 200,
"errors": "",
"groups": [
{
"id": 1,
"name": "Grupo 1",
"currency": "USD",
"amount": "1000.00",
"created_at": "2024-05-03T23:09:03.000000Z"
},
{
"id": 5,
"name": "Colones",
"currency": "CRC",
"amount": "10.00",
"created_at": "2024-05-08T23:52:41.000000Z"
}
]
}
```
```schema
{
"type": "object",
"properties": {
"status": {
"type": "integer"
},
"errors": {
"type": "string"
},
"groups": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"currency": {
"type": "string"
},
"amount": {
"type": "string"
},
"created_at": {
"type": "string"
}
}
}
}
}
}
```
---
# API · List affiliates
> List affiliates: POST /api/v1/collect/get/affiliates.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-10-20
- url: https://tilopay.com/en/developers/api/cobros-tarjetas-guardadas/get-affiliates
```http
POST /api/v1/collect/get/affiliates
```
## What it does [#que-hace]
List affiliates.
## Authentication [#autenticacion]
Host: `https://app.tilopay.com`. Requires the API bearer token in `Authorization: Bearer ` and the integration key in the body (`key`).
[Get the API token](/en/developers/api/autenticacion/token-api).
## Parameters [#parametros]
Integration key.
Group ID; 0 = all.
## Request example [#ejemplo-request]
`` is the placeholder for your integration key.
```json
{
"key": "",
"group": 0
}
```
## Response [#respuesta]
affiliates contains affiliate data and daily/monthly limits.
`status`.
`errors`.
`affiliates`.
```json
{
"status": 200,
"errors": "",
"affiliates": [
{
"id": 2,
"name": "Juan",
"lastname": "Lopez",
"email": "cliente@ejemplo.com",
"company": "JuanSA",
"phone": "88778878",
"address": "San José, 100 m este",
"city": "San Jose",
"state": "CR-SJO",
"zipcode": "10101",
"country": "CR",
"currency": "USD",
"amount_max_daily": "1000.00",
"amount_max_month": "1250.00",
"base_amount": "10.00",
"status": 1,
"created_at": "2024-01-16T22:45:00.000000Z"
},
{
"id": 14,
"name": "Ramon",
"lastname": "Perez",
"email": "otro@ejemplo.com",
"company": null,
"phone": null,
"address": "San José",
"city": "Alajuela",
"state": "CR-A",
"zipcode": "10101",
"country": "CR",
"currency": "USD",
"amount_max_daily": "100.00",
"amount_max_month": "1000.00",
"base_amount": "0.00",
"status": 1,
"created_at": "2024-02-27T18:19:31.000000Z"
}
]
}
```
```schema
{
"type": "object",
"properties": {
"status": {
"type": "integer"
},
"errors": {
"type": "string"
},
"affiliates": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"lastname": {
"type": "string"
},
"email": {
"type": "string"
},
"company": {
"type": [
"string",
"null"
]
},
"phone": {
"type": [
"string",
"null"
]
},
"address": {
"type": "string"
},
"city": {
"type": "string"
},
"state": {
"type": "string"
},
"zipcode": {
"type": "string"
},
"country": {
"type": "string"
},
"currency": {
"type": "string"
},
"amount_max_daily": {
"type": "string"
},
"amount_max_month": {
"type": "string"
},
"base_amount": {
"type": "string"
},
"status": {
"type": "integer"
},
"created_at": {
"type": "string"
}
}
}
}
}
}
```
---
# API · List payment batches
> List payment batches: POST /api/v1/collect/get/massive.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-10-20
- url: https://tilopay.com/en/developers/api/cobros-tarjetas-guardadas/get-massive
```http
POST /api/v1/collect/get/massive
```
## What it does [#que-hace]
List payment batches.
## Authentication [#autenticacion]
Host: `https://app.tilopay.com`. Requires the API bearer token in `Authorization: Bearer ` and the integration key in the body (`key`).
[Get the API token](/en/developers/api/autenticacion/token-api).
## Parameters [#parametros]
Integration key.
## Request example [#ejemplo-request]
`` is the placeholder for your integration key.
```json
{
"key": ""
}
```
## Response [#respuesta]
Use code to query a batch detail.
`status`.
`errors`.
`massives`.
```json
{
"status": 200,
"errors": "",
"massives": [
{
"id": 1,
"code": "R3VhKzhMNU1uaGg1ZjZRVGw4UGh0dz09",
"created_at": "2024-05-15T04:36:58.000000Z"
},
{
"id": 3,
"code": "UnBSdXN0bnZSc0owVXdvU1haVisxZz09",
"created_at": "2024-05-15T04:56:59.000000Z"
}
]
}
```
```schema
{
"type": "object",
"properties": {
"status": {
"type": "integer"
},
"errors": {
"type": "string"
},
"massives": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"code": {
"type": "string"
},
"created_at": {
"type": "string"
}
}
}
}
}
}
```
---
# API · Get batch detail
> Get batch detail: POST /api/v1/collect/get/massive/detail.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-10-20
- url: https://tilopay.com/en/developers/api/cobros-tarjetas-guardadas/get-massive-detail
```http
POST /api/v1/collect/get/massive/detail
```
## What it does [#que-hace]
Get batch detail.
## Authentication [#autenticacion]
Host: `https://app.tilopay.com`. Requires the API bearer token in `Authorization: Bearer ` and the integration key in the body (`key`).
[Get the API token](/en/developers/api/autenticacion/token-api).
## Parameters [#parametros]
Integration key.
The code returned in the batch list.
## Request example [#ejemplo-request]
`` is the placeholder for your integration key.
```json
{
"key": "",
"code": "UnBSdXN0bnZSc0owVXdvU1haVisxZz09"
}
```
## Response [#respuesta]
`responseText` contains the rejection reason: `Daily amount exceeded` means the affiliate exceeded their daily maximum amount. The `Programmed` status indicates a scheduled charge that has not been processed yet.
`status`.
`errors`.
`payments`.
```json
{
"status": 200,
"errors": "",
"payments": [
{
"id": 12,
"collect_id": 2,
"currency": "CRC",
"amount": "100.00",
"reference": "0",
"auth": "",
"date_programmed": "",
"reason": "Cobro mensualidad",
"responseText": "Daily amount exceeded",
"status": "processed",
"approved_payment": "0"
},
{
"id": 20,
"collect_id": 2,
"currency": "CRC",
"amount": "100.00",
"reference": "0",
"auth": "123456",
"date_programmed": "",
"reason": "Cobro mensualidad",
"responseText": "Approved",
"status": "processed",
"approved_payment": "0"
},
{
"id": 9,
"collect_id": 2,
"currency": "CRC",
"amount": "100.00",
"reference": "",
"auth": "",
"date_programmed": "2024-05-19",
"reason": "Cobro mensualidad",
"responseText": "",
"status": "Programmed",
"approved_payment": "0"
}
]
}
```
```schema
{
"type": "object",
"properties": {
"status": {
"type": "integer"
},
"errors": {
"type": "string"
},
"payments": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"collect_id": {
"type": "integer"
},
"currency": {
"type": "string"
},
"amount": {
"type": "string"
},
"reference": {
"type": "string"
},
"auth": {
"type": "string"
},
"date_programmed": {
"type": "string"
},
"reason": {
"type": "string"
},
"responseText": {
"type": "string",
"description": "Rejection reason; Daily amount exceeded means the affiliate daily maximum was exceeded."
},
"status": {
"type": "string",
"enum": [
"processed",
"Programmed"
]
},
"approved_payment": {
"type": "string"
}
}
}
}
}
}
```
---
# API · Create group
> Create group: POST /api/v1/collect/set/group.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-10-20
- url: https://tilopay.com/en/developers/api/cobros-tarjetas-guardadas/set-group
```http
POST /api/v1/collect/set/group
```
## What it does [#que-hace]
Create group.
## Authentication [#autenticacion]
Host: `https://app.tilopay.com`. Requires the API bearer token in `Authorization: Bearer ` and the integration key in the body (`key`).
[Get the API token](/en/developers/api/autenticacion/token-api).
## Parameters [#parametros]
Integration key.
Group name.
ISO 4217 currency.
Default amount, text with 2 decimal places.
## Request example [#ejemplo-request]
`` is the placeholder for your integration key.
```json
{
"key": "",
"currency": "USD",
"amount": "100.00",
"name": "Grupo Name"
}
```
## Response [#respuesta]
type is "200". id identifies the created group.
`type`.
`errors`.
`id`.
```json
{
"type": "200",
"errors": "",
"id": 10
}
```
```schema
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "200"
},
"errors": {
"type": "string"
},
"id": {
"type": "integer"
}
}
}
```
---
# API · Create individual enrollment URL
> Create individual enrollment URL: POST /api/v1/collect/set/urlaffiliate.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-10-20
- url: https://tilopay.com/en/developers/api/cobros-tarjetas-guardadas/set-url-affiliate
```http
POST /api/v1/collect/set/urlaffiliate
```
## What it does [#que-hace]
Create individual enrollment URL.
## Authentication [#autenticacion]
Host: `https://app.tilopay.com`. Requires the API bearer token in `Authorization: Bearer ` and the integration key in the body (`key`).
[Get the API token](/en/developers/api/autenticacion/token-api).
## Parameters [#parametros]
Integration key.
Link name.
ISO 4217 currency.
Base amount.
Daily maximum amount.
Monthly maximum amount.
## Request example [#ejemplo-request]
`` is the placeholder for your integration key.
```json
{
"key": "",
"name": "Name link",
"currency": "USD",
"base_amount": "5.00",
"amount_max_daily": "10.00",
"amount_max_month": "100.00"
}
```
## Response [#respuesta]
link is the URL where the customer registers their card.
`type`.
`errors`.
`link`.
```json
{
"type": "200",
"errors": "",
"link": "https://app.tilopay.com/link/TWc9PXw0"
}
```
```schema
{
"type": "object",
"properties": {
"type": {
"type": "string"
},
"errors": {
"type": "string"
},
"link": {
"type": "string"
}
}
}
```
---
# API · Create group enrollment URL
> Create group enrollment URL: POST /api/v1/collect/set/urlgroup.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-10-20
- url: https://tilopay.com/en/developers/api/cobros-tarjetas-guardadas/set-url-group
```http
POST /api/v1/collect/set/urlgroup
```
## What it does [#que-hace]
Create group enrollment URL.
## Authentication [#autenticacion]
Host: `https://app.tilopay.com`. Requires the API bearer token in `Authorization: Bearer ` and the integration key in the body (`key`).
[Get the API token](/en/developers/api/autenticacion/token-api).
## Parameters [#parametros]
Integration key.
Link name.
ISO 4217 currency.
Base amount.
Daily maximum amount.
Monthly maximum amount.
Group ID.
## Request example [#ejemplo-request]
`` is the placeholder for your integration key.
```json
{
"key": "",
"name": "Name link",
"group": "1",
"currency": "USD",
"base_amount": "5.00",
"amount_max_daily": "10.00",
"amount_max_month": "100.00"
}
```
## Response [#respuesta]
Share link with customers enrolling in the group.
`type`.
`errors`.
`link`.
```json
{
"type": "200",
"errors": "",
"link": "https://app.tilopay.com/link/TXc9PXw0"
}
```
```schema
{
"type": "object",
"properties": {
"type": {
"type": "string"
},
"errors": {
"type": "string"
},
"link": {
"type": "string"
}
}
}
```
---
# API · Edit affiliate
> Edit affiliate: POST /api/v1/collect/edit/affiliate.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-10-20
- url: https://tilopay.com/en/developers/api/cobros-tarjetas-guardadas/edit-affiliate
```http
POST /api/v1/collect/edit/affiliate
```
## What it does [#que-hace]
Edit affiliate.
## Authentication [#autenticacion]
Host: `https://app.tilopay.com`. Requires the API bearer token in `Authorization: Bearer ` and the integration key in the body (`key`).
[Get the API token](/en/developers/api/autenticacion/token-api).
## Parameters [#parametros]
Integration key.
Affiliate ID.
name
lastname
company
phone
address
city
state
zipcode
country
base_amount
## Request example [#ejemplo-request]
`` is the placeholder for your integration key.
```json
{
"key": "",
"affiliateid": 2,
"name": "Juan",
"lastname": "Lopez",
"company": "Tilo",
"phone": "88998877",
"address": "Escazu",
"city": "San Jose",
"state": "SJO",
"zipcode": "10101",
"country": "CR",
"base_amount": "10.00"
}
```
## Response [#respuesta]
update returns success.
`type`.
`errors`.
`update`.
```json
{
"type": "200",
"errors": "",
"update": "success"
}
```
```schema
{
"type": "object",
"properties": {
"type": {
"type": "string"
},
"errors": {
"type": "string"
},
"update": {
"type": "string",
"const": "success"
}
}
}
```
---
# API · Edit group
> Edit group: POST /api/v1/collect/edit/group.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-10-20
- url: https://tilopay.com/en/developers/api/cobros-tarjetas-guardadas/edit-group
```http
POST /api/v1/collect/edit/group
```
## What it does [#que-hace]
Edit group.
## Authentication [#autenticacion]
Host: `https://app.tilopay.com`. Requires the API bearer token in `Authorization: Bearer ` and the integration key in the body (`key`).
[Get the API token](/en/developers/api/autenticacion/token-api).
## Parameters [#parametros]
Integration key.
Group ID.
Group default amount.
Group name.
## Request example [#ejemplo-request]
`` is the placeholder for your integration key.
```json
{
"key": "",
"groupid": 1,
"amount": "800.00",
"name": "Grupo Name"
}
```
## Response [#respuesta]
update returns success.
`type`.
`errors`.
`update`.
```json
{
"type": "200",
"errors": "",
"update": "success"
}
```
```schema
{
"type": "object",
"properties": {
"type": {
"type": "string"
},
"errors": {
"type": "string"
},
"update": {
"type": "string",
"const": "success"
}
}
}
```
---
# API · Create payments
> Create payments: POST /api/v1/collect/set/payments.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-10-22
- url: https://tilopay.com/en/developers/api/cobros-tarjetas-guardadas/set-payments
```http
POST /api/v1/collect/set/payments
```
## What it does [#que-hace]
Create payments.
## Authentication [#autenticacion]
Host: `https://app.tilopay.com`. Requires the API bearer token in `Authorization: Bearer ` and the integration key in the body (`key`).
[Get the API token](/en/developers/api/autenticacion/token-api).
## Parameters [#parametros]
Integration key.
Also applies to charges scheduled by date.
1 captures; 0 only authorizes.
Payment reason.
Affiliates: array of `{id, amount, currency, date}`.
Groups: array of `{id, amount, currency, date}`; amount is per affiliate.
The `date` field is empty for immediate charges or `YYYY-MM-DD` for scheduled charges. In `groups`, `amount` is per affiliate.
## Request example [#ejemplo-request]
`` is the placeholder for your integration key.
```json
{
"key": "",
"capture": 1,
"reason": "Cobro mensualidad",
"users": [
{
"id": "5",
"amount": "500.00",
"currency": "CRC",
"date": ""
},
{
"id": "32",
"amount": "1000.00",
"currency": "CRC",
"date": "2024-06-20"
},
{
"id": "25",
"amount": "10.00",
"currency": "USD",
"date": "2024-06-20"
}
],
"groups": [
{
"id": "10",
"amount": "25.00",
"currency": "USD",
"date": ""
}
]
}
```
## Response [#respuesta]
batch is the batch code for get/massive/detail. Empty date = immediate; YYYY-MM-DD = scheduled. Repeating this operation creates another charge.
`status`.
`errors`.
`users_errors`.
`groups_errors`.
`programeds`.
`batch`.
```json
{
"status": 200,
"errors": "",
"users_errors": "",
"groups_errors": "",
"programeds": {
"users": [
"5",
"32",
"25"
],
"groups": [
"10"
]
},
"batch": "SGZqbHlHalJiWmRNSEszd3ZEZHo4dz09"
}
```
```schema
{
"type": "object",
"properties": {
"status": {
"type": "integer"
},
"errors": {
"type": "string"
},
"users_errors": {
"type": [
"string",
"array"
],
"items": {}
},
"groups_errors": {
"type": [
"string",
"array"
],
"items": {}
},
"programeds": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "string"
}
},
"groups": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"batch": {
"type": "string"
}
}
}
```
## Error response [#respuestas-de-error]
HTTP 400:
```json
{
"status": "400",
"errors": "Please verify the data sent",
"users_errors": [
{
"id": "32",
"amount": "1000.00",
"currency": "CRC",
"date": "invalidDate"
}
],
"groups_errors": [
{
"id": "10",
"amount": "25.00",
"currency": null,
"date": null
}
]
}
```
[Safe retries](/en/developers/reintentos-seguros).
---
# API · Webhooks
> Which events exist, how many retries there are, in what format they arrive and how to confirm the state of a charge.
- kind: concept
- status: stable
- api_version: v1
- last_verified: 2026-10-20
- url: https://tilopay.com/en/developers/api/webhooks
## Recurrence [#recurrencia]
Six fields configured when **creating or editing a plan**. All optional.
| Field | What it is |
|---|---|
| `webhook_subscribe` | Subscription webhook |
| `webhook_payment` | Charge webhook |
| `webhook_rejected` | Rejected charge webhook |
| `webhook_unsubscribe` | Unsubscribe webhook |
| `webhook_reactive` | Reactivation webhook |
| `thanks_url` | **Not a webhook:** it is a GET callback |
## Payment links [#links-de-pago]
`webhook_url` is configured when creating the link.
## Retries [#reintentos]
| Source | Attempts | When it retries |
|---|---|---|
| Recurrence | 5 | When your response is 400, 404, 502, 504 or 403 |
| Purchases | 1 | — |
Delivery is considered successful on an **HTTP 200**. Respond 200 as soon as you receive the
event and process it separately: anything else counts as a failure, and purchases have no second
attempt.
## Format [#formato]
JSON.
## The card token [#token]
| Source | Token |
|---|---|
| Recurrence | **Not sent** |
| Purchases | Sent and **usable** |
## Origin verification [#verificacion]
> **Warning:** The only origin verification available is the `orderHash`, and its algorithm is not public:
> it is requested by writing to `soporte@tilopay.com`.
>
> Until you have the algorithm, do not take irreversible business decisions from webhook content
> alone: confirm the state against the API before shipping or releasing a service.
## Main flow webhook [#processpayment]
> **Note:** `processPayment` also has a webhook. Its technical specification (the fields it sends) we deliver it when you request it, so your team can implement it:
> write to `soporte@tilopay.com` to receive it.
---
# JavaScript SDK
> The integration path where the card form lives on your page and the SDK sends the data straight to Tilopay.
- kind: guide
- status: stable
- sdk_version: 2.1.1
- last_verified: 2026-10-22
- url: https://tilopay.com/en/developers/sdk
## What it is [#que-es]
The card fields live on your page. The V2 SDK takes over those inputs and sends the data
**from the browser straight to Tilopay**: it never passes through your server.
## Who it is for [#para-quien]
For teams that want to control the checkout design without card data touching their backend.
You need a JavaScript frontend and a minimal backend to obtain the SDK token.
## How to build it, in order [#orden]
1. **Credentials.** There are no shared sandbox credentials: get yours through
[developer registration](/en/developers/registro).
2. **SDK token.** Your backend requests it with `POST /api/v1/loginSdk`. See
[authentication](/en/developers/api/autenticacion).
3. **Load the script.** See [installation](/en/developers/sdk/instalacion).
4. **Add the inputs with the contract ids** and the `responseTilopay` container. See
[form fields](/en/developers/sdk/campos-del-formulario).
5. **Start the purchase** with [`Tilopay.Init()`](/en/developers/sdk/reference/init) and show the
customer the payment methods it returns.
6. **Close the purchase** with
[`Tilopay.startPayment()`](/en/developers/sdk/reference/startpayment). The SDK handles 3DS and
renders the result on your `redirect` URL.
7. **Confirm the result on your server.** The redirect belongs to the customer; before
delivering the product, confirm the status with the API. See
[confirm the result](#confirmar).
## Method flow [#flujo]
## SINPE Móvil: confirmation and timing [#sinpe-confirmacion]
When the transfer arrives, the SDK redirects to your `redirect`; Tilopay also notifies `webhook` if provided. The SDK does not set a deadline, but Tilopay matches transfers with SINPE Móvil orders created within the last **25 minutes**: customers must transfer within that window. The session depends on the SDK token lifetime.
```text
Required: Init() ──────────────────────────────► startPayment()
Optional: getCardType() (show the brand icon)
updateOptions() (if data changes)
```
You can also accept [Apple Pay](/en/developers/sdk/apple-pay): the SDK draws the button inside the
form.
## Confirm the result on your server [#confirmar]
When it finishes, the customer's browser lands on your `redirect` URL with the result
parameters: `code`, `description`, `auth`, `order`, `tpt`, `tilopay-transaction`, `OrderHash`
and `returnData`. See the full table in
[parameters that arrive at the redirect](/en/developers/api/hosted-payment-page/process-payment#parametros-del-redirect).
- `code = 1` means the transaction is approved; any other value is a decline.
- The redirect is received by the customer's browser, so it is not enough proof: **before
delivering the product, confirm the status with `POST /api/v1/consult` from your server**.
- `OrderHash` is a unique string per transaction: its algorithm is not public and is
requested by writing to `soporte@tilopay.com`.
## Before assuming you are in test mode [#entornos]
Testing and production share one host: the mode is verified with the `environment` field returned
by `Init()` (`"TEST"` or `"PROD"`). See [environments](/en/developers/entornos).
## Full example [#ejemplo-completo]
Form inside `.payFormTilopay`, the five fields, Pay and Update buttons, `responseTilopay`
outside the form, the v2 script, `Init()` with every field, loading `methods` and `cards` into
their selects, and `startPayment()`.
```html
```
## Compliance [#cumplimiento]
Card data does not pass through your server, but your page captures it: check the applicable
scope with your compliance team.
---
# API · Get SDK token
> SDK login: returns the token that Tilopay.Init() uses in the browser.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-10-20
- url: https://tilopay.com/en/developers/api/autenticacion/token-sdk
```http
POST /api/v1/loginSdk
```
## What it does [#que-hace]
Returns the security token needed to consume the SDK. All three credentials come from [Admin panel · Platform integrations](https://admin.tilopay.com/platform-integrations).
## Authentication [#autenticacion]
It does not require a token: this is the operation that issues it. See [authentication](/en/developers/api/autenticacion).
> **Warning:** This login runs on your server, never in the browser. `apiuser`, `password` and `key`
> are merchant secrets: they are never exposed in the frontend. Only the token returned by
> this operation reaches the browser.
## Parameters [#parametros]
Merchant API user.
Merchant API password.
Merchant api key.
## Request example [#request]
The `<...>` values are placeholders: replace them with your own credentials and data.
```json
{
"apiuser": "",
"password": "",
"key": ""
}
```
## Response [#respuesta]
```json
{
"access_token": "351d477adaaa51cdbb33ae4b4b8c843aa759f131c1c38415180b5035543d59d2f23f4e049706f5fa71c5f0d9ff763960a3cd035b4c1cefa428c90bedb672f780",
"token_type": "bearer",
"expires_in": "2023-06-05 13:32:06"
}
```
## Error responses [#respuestas-de-error]
Invalid credentials → HTTP 401:
```json
{
"error": "Unauthorized"
}
```
To interpret a response that is not a success, see [how to read an error response](/en/developers/api/procesos-operativos/errors).
---
# SDK installation
> The V2 SDK script tag, the version history, the domains for your Content-Security-Policy and which versioning guarantees do not exist.
- kind: guide
- status: stable
- sdk_version: 2.1.1
- last_verified: 2026-10-22
- url: https://tilopay.com/en/developers/sdk/instalacion
## The script [#script]
```html
```
Load it before your own checkout code. The SDK exposes the global `Tilopay` object. The
current version is **2.1.1**.
## jQuery is not required [#jquery]
> **Note:** jQuery is NOT required. Since version 2.0.0 the SDK is written in JavaScript: you can
> install it without jQuery on the page.
## Version history [#versiones]
| Version | Date | Change |
|---|---|---|
| 1.0.0 | 29/07/2022 | Tilopay payment form |
| 1.1.0 | 05/10/2022 | Saved cards and SINPE Móvil |
| 2.0.0 | 01/06/2023 | Migration from jQuery to JavaScript |
| 2.1.0 | 30/08/2023 | [`InitTokenize()`](/en/developers/sdk/reference/init-tokenize) to save cards |
| 2.1.1 | — | [Apple Pay](/en/developers/sdk/apple-pay) |
## Domains for Content-Security-Policy [#csp]
If your site uses a Content-Security-Policy, allow the origins the SDK loads:
| Origin | When |
|---|---|
| `https://app.tilopay.com` | Always |
| `https://api.tokenex.com` | Always |
| `https://h.online-metrix.net` | Always |
| `https://storage.googleapis.com` | Always |
| `https://cdn.jsdelivr.net` | Always |
| `https://applepay.cdn-apple.com` | Only if you use [Apple Pay](/en/developers/sdk/apple-pay) |
## What does not exist [#garantias]
> **Warning:** There is no immutable versioning, no SRI hash and no changelog. The
> `/sdk/v2/sdk_tpay.min.js` URL is not pinned to a specific version: its contents can change
> without prior notice and without public release notes.
>
> Practical consequences:
>
> - You cannot set `integrity="sha384-..."` on the `script` tag, because the file changes.
> - You cannot rely on a build number to reproduce a bug.
> - Keep smoke tests for your checkout running periodically, not only on deploy.
## Single-page applications [#spa]
Works in React and Vue. Call `Init()` after the fields mount in the DOM: it uses them immediately and fails if they do not exist. Call `Init()` again if the form remounts.
React Native WebView is not tested by Tilopay and may disable Apple Pay; test it in your environment before production.
## What is next [#que-sigue]
- [Form fields](/en/developers/sdk/campos-del-formulario) — the ids the SDK looks for.
- [`Tilopay.Init()`](/en/developers/sdk/reference/init) — start the purchase.
---
# Form fields
> The tlpy_* ids the V2 SDK looks for inside the payFormTilopay div, and the responseTilopay container it needs for 3DS.
- kind: concept
- status: stable
- sdk_version: 2.1.1
- last_verified: 2026-10-21
- url: https://tilopay.com/en/developers/sdk/campos-del-formulario
The V2 SDK does not render the form: it takes over the inputs that already exist on your
page, finding them by `id`. Those ids are a contract — change one and the SDK stops finding
the field.
> **Warning:** The `payFormTilopay` container is required. All `tlpy_*` fields (and the
> [Apple Pay](/en/developers/sdk/apple-pay) div) must be inside a `div` with the class
> `payFormTilopay`: the SDK looks for that container to listen to the fields. The
> `responseTilopay` container goes outside that `div`.
## Fields [#campos]
Holds the payment method id obtained from Tilopay. It may be visible or hidden, at your discretion.
Holds the saved card id obtained from Tilopay. It must exist in the DOM; it may be hidden
if the payment method does not use it.
Card number. It must exist in the DOM; it may be hidden if the payment method does not use
it.
Expiration date in month/year format, for example `12/30`. It must exist in the DOM; it may
be hidden if the payment method does not use it.
Security code. It must exist in the DOM; it may be hidden if the payment method does not
use it. When the customer uses a saved card, this field must be enabled so they can type
the CVV.
For [Apple Pay](/en/developers/sdk/apple-pay): the SDK draws the Apple Pay button there. It goes
inside `payFormTilopay`.
Optional, for Apple Pay. Its value changes to `"cancelled"` and fires `change` when the buyer
closes the Apple Pay sheet.
Required container, **outside `payFormTilopay`**. This is where the SDK mounts the 3DS flow.
## The Yappy phone does not travel through the DOM [#yappy]
The Yappy phone number is **not** read from a form field: it is sent in the `phoneYappy`
parameter of [`Init()`](/en/developers/sdk/reference/init) or
[`updateOptions()`](/en/developers/sdk/reference/update-options).
## Example structure [#estructura]
The `div` with the `payFormTilopay` class, the input `id`s and `responseTilopay` are
required; the other `div` elements are free-form.
```html
```
---
# Apple Pay
> How to accept Apple Pay with the V2 SDK (2.1.1) — requirements, steps, example, payment sheet data and common problems.
- kind: guide
- status: stable
- sdk_version: 2.1.1
- last_verified: 2026-10-21
- url: https://tilopay.com/en/developers/sdk/apple-pay
## What it is [#que-es]
The SDK draws the Apple Pay button inside your form, opens Apple's payment sheet and processes
the payment with Apple's encrypted token. The buyer does not type the card.
## Requirements [#requisitos]
| Requirement | Detail |
|---|---|
| Production account | In testing mode the button does not appear and `applePaySupported` is `false`: it cannot be tested in testing mode. |
| Payment method with Apple Pay | In `init.methods` the method has `apple_pay = 1`. If your method does not, the button is not shown. |
| Certified domain | The domain must be certified for Apple Pay in your Tilopay account. The match is exact: `www.comercio.com` and `comercio.com` are different domains. To certify it, write to soporte@tilopay.com with the exact domain. |
| HTTPS | The page is served over HTTPS. |
| Browser | Safari on an Apple device with Apple Pay set up. |
| Cards | Visa, Mastercard or American Express. |
## Steps [#pasos]
1. Load the [v2 SDK](/en/developers/sdk/instalacion).
2. Inside `.payFormTilopay` add `` where the button
goes and, optionally, `` to know when the
buyer closes the sheet (its value changes to `"cancelled"` and fires `change`).
3. Call [`Init()`](/en/developers/sdk/reference/init) as usual (token, currency, amount, order,
billing, `capture` and `redirect`). `applePaySupported: true` means the requirements are met
for that domain and browser.
4. Fill `#tlpy_payment_method` with `init.methods`.
5. The button appears when the select fires the `change` event with a method that has Apple
Pay. If you select the method from code, fire
`select.dispatchEvent(new Event('change'))`.
6. When the button is tapped, the SDK opens Apple Pay and, once the buyer authorizes, processes
the payment: if approved it redirects to `redirect`; if the bank asks for 3DS it shows it in
`#responseTilopay`.
> **Note:** The card fields are still required. `tlpy_cc_number`, `tlpy_cc_expiration_date` and
> `tlpy_cvv` must be in the HTML even if the buyer pays with Apple Pay, because the SDK
> initializes them in `Init()`.
## Example [#ejemplo]
```html
```
## Apple Pay sheet data [#hoja]
| Field | Value |
|---|---|
| Country | `CR` |
| Currency | The one from `Init()`, uppercase |
| Networks | `visa`, `mastercard` and `amex` |
| Capability | `supports3DS` |
| Label | `Tilopay: ` |
| Amount | The one from `Init()` |
## Behavior to keep in mind [#comportamiento]
- The Apple Pay payment result **is not returned to your code** (the button calls the SDK
directly): it arrives on the `redirect` URL like any payment. Confirm it with
`POST /api/v1/consult` from your server. See [confirm the result](/en/developers/sdk#confirmar).
- You can only listen for cancellation, with `tlpy_apple_pay_cancel`.
- If the payment fails, the sheet stays open until the buyer closes it or it expires, and the
detail is logged in the browser console.
## Common problems [#problemas]
| Symptom | Cause and fix |
|---|---|
| `applePaySupported` is `false` | Account in testing mode, no method with `apple_pay = 1`, browser without Apple Pay or uncertified domain. When it is the domain, the console shows `Apple Pay not allowed for this domain`. |
| `applePaySupported` is `true` but the button does not appear | The div is not inside `.payFormTilopay`, the selected method has no Apple Pay or the select did not fire `change`. |
| It works on one domain but not with `www` | Certify the other form too, or always use the certified one. |
| The button opens the sheet and it closes right away | Merchant validation with Apple failed: check that the domain certification is current and write to soporte@tilopay.com with the domain and the time. |
| The buyer authorizes and the sheet keeps loading | The payment failed: check the console and look up the transaction by order number. |
---
# Tilopay.Init()
> Starts a purchase: authenticates the checkout and returns the environment, the available payment methods and the customer's saved cards.
- kind: sdk-method
- status: stable
- sdk_version: 2.1.1
- last_verified: 2026-10-22
- url: https://tilopay.com/en/developers/sdk/reference/init
Starts a purchase. It authenticates the checkout with the SDK token and returns the payment
methods available to you.
To save a card without charging it, use
[`Tilopay.InitTokenize()`](/en/developers/sdk/reference/init-tokenize).
## Signature [#firma]
```js
await Tilopay.Init({ /* parameters */ })
```
## Parameters [#parametros]
URL where Tilopay notifies the outcome of SINPE Móvil and Yappy payments.
SDK token, obtained by your backend with `POST /api/v1/loginSdk`. See
[SDK token](/en/developers/api/autenticacion/token-sdk).
Purchase currency, ISO 4217.
Checkout language: `es` or `en`.
Purchase amount.
Customer email. Needed for the response to include saved cards.
Order number. **It cannot be repeated.** See
[safe retries](/en/developers/reintentos-seguros).
Customer identification type. Required for SINPE Móvil. See the
[type table](/en/developers/sdk/reference/update-options#tipos-de-identificacion).
Customer identification number. Required for SINPE Móvil.
Customer first name.
Customer last name.
Customer address line 1.
Customer address line 2.
City.
State or province.
Postal code.
Country, ISO 3166-1 alpha-2.
Customer phone.
Shipping recipient first name.
Shipping recipient last name.
Shipping address line 1.
Shipping address line 2.
Shipping city.
Shipping state or province.
Shipping postal code.
Shipping country, ISO 3166-1 alpha-2.
Shipping phone.
`0` authorizes; `1` authorizes and captures.
URL where the SDK renders the final purchase response.
`1` saves the customer card in Tilopay; `0` does not save it.
Values `"V1"` or `"V2"`. If omitted, the final response hash is built with **V2**. It is
sent in this first call.
Returned as-is in the final payment response and recovered on the transaction
response URL. Supports up to **65,535 characters**, although a very long value can affect
the response URL. You can send a base64-serialized array so it satisfies the string format.
Yappy phone. Required when paying with Yappy. It is not read from the DOM.
## Call [#llamada]
```js
const init = await Tilopay.Init({
token: "",
currency: "CRC",
language: "es",
amount: 100.0,
billToEmail: "cliente@ejemplo.com",
orderNumber: "ORD-2026-000123",
billToFirstName: "Ana",
billToLastName: "Rojas",
billToCountry: "CR",
capture: 1,
redirect: "https://ejemplo.com/respuesta",
subscription: 0,
});
```
## Response [#respuesta]
```json
{
"message": "Success",
"environment": "PROD",
"sinpemovil": { "code": "TB095", "amount": "100.00" },
"methods": [
{ "id": "", "name": "Tarjeta", "type": "card", "apple_pay": 0 },
{ "id": "", "name": "SINPE Móvil", "type": "sinpemovil", "apple_pay": 0 }
],
"cards": [
{ "id": "411112555451111:Ref", "name": "4111********1111", "brand": "visa" }
],
"applePaySupported": false
}
```
`Success`, or the error description.
`"PROD"` production, `"TEST"` testing. See [environments](/en/developers/entornos).
Object with `code` and `amount`, present when you have SINPE Móvil. The full data,
including the destination phone, is obtained with
[`getSinpeMovil()`](/en/developers/sdk/reference/get-sinpe-movil).
Array of `{id, name, type, apple_pay}` with available methods. `type` is `card`, `sinpemovil` or `yappy`; every method includes `apple_pay` (`0` or `1`).
Array of `{id, name, brand}` with the customer's saved cards.
`true` when the [Apple Pay](/en/developers/sdk/apple-pay) requirements are met for that domain
and browser.
### On error [#respuesta-de-error]
On error:
```json
{
"message": "",
"methods": [],
"cards": []
}
```
## Payment method id format [#formato-id-metodo]
Do not interpret the id: store it as-is as the select value and use each method's `type` field
(`card`, `sinpemovil` or `yappy`) to decide which fields to show.
## Yappy [#yappy]
The method has `type: "yappy"`; its id has the form `:18::…`.
The form needs the required `Init()` fields plus `phoneYappy`. Calling `startPayment()` redirects to a Tilopay page that opens Yappy; the customer approves in their app. When finished, Tilopay notifies `webhook` (if provided) and redirects to your `redirect` with `code`, `auth`, `order` and `OrderHash`. Cancellation rejects the order; without a response within **7 minutes**, it becomes “Transaction expired”.
## Saved cards [#tarjetas-guardadas]
- For the response to include `cards`, **`billToEmail` is required**.
- Once the cards are obtained, **the email can no longer be changed** with
[`updateOptions()`](/en/developers/sdk/reference/update-options).
- The customer can pick a saved card or type a new one.
- When a saved card is picked, **enable `tlpy_cvv`** so the customer can type the code.
---
# Tilopay.InitTokenize()
> Starts saving a card without a purchase: the card is validated with a USD 0.10 charge that is reversed immediately.
- kind: sdk-method
- status: stable
- sdk_version: 2.1.1
- last_verified: 2026-10-22
- url: https://tilopay.com/en/developers/sdk/reference/init-tokenize
Starts saving a card **without a purchase**. It uses the same
[form fields](/en/developers/sdk/campos-del-formulario) as `Init()` and is closed with
[`Tilopay.startPayment()`](/en/developers/sdk/reference/startpayment).
> **Note:** Validation charge. To validate the card, Tilopay makes a USD 0.10 charge (or its equivalent
> in the currency) that is reversed immediately; the customer sees it refunded within minutes.
Store the token you receive and associate it with the customer's email to use it later.
## Signature [#firma]
Do not send `orderNumber`: the SDK uses its own session identifier. Tilopay sets the validation amount.
```js
await Tilopay.InitTokenize({ /* parameters */ })
```
## Redirect parameters [#parametros-del-redirect]
Redirect query parameters are `code`, `crd`, `order`, `brand`, `last-digits` and `OrderHash`. `crd` is the card token and only has a value when `code = 1`; store it with the customer email. Tilopay generates `order`, not the merchant.
## Parameters [#parametros]
SDK token, obtained with `POST /api/v1/loginSdk`.
Currency, ISO 4217.
Language: `es` or `en`.
Customer email.
Customer first name.
Customer last name.
Customer address line 1.
Customer address line 2.
City.
State or province.
Postal code.
Country, ISO 3166-1 alpha-2.
Customer phone.
URL where the SDK renders the final response.
## Call [#llamada]
```js
const init = await Tilopay.InitTokenize({
token: "",
currency: "USD",
language: "es",
billToEmail: "cliente@ejemplo.com",
billToFirstName: "Ana",
billToLastName: "Rojas",
redirect: "https://ejemplo.com/respuesta",
});
```
## Response [#respuesta]
```json
{
"message": "Success",
"environment": "PROD",
"methods": [
{ "id": "", "name": "Tarjeta", "type": "card" }
]
}
```
On error:
```json
{
"message": "",
"methods": []
}
```
---
# Tilopay.startPayment()
> Closes the purchase. It takes no parameters; it redirects to the redirect URL or shows 3DS in responseTilopay.
- kind: sdk-method
- status: stable
- sdk_version: 2.1.1
- last_verified: 2026-10-22
- url: https://tilopay.com/en/developers/sdk/reference/startpayment
Closes the purchase started with [`Tilopay.Init()`](/en/developers/sdk/reference/init) (or the card
save started with [`InitTokenize()`](/en/developers/sdk/reference/init-tokenize)).
## Signature [#firma]
```js
await Tilopay.startPayment()
```
It takes no parameters. **It requires the data to be complete**: payment method, card data and
whatever the method needs, sent in `Init()` or in
[`updateOptions()`](/en/developers/sdk/reference/update-options).
## 3DS: the SDK handles it [#tres-ds]
**The SDK handles the whole 3D Secure flow.** If the bank asks for it, the SDK shows it in the
`responseTilopay` container:
```html
```
See [form fields](/en/developers/sdk/campos-del-formulario#campos).
## Where the result arrives [#resultado]
On successful payment, the SDK redirects and the promise resolves with `{ "message": "" }`, without payment data. On error it returns `{ "message": "" }`.
If everything goes well, the SDK redirects to the URL given in `redirect`. That redirect is
received by the customer's browser, so before delivering the product
[confirm the result on your server](/en/developers/sdk#confirmar).
If there is an error, the method returns the description:
```json
{
"message": ""
}
```
With SINPE Móvil, until the transfer arrives, `startPayment()` returns the pending-SINPE error.
See [`getSinpeMovil()`](/en/developers/sdk/reference/get-sinpe-movil).
---
# Tilopay.getCardType()
> Returns the brand of the card the customer typed or picked, in lowercase, so you can show its icon.
- kind: sdk-method
- status: stable
- sdk_version: 2.1.1
- last_verified: 2026-10-21
- url: https://tilopay.com/en/developers/sdk/reference/get-card-type
Returns the card brand from the number the customer already typed into `tlpy_cc_number` (or
from the saved card they picked). The typical use is showing the brand icon.
## Signature [#firma]
```js
await Tilopay.getCardType()
```
It takes no parameters.
**Precondition:** the customer must have already typed the card number or picked a saved card.
## Call [#llamada]
```js
const type = await Tilopay.getCardType();
```
## Response [#respuesta]
```json
{
"message": "visa"
}
```
The card brand, in lowercase. If the brand is not recognized, it is empty.
## Brand values [#marcas-soportadas]
| Status | Values |
|---|---|
| Supported | `visa`, `mastercard`, `amex` |
| Not supported | `elo`, `visaelectron`, `maestro`, `forbrugsforeningen`, `dankort`, `hipercard`, `dinersclub`, `discover`, `unionpay`, `jcb`, `laser` |
Use the result for presentation only: brand validation happens when Tilopay processes the
charge, not in this method.
---
# Tilopay.getSinpeMovil()
> Returns the data to show the customer to pay via SINPE Móvil: destination phone, exact amount and code.
- kind: sdk-method
- status: stable
- sdk_version: 2.1.1
- last_verified: 2026-10-22
- url: https://tilopay.com/en/developers/sdk/reference/get-sinpe-movil
SINPE Móvil is not charged from the form: the customer makes the transfer from their own bank.
This method builds the data of the selected SINPE method that you must show them —
destination phone, exact amount and description code.
## When to use it [#cuando]
When you have a SINPE Móvil method available and the customer selects it from the list
returned by [`Init()`](/en/developers/sdk/reference/init).
## Signature [#firma]
```js
await Tilopay.getSinpeMovil()
```
It takes no parameters.
**Preconditions:**
- The customer must have selected SINPE Móvil as the payment method.
- `typeDni` and `dni` must have been sent earlier, via `Init()` or
[`updateOptions()`](/en/developers/sdk/reference/update-options).
## Call [#llamada]
```js
const params = await Tilopay.getSinpeMovil();
```
## Response [#respuesta]
```json
{
"message": "Success",
"code": "863",
"amount": 10,
"number": "70599200"
}
```
`Success` when the operation succeeded; the error description otherwise.
The code the customer must write in the transfer description. It is what identifies the payment.
The exact amount they must transfer.
The destination phone number for the transfer.
### On error [#respuesta-de-error]
It returns an object with the error description and the other fields empty:
```json
{
"message": "",
"code": "",
"amount": "",
"number": ""
}
```
## SINPE Móvil: confirmation and timing [#sinpe-confirmacion]
When the transfer arrives, the SDK redirects to your `redirect`; Tilopay also notifies `webhook` if provided. The SDK does not set a deadline, but Tilopay matches transfers with SINPE Móvil orders created within the last **25 minutes**: customers must transfer within that window. The session depends on the SDK token lifetime.
## What to do with this data [#que-hacer]
- When SINPE Móvil is selected, hide the card fields and show a message such as: *"To pay with
SINPE Móvil, transfer the exact amount ₡100.00 to phone 8888 8888 and write TB095 in the
description"*.
- Optionally, add an "I already made the SINPE Móvil transfer" button that, when tapped, shows
that the deposit is being awaited. Before enabling it, make sure you have the email, `typeDni`
and `dni`.
- Until the transfer arrives, [`startPayment()`](/en/developers/sdk/reference/startpayment) returns
the pending-SINPE error.
---
# Tilopay.updateOptions()
> Partially updates the parameters sent to Init() when they change before closing the payment.
- kind: sdk-method
- status: stable
- sdk_version: 2.1.1
- last_verified: 2026-10-22
- url: https://tilopay.com/en/developers/sdk/reference/update-options
Updates values already sent in [`Tilopay.Init()`](/en/developers/sdk/reference/init) that changed
during checkout — typically when the customer edits their data, or when they select SINPE Móvil
or Yappy and information that did not apply before must be added.
> **Note:** It is a partial update. Send only the fields you want to update; there is no need to resend
> everything.
## No field is required in the call [#obligatorio]
No parameter is required in `updateOptions()`. What matters is that, before closing the
payment, the data the payment method needs (for example `typeDni` and `dni` for SINPE Móvil, or
`phoneYappy` for Yappy) was sent in `Init()` or in `updateOptions()`.
## Signature [#firma]
```js
await Tilopay.updateOptions({ /* only the fields that change */ })
```
## Call [#llamada]
```js
const update = await Tilopay.updateOptions({
typeDni: 1,
dni: "0707770777",
billToFirstName: "Ana",
billToLastName: "Rojas",
});
```
## Parameters [#parametros]
URL where Tilopay notifies the outcome of SINPE Móvil and Yappy payments.
You can update `typeDni`, `dni`, the `billTo*` fields (except `billToEmail`), the `shipTo*`
fields, `capture`, `redirect`, `subscription` and `phoneYappy`.
Customer identification type. Needed for SINPE Móvil. See
[identification types](#tipos-de-identificacion).
Customer identification number. Needed for SINPE Móvil. **Accepted with and without hyphens.**
Customer first name.
Customer last name.
Customer address line 1.
Customer address line 2.
City.
State or province.
Postal code.
Country, ISO 3166-1 alpha-2.
Customer phone.
Shipping recipient first name.
Shipping recipient last name.
Shipping address line 1.
Shipping address line 2.
Shipping city.
Shipping state or province.
Shipping postal code.
Shipping country, ISO 3166-1 alpha-2.
Shipping phone.
`0` authorizes; `1` authorizes and captures.
URL where the final purchase response is expected.
`1` if the customer wants to save their card in Tilopay; `0` if not.
Yappy phone. Needed when the customer pays with Yappy.
> **Warning:** `billToEmail` cannot be updated. Once `Init()` returned the customer's cards, the email
> cannot be changed through this method.
## Identification types [#tipos-de-identificacion]
Applies to the `typeDni` parameter, both here and in `Tilopay.Init()`. In the masks, `#` is a
**numeric** character and `&` is **alphanumeric**. Lengths do not count hyphens.
| Code | Type | Format | Length |
|---|---|---|---|
| 1 | Cédula de identidad | `0#-####-####` | 10 |
| 2 | Cédula jurídica | `3-###-######` | 10 |
| 3 | Gobierno central | `2-###-######` | 10 |
| 4 | Institución autónoma | `4-###-######` | 10 |
| 5 | Extranjero no residente | `9&&&&&&&&&&&&&&&&&&&` | 20 |
| 6 | DIMEX | `1###########` | 12 |
| 7 | DIDI | `5###########` | 12 |
## Response [#respuesta]
```json
{
"message": "Success"
}
```
`Success` when the update succeeded; the error description otherwise.
---
# Tilopay Banking API
> Reference for Tilopay's Banking API (BaaS), generated from its OpenAPI 3.0.3 spec, version 1.0.0.
- kind: api-index
- status: stable
- api_version: 1.0.0
- last_verified: 2026-10-22
- url: https://tilopay.com/en/developers/api-bancario
With our Banking API you can initiate payments (PIN and SINPE Móvil), check their status,
manage your accounts and receive payment event webhooks from your own systems, always
limited to the accounts your access token authorizes.
**It is a separate product from the payment gateway.** It runs on its own
infrastructure, with its own host, credentials and authentication. If you already
integrate our acquiring API, access to this one is enabled separately.
Here you will find the official endpoints, models and flows for version **1.0.0** of the
Banking API.
## What it can do [#que-permite]
**Payments.** Create a payment, fetch it by identifier, list it by account and search it
by `payment_id`, `public_id` or `client_reference`; the available methods are `PIN` and
`SINPE_MOVIL`. Creation only accepts direction `OUT`; `IN` payments remain available in listings and webhooks.
[See payment operations](/en/developers/api-bancario/pagos).
**Accounts.** Validate a destination account before transferring, list your
accounts with or without balances, check an account balance and request statements
asynchronously.
[See account operations](/en/developers/api-bancario/cuentas).
**Webhooks.** Register your encrypted HTTPS destination, see the events you can
subscribe to per payment method and the data structure we send in each one.
[See webhook operations](/en/developers/api-bancario/webhooks).
**Catalogs.** Customer identification person types per country.
[See catalogs](/en/developers/api-bancario/catalogos).
We also provide `GET /api/public/v1/healthz` for health checks, plus `GET
/openapi.yaml` and `GET /docs` with the OpenAPI definition and interactive documentation
right on the API host.
## Environments [#entornos]
There are two environments, with the same routes and contracts. The sandbox one:
```text
https://api-baas-sandbox.tilopay.com
```
Production is the same host without the `-sandbox` suffix:
```text
https://api-baas.tilopay.com
```
Tilopay issues sandbox credentials on request; coordinate access with your merchant contact at Tilopay. When you are ready, we provide production credentials as we enable your access.
## Machine-readable artifacts [#artefactos]
We publish the full Banking API OpenAPI definition, with open CORS, in two formats:
- [openapi.json](/developers/api-bancario/openapi.json)
- [openapi.yaml](/developers/api-bancario/openapi.yaml)
It is independent from our acquiring API definition
([/developers/openapi.json](/developers/openapi.json)): they are two separate products.
## How to get access [#acceso]
Access is restricted and granted on request, for operations in Costa Rica. To learn
about the product and request it, visit [baas.tilopay.com](https://baas.tilopay.com), stating
estimated monthly volume, use case and systems to integrate.
## Where to go next [#siguiente]
1. [Authentication](/en/developers/api-bancario/autenticacion) — login, token exchange and Bearer.
2. [Conventions](/en/developers/api-bancario/convenciones) — envelope, correlation, safe retries, pagination and dates.
3. [Response codes](/en/developers/api-bancario/errores) — full `response_code` catalog.
---
# Banking API authentication
> Login, token exchange and Bearer JWT usage in Tilopay's Banking API.
- kind: concept
- status: stable
- api_version: 1.0.0
- last_verified: 2026-10-22
- url: https://tilopay.com/en/developers/api-bancario/autenticacion
The Banking API uses a two-step flow: first you authenticate the customer with email and
password, then you exchange the resulting token for a JWT access token that signs every
other call.
The three endpoints in the `Auth` group are the only ones that carry **no**
`Authorization` header. Every other endpoint requires
`Authorization: Bearer `.
## Step 1 — Login [#login]
```http
POST /api/public/v1/auth/login
```
Required body: `email` (email format) and `password`.
```json
{
"email": "operations@merchant.com",
"password": "••••••••"
}
```
The `200` response returns in `data`:
| Field | Type | Description |
|---|---|---|
| `gidp_id_token` | string | Identity token for step 2, valid for 1 hour and only usable for the exchange. |
| `assignments` | array | Available customer contexts. |
Each `assignments` item carries `assignment_id`, `owner_type`, `owner_id`, `tenant_id`,
`tenant_code`, `country_code`, `role`, `roles` and `status`. Pick the `assignment_id` of
the context you will operate with.
## Step 2 — Token exchange [#exchange]
```http
POST /api/public/v1/auth/token/exchange
```
Required body: `gidp_id_token` (from step 1) and `assignment_id` (the chosen context).
```json
{
"gidp_id_token": "eyJhbGciOi...",
"assignment_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}
```
The `200` response returns in `data`:
| Field | Type | Description |
|---|---|---|
| `token` | string | JWT access token. |
| `expires_in` | integer | Access-token lifetime in seconds; read `expires_in`, do not assume a fixed value. |
| `claims` | object | Resolved token context. |
`claims` includes `sub`, `subject_kind`, `user_type`, `tenant_id`, `owner_type`,
`owner_id`, `roles`, `scopes`, `country_code`, `locale`, `channel`, `idp`, `idp_sub` and
`idempotency_key`.
`claims.idempotency_key` is reserved and always empty: ignore it. Idempotency uses the `Idempotency-Key` header.
## Step 3 — Use the Bearer token [#bearer]
The declared security scheme is `BearerAuth`: HTTP bearer with JWT format.
```http
Authorization: Bearer
```
Context travels **inside** the token: business operations do not take `tenant_id`,
`owner_id` or `owner_type` as parameters. The token alone scopes which accounts and
payments you can reach.
When the token is absent, expired or invalid, the response is `401` with
`response_code: UNAUTHORIZED`. If the token is valid but the context does not authorize
the resource, it is `403` with `FORBIDDEN`. There is no refresh token: repeat login and exchange (steps 1 and 2) before expiration, recommended at **80% of `expires_in`**, or after receiving a `401`.
## Passwords [#password]
```http
POST /api/public/v1/auth/request-set-password
```
Starts the set/reset password process for the given email. It requires no prior
authentication and always responds the same way whether or not the account exists, so it
never reveals if an email is registered.
```json
{
"email": "operations@merchant.com"
}
```
## Rate limits [#limites-de-tasa]
They currently apply to authentication and account validation. Exceeding them returns `429` (`TOO_MANY_REQUESTS`). Retry with exponential backoff.
## Sandbox access [#sandbox]
Tilopay issues sandbox credentials on request; coordinate access with your merchant contact at Tilopay.
---
# Banking API conventions
> Response envelope, correlation, safe retries, pagination and date format in the Banking API.
- kind: concept
- status: stable
- api_version: 1.0.0
- last_verified: 2026-10-22
- url: https://tilopay.com/en/developers/api-bancario/convenciones
Every Banking API operation shares the same response shape, the same pagination rules
and the same date format. Here we explain those shared rules.
## Response envelope [#envelope]
Every response, successful or not, travels in the same envelope:
```json
{
"success": true,
"http_status_code": 200,
"response_code": "OK",
"message": "The request was processed successfully.",
"correlation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"data": {}
}
```
| Field | Type | Description |
|---|---|---|
| `success` | boolean | `true` on successful responses; `false` on errors. |
| `http_status_code` | integer | Repeats the HTTP status inside the body. |
| `response_code` | string | Code from the [`response_code` catalog](/en/developers/api-bancario/errores). |
| `message` | string | Human-readable response message. |
| `correlation_id` | string | Call identifier. |
| `data` | object | Operation payload. |
Error responses also carry `errors`, a detail object that may include arbitrary fields
such as `code`, `message` or `detail`.
Branch your logic on `response_code`, never on the `message` text.
## Correlation [#correlacion]
Send `X-Correlation-Id` on the request to propagate your own identifier; the value comes
back as `correlation_id` in the envelope. Keep it in your logs: it is what support uses
to trace a specific call.
## Safe retries [#reintentos]
Two operations accept the `Idempotency-Key` header:
```http
POST /api/public/v1/transactions/payments
POST /api/public/v1/accounts/statements
```
Resending the same key with the same body returns the original result instead of
creating a second record, so a network timeout can be retried without duplicating. If
you reuse a key with a different body, the response is `409` with
`response_code: IDEMPOTENCY_CONFLICT`.
Generate one key per business intent (for example a UUID per order), not one per retry.
Every other operation is a read and can be repeated with no additional effects.
## Pagination [#paginacion]
The API uses two schemes depending on the resource.
**Cursor, on the payment list.** `GET /api/public/v1/transactions/payments` accepts
`limit` (default 20, maximum 100) and `cursor`. The response carries
`pagination.next_cursor`: pass it as `cursor` on the next request. When it is empty or
omitted, there are no more pages.
**Offset, on accounts.** `GET /api/public/v1/accounts` and
`GET /api/public/v1/accounts/balances` accept `limit` (1 to 100) and `offset` (from 0),
and return `pagination` with `limit`, `offset` and `total`.
## Dates and amounts [#formatos]
Date parameters and fields use RFC 3339, for example `2026-09-02T15:04:05Z`. The
`date_from` and `date_to` filters on the payment list follow that same format.
## Host health and documentation [#host]
The host itself exposes three service routes:
```http
GET /api/public/v1/healthz
GET /openapi.yaml
GET /docs
```
`healthz` is for availability checks, `openapi.yaml` returns the OpenAPI definition and `/docs` the
interactive documentation. We also publish it in this portal at
[openapi.json](/developers/api-bancario/openapi.json) and
[openapi.yaml](/developers/api-bancario/openapi.yaml).
## Public identifier [#public-id]
`public_id` is a number in webhooks and text in REST; it is the same identifier. **Always treat it as text.**
## Rate limits [#limites-de-tasa]
They currently apply to authentication and account validation. Exceeding them returns `429` (`TOO_MANY_REQUESTS`); retry with exponential backoff.
---
# Banking API payments
> Banking API payment operations: create, fetch, list and search PIN and SINPE Móvil payments.
- kind: api-operation
- status: stable
- api_version: 1.0.0
- last_verified: 2026-10-22
- url: https://tilopay.com/en/developers/api-bancario/pagos
The `Payments` group covers a payment's full cycle: create it, fetch it by identifier,
list it with filters and search it by any of its references.
```http
POST /api/public/v1/transactions/payments
GET /api/public/v1/transactions/payments
GET /api/public/v1/transactions/payments/{payment_id}
POST /api/public/v1/transactions/payments/search
```
## Resource rules [#reglas]
**Methods.** `payment_method_code` accepts `PIN` and `SINPE_MOVIL`. **Direction.**
At creation, `direction` only accepts `OUT` (outbound); `IN` (inbound) payments remain available in listings and webhooks. **Destination account.** it is
identified by `IBAN` or by `PHONE`, depending on the method. Validate it before
transferring with [account validation](/en/developers/api-bancario/cuentas#operaciones).
**Your own reference.** `client_reference` is your payment identifier and is unique per
tenant: two payments of the same customer cannot share it. Use it to look a payment up
without storing the `payment_id`.
**Safe retries.** Creation accepts `Idempotency-Key`; resending the same key with the same
body returns the original payment instead of creating another one. See
[safe retries](/en/developers/api-bancario/convenciones#reintentos).
## States [#estados]
A payment moves through five states: `pending`, `processing`, `confirmed`, `posted` and
`failed`.
A reversal is **not a state**: a reversed payment stays in `posted` and is recognized by
`result: reversed` and `has_reversal: true`, plus the
[`payment.reversed`](/en/developers/api-bancario/webhooks) event. Always check those two
fields before treating a payment as final.
## Operations [#operaciones]
### List customer payments [#get-transactions-payments]
```http
GET /api/public/v1/transactions/payments
```
Host: `https://api-baas-sandbox.tilopay.com` — requires `Authorization: Bearer `.
Simple REST list of payments for an owned account (IBAN).
Filters are query parameters. Ownership (`tenant_id`, `owner_type`, `owner_id`)
is derived from the access token; clients must not send ownership filters.
**Account identification (required):** `type` + `value` (identifier
scheme + value, e.g. `IBAN` + IBAN string). This is not the internal
account classification.
Pagination is cursor-based (`limit`, `cursor`). Default limit is 20 (max 100).
`status` in the response and as a filter uses the public lowercase catalog
(`pending`, `processing`, `confirmed`, `posted`, `failed`). Same values as webhooks.
REST also returns `status_detail` (uppercase operational name).
Each item includes a consolidated `result` (`succeeded`, `failed`, `reversed`, `pending`)
for reconciliation when a webhook was missed. `status` is only the processing/lifecycle
catalog and does not change to `failed` when a posted payment is later reversed —
use `result=reversed` and `has_reversal=true` (webhook `payment.reversed`).
`error` is `null` when there is no failure information; it is an object only when
`domain` / `platform` is present (`result` is `failed` or `reversed`), same shape
as webhook `payment.failed` `payment.error`.
`source` / `destination` use `null` for unknown `account`, `name`, and `identification`;
account values are IBAN or PHONE only (never internal account UUIDs).
For PIN payments, `identification.number` is the partner-submitted public number
(no SINPE hyphens); older payments may still show the hyphenated SINPE form.
**Parameters**
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `X-Correlation-Id` | header | string | no | Optional client-supplied correlation id for end-to-end tracing. Echoed back as `correlation_id` in the response envelope. If omitted, the API generates one and still returns it. |
| `type` | query | string | yes | Account **identifier scheme** (e.g. `IBAN`). This is **not** the internal account classification (e.g. operational). Values: IBAN |
| `value` | query | string | yes | Account identifier value (IBAN). Spaces are ignored. |
| `status` | query | string | no | Optional payment status filter. Public catalog is lowercase: `pending`, `processing`, `confirmed`, `posted`, `failed`. Uppercase aliases of the same values are accepted. Legacy values such as `INITIATED` map to `pending`. Values: pending, processing, confirmed, posted, failed |
| `date_from` | query | string (date-time) | no | Inclusive lower bound for `created_at`. RFC 3339 (UTC `Z` or offset; optional fractional seconds). |
| `date_to` | query | string (date-time) | no | Inclusive upper bound for `created_at`. RFC 3339 (UTC `Z` or offset; optional fractional seconds). |
| `client_reference` | query | string | no | Filter by partner client reference (exact match against the value sent at payment creation). |
| `currency` | query | string | no | Filter by payment currency (ISO 4217, e.g. CRC). |
| `payment_method_code` | query | string | no | Filter by public payment method code. Values: PIN, SINPE_MOVIL |
| `direction` | query | string | no | Filter by payment direction. Accepts public values `OUT`/`IN` or `PAYOUT`/`PAYIN` (internally normalized to `payout`/`payin`). Values: OUT, IN, PAYOUT, PAYIN |
| `limit` | query | integer | no | Page size (default 20, max 100). |
| `cursor` | query | string | no | Opaque cursor from a previous response `pagination.next_cursor`. |
**200** — The request was processed successfully.
Fields in `data`:
| Field | Type | Required | Description |
|---|---|---|---|
| `schema_version` | string | yes | Same value as webhook envelope `schema_version` (`1.0.0`). |
| `items` | array