Wallets
Create a Wallet
Create a prepaid wallet — one per customer, entity, and currency.
POST
/
v1
/
wallets
Create a prepaid wallet
curl --request POST \
--url https://billing.example.com/v1/wallets \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"customer_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"currency": "<string>",
"entity_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"auto_recharge_threshold": 123,
"auto_recharge_amount": 123
}
'import requests
url = "https://billing.example.com/v1/wallets"
payload = {
"customer_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"currency": "<string>",
"entity_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"auto_recharge_threshold": 123,
"auto_recharge_amount": 123
}
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',
currency: '<string>',
entity_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
auto_recharge_threshold: 123,
auto_recharge_amount: 123
})
};
fetch('https://billing.example.com/v1/wallets', 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/wallets",
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',
'currency' => '<string>',
'entity_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'auto_recharge_threshold' => 123,
'auto_recharge_amount' => 123
]),
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/wallets"
payload := strings.NewReader("{\n \"customer_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"currency\": \"<string>\",\n \"entity_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"auto_recharge_threshold\": 123,\n \"auto_recharge_amount\": 123\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/wallets")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"customer_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"currency\": \"<string>\",\n \"entity_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"auto_recharge_threshold\": 123,\n \"auto_recharge_amount\": 123\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://billing.example.com/v1/wallets")
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 \"currency\": \"<string>\",\n \"entity_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"auto_recharge_threshold\": 123,\n \"auto_recharge_amount\": 123\n}"
response = http.request(request)
puts response.read_body{
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"entity_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"customer_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"currency": "<string>",
"balance": 123,
"auto_recharge_threshold": 123,
"auto_recharge_amount": 123,
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z"
}
}{
"error": {
"code": "validation_failed",
"message": "<string>"
}
}{
"error": {
"code": "validation_failed",
"message": "<string>"
}
}Request body
| Parameter | Type | Required | Description |
|---|---|---|---|
customer_id | string (uuid) | Yes | The wallet’s owner. |
currency | string | Yes | ISO 4217 code; the wallet holds minor units of this currency. |
entity_id | string (uuid) | No | Legal entity the wallet belongs to (Multi-Entity Books). Omit for the primary entity. |
auto_recharge_threshold | integer | null | No | Recharge when the balance falls below this (minor units). |
auto_recharge_amount | integer | null | No | Amount charged to the saved payment method on recharge. |
Example request
curl -X POST https://api.recurso.dev/v1/wallets \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"customer_id": "9f2c1e84-6a3d-4b7e-9c21-8f4a5d6e7b01",
"currency": "INR"
}'
Example response
{
"data": {
"id": "5a8c2f91-3e7b-4d0a-9c6f-2b4e8a1d7c53",
"entity_id": "c4f8b2a6-1d9e-4c3a-8b7f-5e2a9d0c6f41",
"customer_id": "9f2c1e84-6a3d-4b7e-9c21-8f4a5d6e7b01",
"currency": "INR",
"balance": 4070000,
"auto_recharge_threshold": null,
"auto_recharge_amount": null,
"created_at": "2026-05-02T09:00:00Z",
"updated_at": "2026-08-01T12:00:00Z"
}
}
409 when a wallet for this customer, entity, and currency
already exists. New wallets start at a zero balance — fund them with a
top-up.
Errors
| Status | Code | When | Fix |
|---|---|---|---|
400 | validation_failed | Malformed body, customer_id is not a UUID, or currency is not an ISO 3-letter code | Correct the payload; send the currency as e.g. INR, USD |
400 | validation_failed | entity_id is invalid or names an entity that doesn’t exist in this workspace | Use an entity ID from your Entities list, or omit it for the primary entity |
400 | validation_failed | auto_recharge_threshold and auto_recharge_amount are not set together, or are not positive | Send both fields (both positive), or neither |
404 | not_found | customer_id doesn’t exist (or belongs to another tenant) | Create the customer first, or check the ID |
409 | conflict | An open wallet already exists for this customer, entity, and currency | Reuse that wallet — top it up instead of creating another |
Authorizations
Tenant API key obtained from POST /auth/register or POST /v1/developer/keys.
Body
application/json
Required string length:
3Legal entity the wallet belongs to (Multi-Entity Books). Omit for the tenant's primary entity.
Recharge when balance falls below this (minor units).
Amount charged to the saved payment method on recharge.
Response
The created wallet
Prepaid balance per customer+currency, drained before credit notes and the gateway at invoice time. Amounts are minor units.
Show child attributes
Show child attributes
⌘I
Create a prepaid wallet
curl --request POST \
--url https://billing.example.com/v1/wallets \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"customer_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"currency": "<string>",
"entity_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"auto_recharge_threshold": 123,
"auto_recharge_amount": 123
}
'import requests
url = "https://billing.example.com/v1/wallets"
payload = {
"customer_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"currency": "<string>",
"entity_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"auto_recharge_threshold": 123,
"auto_recharge_amount": 123
}
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',
currency: '<string>',
entity_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
auto_recharge_threshold: 123,
auto_recharge_amount: 123
})
};
fetch('https://billing.example.com/v1/wallets', 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/wallets",
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',
'currency' => '<string>',
'entity_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'auto_recharge_threshold' => 123,
'auto_recharge_amount' => 123
]),
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/wallets"
payload := strings.NewReader("{\n \"customer_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"currency\": \"<string>\",\n \"entity_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"auto_recharge_threshold\": 123,\n \"auto_recharge_amount\": 123\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/wallets")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"customer_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"currency\": \"<string>\",\n \"entity_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"auto_recharge_threshold\": 123,\n \"auto_recharge_amount\": 123\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://billing.example.com/v1/wallets")
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 \"currency\": \"<string>\",\n \"entity_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"auto_recharge_threshold\": 123,\n \"auto_recharge_amount\": 123\n}"
response = http.request(request)
puts response.read_body{
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"entity_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"customer_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"currency": "<string>",
"balance": 123,
"auto_recharge_threshold": 123,
"auto_recharge_amount": 123,
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z"
}
}{
"error": {
"code": "validation_failed",
"message": "<string>"
}
}{
"error": {
"code": "validation_failed",
"message": "<string>"
}
}