Charge a user a custom fee
curl --request POST \
--url https://api-dev.rain.xyz/v1/issuing/users/{userId}/charges \
--header 'Api-Key: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"amount": 5000000,
"description": "<string>"
}
'import requests
url = "https://api-dev.rain.xyz/v1/issuing/users/{userId}/charges"
payload = {
"amount": 5000000,
"description": "<string>"
}
headers = {
"Api-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Api-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({amount: 5000000, description: '<string>'})
};
fetch('https://api-dev.rain.xyz/v1/issuing/users/{userId}/charges', 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://api-dev.rain.xyz/v1/issuing/users/{userId}/charges",
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([
'amount' => 5000000,
'description' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Api-Key: <api-key>",
"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://api-dev.rain.xyz/v1/issuing/users/{userId}/charges"
payload := strings.NewReader("{\n \"amount\": 5000000,\n \"description\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Api-Key", "<api-key>")
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://api-dev.rain.xyz/v1/issuing/users/{userId}/charges")
.header("Api-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"amount\": 5000000,\n \"description\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-dev.rain.xyz/v1/issuing/users/{userId}/charges")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Api-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"amount\": 5000000,\n \"description\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"createdAt": "2023-11-07T05:31:56Z",
"amount": 2,
"description": "<string>",
"currency": "usd"
}{
"statusCode": 123,
"error": "<string>",
"message": "<string>"
}Users
Charge a user a custom fee
POST
/
issuing
/
users
/
{userId}
/
charges
Charge a user a custom fee
curl --request POST \
--url https://api-dev.rain.xyz/v1/issuing/users/{userId}/charges \
--header 'Api-Key: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"amount": 5000000,
"description": "<string>"
}
'import requests
url = "https://api-dev.rain.xyz/v1/issuing/users/{userId}/charges"
payload = {
"amount": 5000000,
"description": "<string>"
}
headers = {
"Api-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Api-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({amount: 5000000, description: '<string>'})
};
fetch('https://api-dev.rain.xyz/v1/issuing/users/{userId}/charges', 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://api-dev.rain.xyz/v1/issuing/users/{userId}/charges",
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([
'amount' => 5000000,
'description' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Api-Key: <api-key>",
"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://api-dev.rain.xyz/v1/issuing/users/{userId}/charges"
payload := strings.NewReader("{\n \"amount\": 5000000,\n \"description\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Api-Key", "<api-key>")
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://api-dev.rain.xyz/v1/issuing/users/{userId}/charges")
.header("Api-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"amount\": 5000000,\n \"description\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-dev.rain.xyz/v1/issuing/users/{userId}/charges")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Api-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"amount\": 5000000,\n \"description\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"createdAt": "2023-11-07T05:31:56Z",
"amount": 2,
"description": "<string>",
"currency": "usd"
}{
"statusCode": 123,
"error": "<string>",
"message": "<string>"
}Read the guides before using this pageTo use this endpoint properly, make sure you are up to date on our managing users guides.
Rain-managed vs Partner-managed programs
Rain-managed programs: Rain automatically processes custom charges and applies them directly to the userβs balance. You donβt need any additional ledgering on your side. Partner-managed programs: You canβt use this endpoint. Rain returns a403 with Partner-managed tenants cannot create charges. Handle fees in your own ledger.
Charges apply after authorizationRain applies custom charges after the authorization process, which means users may go negative if their balance is insufficient to cover the charge.
Rain handles FX/XB fees differentlyRain configures foreign exchange (FX) and cross-border (XB) fees at the tenant level and includes them during authorization. See Pricing and fees for more information.
Example
// Apply a \$5 card setup fee when a user requests a new card
const charge = await rain.createUserCharge({
userId: "user_123",
amount: 500, // \$5.00 in cents
description: "Card setup fee",
idempotencyKey: "setup_fee_user_123_card_456"
});
Best practicesAlways use idempotency keys to prevent duplicate charges. Provide clear descriptions for charges to help with user support. Monitor user balances to avoid excessive negative balances, and consider notifying users before applying charges when possible.
Authorizations
Path Parameters
Id of the user to create a custom fee charge for
Body
application/json
Description of the custom fee charge
Response
Successful operation
The id of the charge
The time at which the charge was created
The amount of the charge, in cents
Required range:
x >= 1The description of the charge
Lowercase currency code of the charge, for example usd.
Available options:
usd, eur