# 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.
- [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.
- [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)
---
# 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-08-28
- 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](/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()` |
`loginSdk` is the method the previous article called "GetTokenSdk". It is the same one.
## 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. 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" }'
```
The resulting token is the one passed to the `token` parameter of
[`Tilopay.Init()`](/developers/sdk/reference/init).
## Lifetime [#vigencia]
- **API token: 24 hours.**
- **SDK token: 1 hour.**
The exact value always arrives in `expires_in`. 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.tilopay.com/admin/checkout`. If you do not have access yet, start with
[developer registration](/developers/registro).
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](/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](/developers/registro).
2. **API authentication.** See [authentication](/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](/developers/api/procesos-operativos/errors) before declaring success.
- Configure [webhooks](/developers/api/webhooks) for the events you care about.
- If a call fails without a clear response, resolve the state with
[safe retries](/developers/reintentos-seguros).
## Environments [#entornos]
Testing and production share the same host. See
[environments](/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](/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 test field returned by Init().
- kind: concept
- status: stable
- api_version: v1
- last_verified: 2026-08-28
- url: https://tilopay.com/en/developers/entornos
**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 a **`test`** field:
| Value | Meaning |
|---|---|
| `0` | Production |
| `1` | Testing |
That is the only signal available at runtime. Read it and surface it in your own checkout
while developing.
## The real risk [#riesgo]
Because the host is the same, an integrator can believe they are testing while actually
being in production, taking real money. **Verify `test` before assuming the mode.** If your
integration moves money, make an unexpected `test: 0` fail loudly in your development
environments.
## 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-09-03
- 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 `test` field returned by `Init()`: 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` |
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 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-08-28
- url: https://tilopay.com/en/developers/reintentos-seguros
**The Tilopay 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-08-28
- 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]
**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 **four 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.
## 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](/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-10
- 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 |
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.
---
# 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-09-02
- url: https://tilopay.com/en/developers/api/convenciones
The acquiring API responses have three 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](/developers/api/procesos-operativos/errors).
## Amounts come as strings, not numbers [#montos-cadena]
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](/developers/api/recurrentes/cupones/get-coupon),
[list coupons](/developers/api/recurrentes/cupones/get-coupons),
[list plans](/developers/api/recurrentes/planes/get-plans) and
[subscriber payments](/developers/api/recurrentes/suscriptores/suscriptor-payments).
## There is a JSON payload inside a string [#doble-encoding]
In [subscriber payments](/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`](/developers/api/recurrentes/cupones/get-coupon) (one) | [`getRepeatCoupons`](/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](/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](/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.
---
# 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-08-29
- 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 · Tilopay Checkout](https://admin.tilopay.com/admin/checkout).
## Authentication [#autenticacion]
It does not require a token: this is the operation that issues it. See [authentication](/developers/api/autenticacion).
## Parameters [#parametros]
Merchant API user, obtained in Admin · Tilopay Checkout.
Merchant API password, obtained in Admin · Tilopay Checkout.
## 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
}
```
To interpret a response that is not a success, see [how to read an error response](/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-08-29
- 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](/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: to use it on the merchant side, write to `soporte@tilopay.com` for instructions.
Key associated with the customer. It is obtained in Admin · Tilopay Checkout.
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"
}
```
To interpret a response that is not a success, see [how to read an error response](/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-08-28
- url: https://tilopay.com/en/developers/server-to-server
**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]
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](/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).
The `shipTo*` fields (`shipToFirstName`, `shipToLastName`, `shipToAddress`, `shipToAddress2`,
`shipToCity`, `shipToState`, `shipToZipPostCode`, `shipToCountry`, `shipToTelephone`) appear in the
collection examples as shipping data.
### 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]
```json
{
"code": "1",
"description": "Transaccion aprobada",
"auth": "123456",
"orderNumber": "12345",
"urlRedirect": "",
"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](/developers/api/convenciones) and
[how to read an error response](/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](/developers/hosted-payment-page) — Tilopay hosts the form.
- [JavaScript SDK](/developers/sdk) — the form lives on your page, but the data travels from the
browser straight to Tilopay.
- [No code](/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](/developers/api/links-de-pago/create-link-payment)
- [Payment link detail](/developers/api/links-de-pago/detail-link-payment)
- [Delete a payment link](/developers/api/links-de-pago/delete-link-payment)
- [List payment links](/developers/api/links-de-pago/payment-item-list)
- [Get a payment link by id](/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](/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](/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](/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](/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](/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](/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](/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](/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](/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](/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](/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](/developers/api/recurrentes/planes) — 5
- [Subscribers](/developers/api/recurrentes/suscriptores) — 7
- [Coupons](/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](/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](/developers/api/recurrentes/planes/create-plan)
- [Edit recurring plan](/developers/api/recurrentes/planes/edit-plan)
- [Get a recurring plan](/developers/api/recurrentes/planes/get-plan)
- [List recurring plans](/developers/api/recurrentes/planes/get-plans)
- [Delete recurring plan](/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](/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-08-29
- 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](/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]
```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](/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-08-29
- 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](/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"
}
```
To interpret a response that is not a success, see [how to read an error response](/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](/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](/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-08-29
- 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](/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": ""
}
```
To interpret a response that is not a success, see [how to read an error response](/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](/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](/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](/developers/api/recurrentes/suscriptores/get-suscriptor-plan)
- [Edit subscriber](/developers/api/recurrentes/suscriptores/edit-suscriptor-plan)
- [Pause subscriber](/developers/api/recurrentes/suscriptores/pause-suscriptor-plan)
- [Reactivate subscriber](/developers/api/recurrentes/suscriptores/reactive-suscriptor-plan)
- [Delete subscriber](/developers/api/recurrentes/suscriptores/delete-suscriptor-plan)
- [Registration and renewal URL](/developers/api/recurrentes/suscriptores/consult-url)
- [Subscriber payments](/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](/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](/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](/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-08-29
- 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](/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, `yy-m-d` format.
## Request example [#request]
The `<...>` values are placeholders: replace them with your own credentials and data.
```json
{
"key": "",
"id": "2",
"status": "2",
"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](/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](/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](/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](/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](/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](/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](/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](/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](/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-08-29
- 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](/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"
}
```
To interpret a response that is not a success, see [how to read an error response](/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](/developers/api/recurrentes/cupones/create-coupon)
- [List coupons of a plan](/developers/api/recurrentes/cupones/get-coupons)
- [Get a coupon](/developers/api/recurrentes/cupones/get-coupon)
- [Delete coupon](/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](/developers/api/autenticacion).
---
# API · Create coupon
> Creation of discount coupons for recurring plans.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-08-29
- 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](/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
}
```
To interpret a response that is not a success, see [how to read an error response](/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-08-29
- 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](/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"
}
```
To interpret a response that is not a success, see [how to read an error response](/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-08-29
- 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](/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"
}
```
To interpret a response that is not a success, see [how to read an error response](/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-08-29
- 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](/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"
}
```
To interpret a response that is not a success, see [how to read an error response](/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](/developers/api/cof/process-tokenize) — 1
- [Remove card](/developers/api/cof/remove-card) — 1
- [Charge](/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](/developers/api/autenticacion).
---
# API · processTokenize
> Card tokenization with processTokenize: parameters, request and response.
- kind: api-operation
- status: stable
- api_version: v1
- last_verified: 2026-08-29
- 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](/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"
}
```
To interpret a response that is not a success, see [how to read an error response](/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-08-29
- 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](/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"
}
```
To interpret a response that is not a success, see [how to read an error response](/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-08-29
- 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](/developers/api/autenticacion).
## Parameters [#parametros]
Key associated with the customer. It is obtained in Admin · Tilopay Checkout.
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.
## 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"
}
```
To interpret a response that is not a success, see [how to read an error response](/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](/developers/api/procesos-operativos/process-modification)
- [consult](/developers/api/procesos-operativos/consult)
- [consultTransactions](/developers/api/procesos-operativos/consult-transactions)
- [Split settlement](/developers/api/procesos-operativos/split)
These operations are cross-cutting: they work for any of the four [integration paths](/developers), no matter how the charge was originated.
To interpret a response that is not a success, see [how to read an error response](/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](/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-08-29
- 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](/developers/api/autenticacion).
## Parameters [#parametros]
Example: `1214352`
Example: `2`
Example: `1.00`
Key associated with the customer. It is obtained in Admin · Tilopay Checkout.
## 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 of modification applied.
Transaction identifier.
Result code of the modification.
Result text.
Order hash. See the note about `orderHash` in [webhooks](/developers/api/webhooks#verificacion).
To interpret a response that is not a success, see [how to read an error response](/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-08-29
- 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](/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](/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](/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](/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-08-29
- 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](/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](/developers/api/procesos-operativos/errors).
---
# 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-08-28
- 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]
The only origin verification available is the `orderHash`, and **its algorithm is not public**:
it is delivered to merchants who request it 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]
`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: v2
- last_verified: 2026-08-28
- 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](/developers/registro).
2. **SDK token.** Your backend requests it with `POST /api/v1/loginSdk`. See
[authentication](/developers/api/autenticacion).
3. **Load the script.** See [installation](/developers/sdk/instalacion).
4. **Add the inputs with the contract ids** and the `responseTilopay` container. See
[form fields](/developers/sdk/campos-del-formulario).
5. **Start the purchase** with [`Tilopay.Init()`](/developers/sdk/reference/init) and show the
customer the payment methods it returns.
6. **Close the purchase** with
[`Tilopay.startPayment()`](/developers/sdk/reference/startpayment). The SDK handles 3DS and
renders the result on your `redirect` URL.
## Before assuming you are in test mode [#entornos]
Testing and production share one host: the mode is verified with the `test` field returned by
`Init()`. See [environments](/developers/entornos).
## 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-08-29
- 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 · Tilopay Checkout](https://admin.tilopay.com/admin/checkout).
## Authentication [#autenticacion]
It does not require a token: this is the operation that issues it. See [authentication](/developers/api/autenticacion).
## 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"
}
```
To interpret a response that is not a success, see [how to read an error response](/developers/api/procesos-operativos/errors).
---
# SDK installation
> The V2 SDK script tag, which versions exist, and which versioning guarantees do not exist.
- kind: guide
- status: stable
- sdk_version: v2
- last_verified: 2026-08-28
- 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.
## jQuery is not required [#jquery]
**jQuery is NOT required.** It was a leftover from SDK V1. The article published so far
said otherwise and it is wrong: you can install SDK V2 without jQuery on the page.
## Versions [#versiones]
There are only two versions:
| Version | Status |
|---|---|
| `v1` | Unsupported |
| `v2` | Current |
## What does not exist [#garantias]
**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.
## What is next [#que-sigue]
- [Form fields](/developers/sdk/campos-del-formulario) — the ids the SDK looks for.
- [`Tilopay.Init()`](/developers/sdk/reference/init) — start the purchase.
---
# Form fields
> The tlpy_* ids the V2 SDK looks for in your form, and the responseTilopay container it needs for 3DS.
- kind: concept
- status: stable
- sdk_version: v2
- last_verified: 2026-08-28
- 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.
**The contract is the inputs, not the containers.** You can name the `div` elements that
wrap the fields however you want: the SDK does not look for them. The only exception is
`responseTilopay`, which is required.
## 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. If the customer has no saved cards, hide it.
Card number.
Expiration date in month/year format, for example `01/25`.
Security code. When the customer uses a saved card, this field must be enabled so they can
type the CVV.
Required container, **outside the form**. 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()`](/developers/sdk/reference/init) or
[`updateOptions()`](/developers/sdk/reference/update-options).
## Example structure [#estructura]
The `div` elements in this example are free-form; the input `id`s and `responseTilopay` are
not.
```html
```
---
# SDK · Tilopay.Init()
> Starts a purchase: authenticates the checkout and returns the available payment methods and the customer's saved cards.
- kind: sdk-method
- status: stable
- sdk_version: v2
- last_verified: 2026-08-28
- 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, the SDK has a second start flow:
**`Tilopay.InitTokenize()`**, with the same parameters as `Init()` except `amount`,
`orderNumber`, `capture` and `subscription`, which do not apply because nothing is charged.
## Signature [#firma]
```js
await Tilopay.Init({ /* parameters */ })
```
## Parameters [#parametros]
SDK token, obtained with `POST /api/v1/loginSdk`. See
[authentication](/developers/api/autenticacion).
Purchase currency, ISO 4217.
Checkout **language**, ISO 639-1. Only `es` and `en` are supported; defaults to `es`.
Purchase amount.
Customer email. Required for the response to include saved cards.
Order number, unique per merchant. See
[safe retries](/developers/reintentos-seguros).
Customer identification type. Conditional. See the
[type table](/developers/sdk/reference/update-options#tipos-de-identificacion).
Customer identification number. Conditional.
Customer first name.
Customer last name.
Customer address line 1.
Customer address line 2. Optional.
City. Recommended.
State or province. Recommended.
Postal code. Recommended.
Country, ISO 3166-1 alpha-2. Recommended.
Customer phone. Recommended.
`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.
Yappy phone. Required when paying with Yappy. It is not read from the DOM.
Optional. Values `"V1"` or `"V2"`. If omitted, the final response hash is built with V1.
Optional. 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.
## Call [#llamada]
```js
const init = await Tilopay.Init({
token: sdkToken,
currency: "CRC",
language: "es",
amount: 100.0,
billToEmail: "cliente@ejemplo.com",
orderNumber: "ORD-2026-000123",
billToFirstName: "Ana",
billToLastName: "Rojas",
billToAddress: "Avenida 1, Local 2",
billToCountry: "CR",
capture: 1,
redirect: "https://ejemplo.com/checkout/respuesta",
subscription: 0,
});
```
## Response [#respuesta]
`Success`, or the error description.
`0` production, `1` testing. See [environments](/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()`](/developers/sdk/reference/get-sinpe-movil).
Array of `{id, name, type}` with the available payment methods.
Array of `{id, name, brand}` with the customer's saved cards.
## Payment method id format [#formato-id-metodo]
Each method `id` has the shape `A:B:C`. **The second segment defines the payment method, and
`18` corresponds to Yappy.**
## 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()`](/developers/sdk/reference/update-options).
---
# SDK · Tilopay.startPayment()
> Closes the purchase. The SDK handles the whole 3DS flow and renders the response on the redirect URL.
- kind: sdk-method
- status: stable
- sdk_version: v2
- last_verified: 2026-08-28
- url: https://tilopay.com/en/developers/sdk/reference/startpayment
Closes the purchase started with [`Tilopay.Init()`](/developers/sdk/reference/init).
## Signature [#firma]
```js
await Tilopay.startPayment()
```
It takes no parameters.
## 3DS: the SDK handles it [#tres-ds]
**The SDK handles the whole 3D Secure flow.** All you have to do is make sure the
`responseTilopay` container is on the page: that is where the SDK inserts what 3DS needs and
drives the process.
```html
```
See [form fields](/developers/sdk/campos-del-formulario#campos).
## Where the result arrives [#resultado]
When it finishes, the SDK renders the response on the URL given in the `redirect` parameter of
`Init()`. **That is the final purchase response**: treat the `redirect` URL as the point where
your application decides the outcome.
On error, the method returns the description:
```json
{
"message": "error description"
}
```
---
# Tilopay.getCardType()
> Returns the brand of the card the customer is typing, so you can show an icon while they type.
- kind: sdk-method
- status: stable
- sdk_version: v2
- last_verified: 2026-08-28
- 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`. The
typical use is showing the brand icon while the customer types.
## Signature [#firma]
```js
await Tilopay.getCardType()
```
It takes no parameters.
**Precondition:** the customer must have already typed the card number.
## Call [#llamada]
```js
const type = await Tilopay.getCardType();
```
## Response [#respuesta]
```json
{
"message": "visa"
}
```
The card brand.
## Supported brands [#marcas-soportadas]
VISA · MASTERCARD · AMEX
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 and activates the collection listener.
- kind: sdk-method
- status: stable
- sdk_version: v2
- last_verified: 2026-08-28
- 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 returns the data 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()`](/developers/sdk/reference/init).
**It is not just a getter.** Besides returning the data, this method **triggers the SINPE
listener with the Tilopay backend**. Calling it is part of the collection flow, not a
presentation detail.
## 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()`](/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 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]
**On error it returns nothing.** Do not expect an object with empty fields: treat the absence of
a response as the error case.
## What to do with this data [#que-hacer]
When SINPE Móvil is selected, hide the card fields and show the customer this data: destination
phone, exact amount and the code for the description.
**No pay button is needed:** the collection is processed when the transfer arrives.
---
# Tilopay.updateOptions()
> Partially updates the parameters sent to Init() when they change before closing the payment.
- kind: sdk-method
- status: stable
- sdk_version: v2
- last_verified: 2026-08-28
- url: https://tilopay.com/en/developers/sdk/reference/update-options
Updates values already sent in [`Tilopay.Init()`](/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.
**It is a patch.** Send only the fields you want to update; there is no need to resend everything.
## What "required" means here [#obligatorio]
In the list below, "required" means the field **must have been sent either in `Init()` or in
`updateOptions()`**. If it was never sent in either, the payment cannot proceed. It does not mean
you must resend it on every call.
## 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]
Customer identification type. Required for SINPE Móvil. See
[identification types](#tipos-de-identificacion).
Customer identification number. Required for SINPE Móvil. **Accepted with and without hyphens.**
Customer first name.
Customer last name.
Customer address line 1.
Customer address line 2. Optional.
Customer city. Recommended.
State or province. Recommended.
Postal code. Recommended.
Country, ISO 3166-1 alpha-2. Recommended.
Customer phone. Recommended.
`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. Required when the customer pays with Yappy.
**`billToEmail` cannot be updated after saved cards are obtained.** 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-09
- 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`, in `OUT` or `IN` direction.
[See payment operations](/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](/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](/developers/api-bancario/webhooks).
**Catalogs.** Customer identification person types per country.
[See catalogs](/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
```
You can start in sandbox and, when you are ready, we hand over your 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](/developers/api-bancario/autenticacion) — login, token exchange and Bearer.
2. [Conventions](/developers/api-bancario/convenciones) — envelope, correlation, safe retries, pagination and dates.
3. [Response codes](/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-09-02
- 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. |
| `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 | Token lifetime in seconds. |
| `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`.
## 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`. Repeat step 2 to renew the access token
before `expires_in` elapses.
## 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"
}
```
---
# 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-09-02
- 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](/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).
---
# 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-09-02
- 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.**
`direction` accepts `OUT` (outbound) and `IN` (inbound). **Destination account.** it is
identified by `IBAN` or by `PHONE`, depending on the method.
**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](/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`](/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 ledger UUIDs).
For PIN payments created after public identification persistence,
`identification.number` is the partner-submitted public number (no SINPE hyphens);
older payments may still show the hyphenated SINPE form. See `docs/PAYMENT-IDENTIFICATION.md`.
**Parameters**
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `X-Correlation-Id` | header | string | — | 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 | — | 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) | — | Inclusive lower bound for `created_at`. RFC 3339 (UTC `Z` or offset; optional fractional seconds). |
| `date_to` | query | string (date-time) | — | Inclusive upper bound for `created_at`. RFC 3339 (UTC `Z` or offset; optional fractional seconds). |
| `client_reference` | query | string | — | Filter by partner client reference (exact match against the value sent at payment creation). |
| `currency` | query | string | — | Filter by payment currency (ISO 4217, e.g. CRC). |
| `payment_method_code` | query | string | — | Filter by public payment method code. Values: PIN, SINPE_MOVIL |
| `direction` | query | string | — | 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 | — | Page size (default 20, max 100). |
| `cursor` | query | string | — | Opaque cursor from a previous response `pagination.next_cursor`. |
**200** — The request was processed successfully.
`response_code`: `OK`
Fields in `data`:
| Field | Type | Required | Description |
|---|---|---|---|
| `items` | array