Credit Notes
Create Credit Note
Create a credit note against an invoice
POST
/
v1
/
credit-notes
Create a credit note
curl --request POST \
--url https://billing.example.com/v1/credit-notes \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"customer_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"amount": 123,
"currency": "<string>",
"invoice_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"reason": "<string>",
"type": "adjustment",
"expires_at": "2023-11-07T05:31:56Z"
}
'import requests
url = "https://billing.example.com/v1/credit-notes"
payload = {
"customer_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"amount": 123,
"currency": "<string>",
"invoice_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"reason": "<string>",
"type": "adjustment",
"expires_at": "2023-11-07T05:31:56Z"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
customer_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
amount: 123,
currency: '<string>',
invoice_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
reason: '<string>',
type: 'adjustment',
expires_at: '2023-11-07T05:31:56Z'
})
};
fetch('https://billing.example.com/v1/credit-notes', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://billing.example.com/v1/credit-notes",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'customer_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'amount' => 123,
'currency' => '<string>',
'invoice_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'reason' => '<string>',
'type' => 'adjustment',
'expires_at' => '2023-11-07T05:31:56Z'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://billing.example.com/v1/credit-notes"
payload := strings.NewReader("{\n \"customer_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"amount\": 123,\n \"currency\": \"<string>\",\n \"invoice_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"reason\": \"<string>\",\n \"type\": \"adjustment\",\n \"expires_at\": \"2023-11-07T05:31:56Z\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://billing.example.com/v1/credit-notes")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"customer_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"amount\": 123,\n \"currency\": \"<string>\",\n \"invoice_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"reason\": \"<string>\",\n \"type\": \"adjustment\",\n \"expires_at\": \"2023-11-07T05:31:56Z\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://billing.example.com/v1/credit-notes")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"customer_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"amount\": 123,\n \"currency\": \"<string>\",\n \"invoice_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"reason\": \"<string>\",\n \"type\": \"adjustment\",\n \"expires_at\": \"2023-11-07T05:31:56Z\"\n}"
response = http.request(request)
puts response.read_body{
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"tenant_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"customer_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"invoice_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"entity_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"reference": "<string>",
"amount": 123,
"subtotal": 123,
"tax_amount": 123,
"igst_amount": 123,
"cgst_amount": 123,
"sgst_amount": 123,
"tax_type": "<string>",
"hsn_code": "<string>",
"balance": 123,
"currency": "<string>",
"status": "issued",
"reason": "<string>",
"expires_at": "2023-11-07T05:31:56Z",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"customer": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"tenant_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"email": "jsmith@example.com",
"name": "<string>",
"phone": "<string>",
"tax_id": "<string>",
"billing_address": {
"line1": "<string>",
"line2": "<string>",
"postal_code": "<string>",
"city": "<string>",
"state": "<string>",
"zip": "<string>",
"country": "<string>"
},
"ledger_account_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"gstin": "<string>",
"tax_type": "<string>",
"place_of_supply": "<string>",
"tax_exempt": true,
"tax_exemption_number": "<string>",
"tax_exemption_code": "<string>",
"tax_exemption_expires_at": "2023-12-25",
"referral_code": "<string>",
"risk_score": 50,
"risk_factors": {},
"card_brand": "<string>",
"card_last4": "<string>",
"card_exp_month": 123,
"card_exp_year": 123,
"card_token_id": "<string>",
"card_fingerprint": "<string>",
"created_at": "2023-11-07T05:31:56Z"
}
}
}{
"error": {
"code": "BAD_REQUEST",
"message": "<string>"
}
}{
"error": {
"code": "BAD_REQUEST",
"message": "<string>"
}
}Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
invoice_id | string | Yes | The invoice ID to issue the credit note against |
amount | integer | Yes | Credit amount in smallest currency unit |
reason | string | Yes | Reason for the credit note |
Example Request
curl -X POST https://api.recurso.dev/v1/credit-notes \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"invoice_id": "inv_001",
"amount": 2500,
"reason": "Service downtime on 2024-03-12"
}'
Response
{
"id": "cn_r4t8w1",
"object": "credit_note",
"invoice_id": "inv_001",
"customer_id": "cust_abc123",
"status": "issued",
"currency": "INR",
"amount": 2500,
"amount_remaining": 2500,
"reason": "Service downtime on 2024-03-12",
"credit_note_number": "REC-CN/2024/0012",
"created_at": "2024-03-15T11:00:00Z"
}
The credit note amount cannot exceed the original invoice total. The
amount_remaining decreases as the credit is applied to future invoices.Errors
| Status | Code | When | Fix |
|---|---|---|---|
400 | validation_failed | Malformed body: customer_id, positive amount, and currency are required; type must be adjustment or refund | Correct the payload (amount is minor units, > 0) |
400 | validation_failed | Customer doesn’t exist or belongs to another tenant | Check the customer_id |
400 | validation_failed | Refund rules broken: a refund note requires invoice_id; the invoice must be paid, belong to the customer, and match the note’s currency | Issue refunds only against the customer’s paid invoices, in the invoice currency |
400 | validation_failed | Refund amount exceeds what’s still refundable on the invoice (paid amount minus prior refunds) | Lower the amount — cumulative refunds can’t exceed what was paid |
500 | internal_error | Unexpected failure persisting the note | Retry; contact support if it persists |
pending and needs approval. Errors
use the standard envelope — see Errors.Authorizations
Tenant API key obtained from POST /auth/register or POST /v1/developer/keys.
Body
application/json
Amount in the lowest currency unit.
adjustment (default) issues account credit. refund calls the gateway's refund API against the paid invoice in invoice_id and posts a Refunds-vs-Cash ledger reversal; its progress is tracked by the credit note's refund_status.
Available options:
adjustment, refund Optional expiry for a spendable adjustment credit. When it passes with balance remaining, the expiry sweep writes the balance off (DR Customer Credit / CR Credits & Adjustments). Ignored for refunds.
Response
Credit note issued.
Show child attributes
Show child attributes
⌘I
Create a credit note
curl --request POST \
--url https://billing.example.com/v1/credit-notes \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"customer_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"amount": 123,
"currency": "<string>",
"invoice_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"reason": "<string>",
"type": "adjustment",
"expires_at": "2023-11-07T05:31:56Z"
}
'import requests
url = "https://billing.example.com/v1/credit-notes"
payload = {
"customer_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"amount": 123,
"currency": "<string>",
"invoice_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"reason": "<string>",
"type": "adjustment",
"expires_at": "2023-11-07T05:31:56Z"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
customer_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
amount: 123,
currency: '<string>',
invoice_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
reason: '<string>',
type: 'adjustment',
expires_at: '2023-11-07T05:31:56Z'
})
};
fetch('https://billing.example.com/v1/credit-notes', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://billing.example.com/v1/credit-notes",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'customer_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'amount' => 123,
'currency' => '<string>',
'invoice_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'reason' => '<string>',
'type' => 'adjustment',
'expires_at' => '2023-11-07T05:31:56Z'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://billing.example.com/v1/credit-notes"
payload := strings.NewReader("{\n \"customer_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"amount\": 123,\n \"currency\": \"<string>\",\n \"invoice_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"reason\": \"<string>\",\n \"type\": \"adjustment\",\n \"expires_at\": \"2023-11-07T05:31:56Z\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://billing.example.com/v1/credit-notes")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"customer_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"amount\": 123,\n \"currency\": \"<string>\",\n \"invoice_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"reason\": \"<string>\",\n \"type\": \"adjustment\",\n \"expires_at\": \"2023-11-07T05:31:56Z\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://billing.example.com/v1/credit-notes")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"customer_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"amount\": 123,\n \"currency\": \"<string>\",\n \"invoice_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"reason\": \"<string>\",\n \"type\": \"adjustment\",\n \"expires_at\": \"2023-11-07T05:31:56Z\"\n}"
response = http.request(request)
puts response.read_body{
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"tenant_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"customer_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"invoice_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"entity_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"reference": "<string>",
"amount": 123,
"subtotal": 123,
"tax_amount": 123,
"igst_amount": 123,
"cgst_amount": 123,
"sgst_amount": 123,
"tax_type": "<string>",
"hsn_code": "<string>",
"balance": 123,
"currency": "<string>",
"status": "issued",
"reason": "<string>",
"expires_at": "2023-11-07T05:31:56Z",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"customer": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"tenant_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"email": "jsmith@example.com",
"name": "<string>",
"phone": "<string>",
"tax_id": "<string>",
"billing_address": {
"line1": "<string>",
"line2": "<string>",
"postal_code": "<string>",
"city": "<string>",
"state": "<string>",
"zip": "<string>",
"country": "<string>"
},
"ledger_account_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"gstin": "<string>",
"tax_type": "<string>",
"place_of_supply": "<string>",
"tax_exempt": true,
"tax_exemption_number": "<string>",
"tax_exemption_code": "<string>",
"tax_exemption_expires_at": "2023-12-25",
"referral_code": "<string>",
"risk_score": 50,
"risk_factors": {},
"card_brand": "<string>",
"card_last4": "<string>",
"card_exp_month": 123,
"card_exp_year": 123,
"card_token_id": "<string>",
"card_fingerprint": "<string>",
"created_at": "2023-11-07T05:31:56Z"
}
}
}{
"error": {
"code": "BAD_REQUEST",
"message": "<string>"
}
}{
"error": {
"code": "BAD_REQUEST",
"message": "<string>"
}
}