Changelog
Every new API version is listed here with what changed in it, newest first. A change that can break an integration comes only with a new version, and your integration stays on its own version until you move it.
A change to our IP addresses is announced here at least 7 days ahead, and by email to your developers.
2026-10-25.acacia
- Payments: a payment no longer has verification, and the payment.verified event is no longer sent: whether a bank's statement showed a payment's money is ours to check. Credit amount_credited on payment.succeeded.
- Webhook endpoints: payment.verified is taken out of the event types an endpoint listens to, and is no longer one you can pick: the portal does not offer it, and novaro listen --events payment.verified is refused. One that listened to it alone stays as it is and is sent nothing: pick other event types for it. A payment.verified delivery still waiting is canceled; events already sent stay in GET /events for their 30 days.
2026-10-24.acacia
- Payouts: POST /payouts sends money from your available balance to a bank account you name: in Argentina destination { type cvu | cbu | alias, and that field }, with recipient.tax_id optional. The amount and the payout fee of your agreement are held at once; the payout is pending, then processing, and ends paid or failed (failure_code says why; the amount and fee come back), or requires_review while we check an unknown outcome. Idempotency-Key required; more than available is 400 balance_insufficient. GET /payouts and /payouts/{id} read your account's payouts; POST /payouts/{id}/cancel cancels a pending one (409 payout_not_cancelable once it is being sent or ended). Test mode only for now: a live key is 409 payouts_not_available, and a test payout's amount takes it to paid, failed or requires_review (magic amounts, see Payouts › Test mode).
- Events: payout.created, payout.paid, payout.failed, payout.requires_review and payout.canceled carry the payout; in test mode, magic amounts send each of them.
2026-10-23.acacia
- Payments: our hosted page shows an ar_bank_transfer payment, in Spanish. POST /payments takes checkout with it; customer.tax_id is then optional, and the page asks the payer for their DNI, CUIT or CUIL before it shows where to pay. Its display_bank_transfer_instructions.hosted_instructions_url is the page's URL, as a UPI payment's is; it was null.
2026-10-22.acacia
- Payments: in Argentina, POST /payments takes payment_method_data.type ar_bank_transfer, a transfer in ARS from the payer's bank or wallet. Its next_action is display_bank_transfer_instructions { type ar_bank_transfer, amount_remaining, currency, financial_addresses, hosted_instructions_url }: the CVU ({ type cvu, cvu: { cvu } }) and its alias ({ type alias, alias: { alias } }, when there is one) to transfer the exact amount to; hosted_instructions_url is null for now. It needs customer.tax_id: without it, 400 parameter_missing with param customer.tax_id. Our hosted page does not show transfers yet: with checkout, 400 parameter_invalid with param checkout.
- Payments: an ar_bank_transfer amount is whole pesos, a multiple of 100 centavos; one with centavos is 400 amount_not_whole with param amount. A UPI amount is unchanged.
- Payments: POST /payments/{id}/confirmations takes coelsa_id, the operation number on an Argentine transfer's receipt, for a payment whose confirmation_fields name it; utr is a UPI payment's.
- Payments: next_action carries only its type's details: a UPI payment's has upi_display_details and no display_bank_transfer_instructions key, as before.
2026-10-21.acacia
- Payments: POST /payments takes the customer's tax id, customer.tax_id { type, value }, in markets whose payments take one (Argentina): ar_cuit or ar_cuil, 11 digits with a check digit, or ar_dni, 7 or 8 digits. A CUIT or CUIL whose check digit fits another of a person's prefixes (20, 23, 24, 27) is taken as its DNI; any other number that is not one is 400 tax_id_invalid, a tax_id without its type or value 400 parameter_missing, another type 400 parameter_invalid, and a well-formed one sent where payments take none 400 parameter_unknown.
2026-10-20.acacia
- Balance: GET /balance reads your balance on your key's market, per currency: available (what you can pay out or settle now), pending (deposits not available yet) and reserved (held for pending payouts and settlements). All your merchant accounts on the market share it, and any of their keys reads it; a test key reads the test environment's, livemode false.
- Settlements: POST /settlements requests a settlement of your balance in USDT on TRON, live keys only, with an Idempotency-Key: 201 with the settlement pending, its amount reserved from your available balance; a retry with the key answers it again and reserves nothing more. A test key is 409 livemode_only; more than available 400 balance_insufficient; another request of yours still pending 409 settlement_request_pending; no default payout address 409 payout_address_missing; an address not active 400 payout_address_not_active; an amount that comes to no USDT 400 amount_too_small; no settlement terms on your agreement yet 409 settlement_terms_missing. GET /settlements lists your settlements on the market, yours and those our team made (origin novaropay), newest first, filtered by status and created; GET /settlements/{id} reads one.
- Payout addresses: GET /payout_addresses lists your active payout addresses, the default first. They are still added, made default and blocked in the merchant portal only.
- Events: the settlement in settlement.* events is the API's settlement object, which adds exchange_rate, usdt_amount and payout_address { id, network, asset, address }, with the values of rate, usdt and address (which stay), and origin, fee_fixed_usdt, tronscan_url, description and livemode. settlement.created is sent for a settlement you request, as for one our team makes.
2026-10-19.acacia
- Payments: POST /payments/{id}/confirmations with the UTR of the bank transaction that paid the payment answers 200 with the payment and records nothing, as the same value sent again does, after the payment succeeded too; it was 409 payment_final. Any other value on a payment that succeeded or failed is still 409 payment_final.
- Payments: a payment has amount_paid (what arrived from the payer's bank), amount_credited (what to credit your customer: the amount you asked for when the payer paid exactly amount_payable, else amount_paid; amount_received is the same amount), amount_mismatch (the payer paid other than amount_payable) and verification (unverified, or verified once the bank's statement shows the money), each null until the payment succeeded; webhook events' data.object has them as at the event.
- Events: payment.verified, when the bank's statement shows a succeeded payment's money; its verification is verified. Sent whether the statement came after an SMS or was the first to show the money. In test mode a test payment a UTR succeeded is verified 5 seconds later.
- Events: settlement.created, settlement.updated, settlement.paid and settlement.canceled, when a settlement of your balance is made, changed before it is sent, sent (its tx_hash is the TRON transfer) or canceled. data.object is the settlement: id, status, market, amount and fee in the market's currency, rate, usdt in micro-USDT, address, tx_hash, cancel_reason, created, paid_at, canceled_at and version. Each of your accounts on the market gets them.
- Events: a paid settlement taken back sends settlement.updated with status reversed and reversed_at: its amount is back in your balance. reversed_at is null on every other settlement.
2026-10-16.acacia
- Events: POST /events/{id}/retry with webhook_endpoint (whe_…) sends an event to one of your webhook endpoints again, now: one more attempt of its delivery there, as Resend in the merchant portal, answered with the event. The endpoint must have been sent the event and be turned on; one turned off is 400 parameter_invalid, and an event not sent to it 404 resource_missing naming webhook_endpoint. The automatic retries of a delivery still failing go on as they were. It takes no Idempotency-Key: the same request again sends the event once more.
- CLI keys may also resend an event (novaro events resend). Coming with the novaro CLI: novaro listen forwards your test-mode events to a server on your machine, ready with the latest API version on --latest, and novaro trigger makes them happen; see Test webhooks locally with the CLI.
2026-10-14.acacia
- Test mode is open: an sk_test_ key works on the same host as a live one, in a test environment of its market with its own keys and payments (livemode false), magic UTRs and no real money; a market with no test environment answers its test keys 404 resource_missing. Test keys created before keep their secret. Try it in the API reference sends test requests with a pasted test key.
- Events: GET /events lists your account's events of the last 30 days, newest first, filtered by type (payment.* for a resource's every type), created and delivery_success; GET /events/{id} reads one. An event has data.object, the object right after it, previous_attributes for payment.instructions_updated, request and pending_webhooks. The events are kept 30 days and sent to the webhook endpoints that listen to their type, signed with PSP-Signature, with retries. Webhook endpoints are set up in the merchant portal (its Webhooks page is coming soon; until then, your account manager sets them up).
- CLI keys (coming with the novaro CLI): novaro login makes an rk_test_ key, allowed by someone of your account in the merchant portal: test mode only, 90 days, never rotated; it may read events and create, read and confirm payments, and any other call is 403 api_key_permission.
- Payments: a payment has version, which grows with every change of it: of two copies of a payment, the one with the higher version is the newer, and a webhook event's data.object has the version of that event.
- Payments: send traffic_type on POST /payments, ftd for a customer's first deposit with you or std for a subsequent one; ftd when left out, any other value, the empty one too, 400 parameter_invalid. Every payment carries traffic_type, and GET /payments filters by it. A type turned off on your account is 400 traffic_type_disabled, and nothing is made; payments made before keep going.
2026-10-01.acacia
- The first version. Payments: retrieve a payment with GET /payments/{id}; a payment of another account is 404 resource_missing.
- Payments: create a payment with POST /payments, answered 201 with the details to pay to; metadata is kept and answered back. An Idempotency-Key is required: a retry with it gets the first answer and the header Idempotent-Replayed, another body under it is 400 idempotency_error, and while the first runs 409 idempotency_key_in_use.
- Payments: list your payments with GET /payments, newest first, a page at a time (limit, starting_after, ending_before; see Pagination), filtered by merchant_reference, customer_id, status and created[gt|gte|lt|lte]; an unknown cursor is 404 resource_missing.
- A request's parameters, in its body or its query, are checked as Stripe checks them: parameter_unknown, parameter_missing and parameter_invalid name the parameter; an amount outside the limits is amount_too_small or amount_too_large, naming the limit; a method not available is method_not_enabled; a merchant reference used before is 409 merchant_reference_already_used; and 503 temporarily_unavailable creates nothing.
- Payments: the limits of an amount are the method's in your market, which may be narrower than the method allows elsewhere, and your account's own; outside either, POST /payments answers amount_too_small or amount_too_large with the limit, and no payment is made.
- PSP-Version: every response names the version it ran in, your account is pinned to the current version on its first request, and an unknown version is 400 invalid_api_version.
- A working key refused for its account's or market's state is 403 account_inactive or market_not_enabled; a wrong key stays 401. Test keys work only in test mode.
- A key that was revoked, or replaced by a rotation whose expiry has passed, is 401 api_key_expired with the key's prefix in the message, from any address; a wrong key stays 401 with no code.
- Payments: send checkout with a return_url to show the payer our hosted payment page: the payment has channel hosted and checkout { url, status, opened_at }, the page on your account's checkout domain. A return_url off your account's return hosts is 400 return_url_not_allowed; an account with no checkout domain is 503 checkout_unavailable, and nothing is made.
- Payments: every payment has channel (h2h or hosted), and its UPI details the hosted page with them, hosted_instructions_url, and qr_code { data, image_url_svg, image_url_png }; the URLs are null while your account has no checkout domain.
- Payments: upi_uri carries pn, the name the VPA is registered under, and the UPI details list app_links [{ app, url }], links that open Paytm and PhonePe on the same details with the amount and the note locked where the app allows it: every app we have not switched off for your market because its link broke, [] with no VPA.
- Payments: confirm a payment with what its payer told you, POST /payments/{id}/confirmations with the fields its confirmation_fields name (utr in India): 200 with the payment, processing if it waited for the payer, never succeeded; the same value again answers it again. A value confirmed on another payment is 409 reference_already_used, a payment that succeeded or failed 409 payment_final, a method with no confirmation fields 400 confirmation_not_supported. A payment processing on your confirmation alone fails if no money is seen 24 hours after it.
- Payments: the UPI details of a payment waiting for the payer may change, and with them its amount_payable when your account matches payments by amount, its reference code kept: the payer asked the hosted page for others, or we moved the payment to better details within a minute of its creation. GET /payments/{id} reads the current ones; money sent to the earlier details still pays the payment.
- Test mode: a test key may send at most 25 requests a second, and an account 100 over all its test keys; a request over either is 429 rate_limit, type rate_limit_error, with a Retry-After header in seconds, and nothing runs. Live mode has no such limit.
- Hosted page: the page goes back to return_url as you sent it, with nothing added, and the payment's status says what happened; in a frame on your account's embed hosts it posts { type: "psp.checkout", status, height } to the frame's page and does not go back by itself; in a WebView it hides the app buttons until your app opens their links and the account's option is on. The guide Hosted payment page covers all three.