Create Credit Top-up Purchase
curl --request POST \
--url https://api.nozle.app/engine/api/v1/credit-top-up-purchases \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.nozle.app/engine/api/v1/credit-top-up-purchases"
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, headers=headers)
print(response.text)const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.nozle.app/engine/api/v1/credit-top-up-purchases', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.nozle.app/engine/api/v1/credit-top-up-purchases"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}require 'uri'
require 'net/http'
url = URI("https://api.nozle.app/engine/api/v1/credit-top-up-purchases")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.nozle.app/engine/api/v1/credit-top-up-purchases",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}HttpResponse<String> response = Unirest.post("https://api.nozle.app/engine/api/v1/credit-top-up-purchases")
.header("Authorization", "Bearer <token>")
.asString();Product Credits
Create Credit Top-up Purchase
Start checkout for a fixed product-credit package
POST
/
engine
/
api
/
v1
/
credit-top-up-purchases
Create Credit Top-up Purchase
curl --request POST \
--url https://api.nozle.app/engine/api/v1/credit-top-up-purchases \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.nozle.app/engine/api/v1/credit-top-up-purchases"
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, headers=headers)
print(response.text)const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.nozle.app/engine/api/v1/credit-top-up-purchases', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.nozle.app/engine/api/v1/credit-top-up-purchases"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}require 'uri'
require 'net/http'
url = URI("https://api.nozle.app/engine/api/v1/credit-top-up-purchases")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.nozle.app/engine/api/v1/credit-top-up-purchases",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}HttpResponse<String> response = Unirest.post("https://api.nozle.app/engine/api/v1/credit-top-up-purchases")
.header("Authorization", "Bearer <token>")
.asString();Base URL:
All three fields are required. Unknown fields return
Core checks the customer’s payment provider before it creates anything. A provider error leaves no invoice, no purchase, no
https://api.nozle.app/engine/api/v1.
Auth: secret key only. The key requires credit_system:write. Publishable keys are rejected. Idempotency-Key is required and must not exceed 255 bytes.
{
"customer_id": "customer_123",
"credit_system_code": "ai_credits",
"top_up_package_code": "starter_pack"
}
400.
The Engine forwards the request to Nozle Core and returns Core’s status and body unchanged. The body is { "credit_top_up_purchase": { ... } }. The response returns the pending purchase snapshot and hosted payment_url. Navigate the same page to that URL. For a customer on Stripe, payment_url is a Stripe-hosted checkout.stripe.com page that is valid for 24 hours, and the customer must already be linked to a Stripe customer. For a customer on Razorpay, payment_url is an rzp.io payment link, payment_provider is razorpay, and the package must be priced in INR. The purchase object carries payment_status. A Razorpay top-up has no checkout ID to poll.
Creating checkout does not grant credits. Credits are materialized once the top-up invoice is fully paid, by any route: a card or provider payment, a manual payment for the full amount, a payment request, or marking the invoice paid. A partial manual payment grants nothing until the invoice is fully paid.
Errors
| Status | Code | Cause |
|---|---|---|
400 | none; {"error": "invalid request body"} | The body is not valid JSON or has an unknown field. |
400 | none; {"error": "customer_id, credit_system_code, and top_up_package_code are required"} | A required field is missing. |
400 | none; {"error": "a valid Idempotency-Key header is required"} | Idempotency-Key is missing or over 255 bytes. |
502 | none; {"error": "failed to reach billing service"} | The Engine could not reach Core. |
422 | validation_errors with customer_currency_mismatch in error_details.currency | The customer has a currency that differs from the package currency. |
422 | validation_errors with razorpay_requires_inr | A Razorpay customer and a package that is not priced in INR. |
422 | validation_errors with no_linked_payment_provider | The customer has no payment provider. |
422 | validation_errors with invalid_payment_provider, missing_payment_provider or missing_payment_provider_customer | The customer’s payment provider cannot take the payment (for example GoCardless), or the customer has no link to a provider customer. |
invoice.one_off_created webhook or email, and the customer’s currency stays unset, so retrying with a new Idempotency-Key after such an error creates nothing. A successful purchase is recorded in the activity log as credit_top_up_purchase.created, and its finalized one-off invoice as invoice.one_off_created.