Get started
Create a payment
You need an active merchant account, an sk_test_… secret key, and a default tax configured for your merchant. Store the key in TIMBRO_PAYMENTS_SECRET_KEY on your server only. Prepare your account if you have not done that yet.
Install the SDK in a project with Node.js 24.19 or later:
npm install @timbro/paymentsIn a server route that returns a Response:
import { createTimbroPayments } from "@timbro/payments";
const timbro = createTimbroPayments({ apiKey: process.env.TIMBRO_PAYMENTS_SECRET_KEY! });
export async function POST() { const payment = await timbro.payments.create({ paymentReference: "order-123", amount: { currency: "DOP", value: "1250.00" }, description: "Maintenance service", returnUrl: "https://merchant.example/orders/123", }); return Response.redirect(payment.checkout.url);}Install the SDK in a project with Python 3.11 or later:
pip install timbro-paymentsThis program creates the payment and prints the Checkout link where the customer pays. TimbroPayments is the synchronous client, which ERPs usually use:
import os
from timbro_payments import TimbroPayments
with TimbroPayments( api_key=os.environ["TIMBRO_PAYMENTS_SECRET_KEY"], application="my-erp/1.0") as timbro: payment = timbro.payments.create({ "paymentReference": "order-123", "amount": {"currency": "DOP", "value": "1250.00"}, "description": "Maintenance service", "returnUrl": "https://merchant.example/orders/123", }) print(payment["id"], payment["checkout"]["url"])application is optional: it adds your integration’s name and version to the User-Agent header. Requests and responses are dictionaries with the API’s field names, and amounts are strings.
If your server uses asyncio, AsyncTimbroPayments has the same methods. await each call:
import asyncioimport os
from timbro_payments import AsyncTimbroPayments
async def main() -> None: async with AsyncTimbroPayments(api_key=os.environ["TIMBRO_PAYMENTS_SECRET_KEY"]) as timbro: payment = await timbro.payments.create({ "paymentReference": "order-123", "amount": {"currency": "DOP", "value": "1250.00"}, "description": "Maintenance service", "returnUrl": "https://merchant.example/orders/123", }) print(payment["id"], payment["checkout"]["url"])
asyncio.run(main())The Python examples in the other guides use the synchronous client.
amount is the total, including tax. Use a different reference for each collection request and keep it the same when retrying. Save the payment id with the order.
Checkout stays open for 30 minutes with a returnUrl and 1 hour without one. To change that, send expiresAfterSeconds with a value from 300 to 86400 seconds, and read the deadline from expiresAt on the payment. A POS, for example, sends 600. More about the window.
These windows apply to ordinary payments. The first payment for a Subscription has a fixed 24-hour window; when it expires, the Subscription is terminal, so create another one with a new subscriptionReference. Automatic payments start with both expiresAt and checkout.expiresAt set to null. Timbro sets a 7-day deadline when the email provider accepts the pending payment notice. Do not show a countdown while the deadline is null, and resending the notice does not extend a deadline that is already set.
Use HTTP directly
curl https://api.timbro.do/v1/payments \ -H "Authorization: Bearer $TIMBRO_PAYMENTS_SECRET_KEY" \ -H "Content-Type: application/json" \ -d '{ "paymentReference": "order-123", "amount": { "currency": "DOP", "value": "1250.00" }, "description": "Maintenance service", "returnUrl": "https://merchant.example/orders/123" }'The response includes id and checkout.url. You do not need to send an idempotency key for this operation.
Confirm the payment
Section titled “Confirm the payment”Returning to returnUrl in the browser does not confirm the payment. Retrieve the payment from your server and apply the payment once when its status is succeeded. Use webhooks to receive the notification even if the customer closes the tab.
This example creates a payment without an invoice. If the sale needs an invoice, choose how to integrate your system.