top of page

Choose the correct recipe contract

Classic sale/refund and REST recurring examples are different protocols.

Classic sale and refund

The source sale/refund recipes call /api/transact.php with form encoding and security_key in the body. They do not use the REST Authorization header. Use type=sale with payment_token and amount, or type=refund with the original transactionid and refund amount. # Server-side Classic request; placeholders are not live credentials. curl --request POST 'https://sandbox.nmi.com/api/transact.php' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode "security_key=$NMI_PRIVATE_KEY" \ --data-urlencode 'type=refund' \ --data-urlencode 'transactionid=REPLACE_WITH_ORIGINAL_TRANSACTION_ID' \ --data-urlencode 'amount=1.00'

Decode the real response

The recipes show {success:true} as an example, but Classic gateway replies use transaction-result fields. Treat success as your application’s normalized response only. The source sale cURL also has broken continuation lines; the corrected request above is not a literal copy. Payment outcome codes Refund recipe

REST recurring

The recurring recipe calls /api/v5/subscriptions with JSON and Authorization. Its plan_details example combines plan_id and plan fields and uses a historical start date. Choose the documented existing-plan or inline-plan contract rather than assuming every sample field belongs together. Subscription reference Recurring recipe

Frontend handoff

The source uses NmiPayments from @nmipayments/nmi-pay-react or mountNmiPayments from @nmipayments/nmi-pay. onPay sends a token to your server and returns true or an error message. Derive amount from the server order, not an editable browser field. A frontend {success:true} response must reflect a verified backend outcome. Frontend recipe Server sale recipe

Join the community and get the latest biz news & tips

Thanks for submitting!

© 2025 Betterpay. All Rights Reserved.

bottom of page