Mono Colombia

Templates

The reusable definition of how money gets into a subaccount.

A template answers one question: how do payments get into this subaccount? You create it once — like opening a collection point for a wallet, a campaign, or a customer — and it stays there as the standing definition of what you expect to receive. Payers pay, and every payment is checked against the template before it becomes a payin.

You never handle the money in a template: it is pure configuration. The money arrives later, as payins created against it.

Creation is idempotent on external_id: repeating the request returns the existing template instead of creating a duplicate.

What a template can do

A template is the most capable entity in payins. Everything below is optional beyond the basics — each capability has its own section or page:

  • Receive one payment or manyusage_mode (single use or multiple use).
  • Serve top-ups or collectionstype (top-up or collection).
  • Issue what the payer pays to — the payment token of each accepted method; for Bre-B, a key and an optional QR.
  • Bound the amounts — per payin and cumulative (limits and counters).
  • Restrict who may payexpected_payers.
  • Host intents — with per-intent keys, so each payment is pre-identified.
  • Configure every payin it produces — crediting trigger, metadata, and fee overrides (inherited configuration).
  • Offer a checkout — integrate API-only with your own UI, or use Mono's hosted checkout, pointed at one of your brands and asking for the extra fields you need (hosted checkout or API-only).
  • Track its own progresspaid_amount, pending_amount, and the successful_payins / failed_payins counters.
  • Expire and clean up after itself — expiration (as a date expires_at or a duration expires_in, mutually exclusive on creation) and pruning.

Top-up or collection

The type field declares the template's purpose:

TypePurposeTypical case
topupAn end user loads money into their own subaccount.Wallet recharge with a permanent key.
collectionYour business collects money from customers into a subaccount. Default.Checkout, invoicing, donations.

Single use or multiple use

usage_mode defines how many payments the template accepts:

  • single_use — exactly one successful payin. The first payment moves the template to paid, and a paid single-use template is closed history: it cannot be updated or reopened.
  • multiple_use — any number of payins, bounded only by the cumulative totals (below) and the expiration.

Lifecycle

  • created — the template was accepted and persisted, but its payment tokens are still being set up, so it cannot receive payments yet. The setup is asynchronous: for Bre-B with key_per: "template" (the default), the template waits in created until the network confirms the key.
  • ready — the template can receive payments. payment_tokens carries one entry per accepted method that issues a token — for Bre-B, the key and the QR when requested. Methods that need no token have no entry there.
  • minimum_paid — the cumulative paid_amount reached total_minimum_amount. The template keeps accepting payments up to total_maximum_amount. An update that raises the minimum above what is already paid moves it back to ready.
  • paid — the cumulative maximum was reached, or the single_use template received its payment. A multiple_use template can reopen (back to ready or minimum_paid) if an update raises or removes total_maximum_amount.
  • discarded — the template was pruned (expiration or inactivity) or deleted, and its payment tokens were torn down. prune_reason explains which.
  • failed — the payment-token setup exhausted its retries (for example, the Bre-B key registration failed). state_reason explains why.

Every reason behind a failed or discarded template is in Template errors.

State transitions caused by an update (raising or lowering the totals) travel inside the payin_template_updated webhook with the previous values — the separate state webhooks are not sent for them. All other transitions emit their own webhook.

Amount limits and counters

Two pairs of limits, all denominated in the template's currency:

FieldScopeEffect
minimum_payin_amount / maximum_payin_amountEach payinA payment outside the range is rejected (amount_below_minimum / amount_exceeds_maximum).
total_minimum_amount / total_maximum_amountCumulativeDrive the minimum_paid and paid states.

The template also keeps running counters: paid_amount (cumulative collected), pending_amount (authorized, in flight), and the successful_payins / failed_payins counts.

Restricting who can pay

expected_payers is an optional list of identity documents (type and number). When set, only those payers can pay the template — a payment from anyone else is rejected with payer_not_allowed. For Bre-B, the payer's document arrives with the payment itself, so the check needs nothing from the payer beyond paying from their own bank.

Per-method configuration

method_params carries the configuration of each accepted method. For co_breb: whether to generate a QR (create_qr), a custom key alias (custom_key_value), whether the key is minted per template or per intent (key_per), and the QR merchant data. The details live in Payment tokens and Bre-B.

Configuration inherited by every payin

payin_data holds settings that every payin created from the template inherits:

  • subaccount_disbursement_trigger — when the subaccount is credited: on_approval (as soon as the provider approves) or on_funds_delivery (when the money reaches its destination account). See Crediting the subaccount.
  • metadata — attached to every payin, for your own reconciliation.
  • fee_override — per-template fee overrides. See Fees.
  • redirect_url — where the payer returns after paying on the hosted checkout. See Hosted checkout or API-only.

An intent created from the template can override these values for its own payin.

Hosted checkout or API-only

A template supports two integration modes for the payer-facing side:

  • API-only (available today) — your product owns the whole payer experience: you read the payment token from the template or intent and render the key or QR in your own app, page, or receipt. Every flow in these guides works this way.
  • Mono-hosted checkout (in development) — Mono serves the payment page for you: a hosted checkout where the payer completes the payin, rendered with the brand the template points at. This is being built; no dates or scope are committed here. Nothing the checkout will do is blocked today: everything it will offer is already possible API-only.

The contract already carries the hosted-checkout fields, so you will not need a schema change when it arrives:

FieldOnWhat it is
checkout_urlTemplate (response)The hosted checkout URL of the template. Always null today.
urlIntent (response)The hosted page where the payer completes that specific intent. Always null today.
redirect_urlpayin_dataWhere the payer is redirected after completing a payin on the hosted checkout. If omitted, Mono's default voucher page is used.
form_customizationTemplateHow the checkout is customized for this template: the brand it renders with, and the extra fields it asks the payer to fill.

redirect_url and form_customization only take effect on the hosted flow: both are accepted and stored today, with no visible effect until the checkout ships.

What form_customization carries

Two things, and neither of them is the branding itself:

FieldTypeWhat it is
brand_idstring | nullThe brand the checkout renders with for this template. null means the checkout falls back to its default presentation.
custom_fieldsarray | nullThe fields the checkout asks the payer to fill beyond the amount — an ordered list, not a free-form object.

The whole form_customization object comes back null when the template has neither a brand nor custom fields.

Each entry in custom_fields is a typed field:

PropertyWhat it does
labelThe field name the payer sees. Required.
typeWhat the payer writes: text (default), number, boolean, or date.
default_valueValue shown pre-filled in the form.
requiredWhether the payer must fill it. Defaults to false.
editableWhether the payer can change the pre-filled value. Defaults to true.
{
  "form_customization": {
    "brand_id": "cpitplb_5tgliBmzjZ6mpQPRbQjfKj",
    "custom_fields": [
      {
        "label": "Order number",
        "type": "text",
        "default_value": "ORD-1042",
        "editable": false
      },
      { "label": "Delivery date", "type": "date", "required": true }
    ]
  }
}

Brands

A brand is the reusable look your hosted checkout wears: a name, the text on the pay button, an accent color, a logo, and the message shown on the voucher after paying. It belongs to you, not to a single template — many templates can point at the same brand, and changing the brand changes all of them at once. One of your brands is the default, used when a new template does not name one.

Brands are managed today from the Core Dashboard, not through the API: brand_id is the only part of them that appears in the payins contract, and it is a reference to a brand that already exists on your client. Brands are resolved within your own scope, so a brand_id that is not yours is rejected.

Updating and deleting

Updates are presence-aware: an omitted field keeps its value, an explicit null clears a nullable one. payin_data and form_customization are merged field by field, but a field holding a list is replaced whole — sending custom_fields swaps the entire list, there is no per-field merge inside it, and the same goes for expected_payers. Setting form_customization to null clears the custom fields and unlinks the brand. custom_merchant_name is fixed at creation and cannot be updated. A template cannot be updated while still created, once discarded or failed, as a consumed single-use template, or while being pruned. Every successful update emits payin_template_updated with the previous values of the changed fields.

Deletion is a soft delete: the template stops accepting payins and its external_id is freed for reuse. It is only allowed when the template holds no money — paid_amount and pending_amount both zero — and is not in created, discarded, or failed state.

Pruning

Templates do not live forever: a daily sweep retires the ones that are done — expired, inactive, or deleted — and hands their payment tokens back to the provider. Which rules fire, the grace periods you can configure, and what the payin_template_discarded webhook means for your integration are covered in Pruning.

Data model

The full schema, request and response shapes live in the Templates API reference.

Next steps

On this page