curl --request POST \
--url https://api.unprice.dev/v1/budgets/settle \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"key": "customer:acme",
"holdId": "h_42",
"amount": "0.05"
}
'import requests
url = "https://api.unprice.dev/v1/budgets/settle"
payload = {
"key": "customer:acme",
"holdId": "h_42",
"amount": "0.05"
}
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({key: 'customer:acme', holdId: 'h_42', amount: '0.05'})
};
fetch('https://api.unprice.dev/v1/budgets/settle', 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.unprice.dev/v1/budgets/settle",
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([
'key' => 'customer:acme',
'holdId' => 'h_42',
'amount' => '0.05'
]),
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://api.unprice.dev/v1/budgets/settle"
payload := strings.NewReader("{\n \"key\": \"customer:acme\",\n \"holdId\": \"h_42\",\n \"amount\": \"0.05\"\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://api.unprice.dev/v1/budgets/settle")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"key\": \"customer:acme\",\n \"holdId\": \"h_42\",\n \"amount\": \"0.05\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.unprice.dev/v1/budgets/settle")
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 \"key\": \"customer:acme\",\n \"holdId\": \"h_42\",\n \"amount\": \"0.05\"\n}"
response = http.request(request)
puts response.read_body{
"holdId": "h_42",
"actual": "<string>",
"released": "<string>",
"expired": true,
"crossed": [
"<string>"
],
"replayed": true,
"balance": {
"remaining": "<string>",
"held": "<string>",
"limits": [
{
"id": "<string>",
"window": "month",
"enforce": "hard",
"amount": "<string>",
"consumed": "<string>",
"held": "<string>",
"remaining": "<string>",
"resetsAt": 123
}
],
"asOf": 123
}
}{
"error": {
"code": "BAD_REQUEST",
"docs": "https://docs.unprice.dev/api-reference/errors/code/BAD_REQUEST",
"message": "<string>",
"requestId": "req_1234",
"details": {
"kind": "invalid_config",
"issues": [
{
"path": "config.plans[0].version.features[1].featureSlug",
"message": "<string>"
}
]
}
}
}{
"error": {
"code": "UNAUTHORIZED",
"docs": "https://docs.unprice.dev/api-reference/errors/code/UNAUTHORIZED",
"message": "<string>",
"requestId": "req_1234",
"details": {
"kind": "invalid_config",
"issues": [
{
"path": "config.plans[0].version.features[1].featureSlug",
"message": "<string>"
}
]
}
}
}{
"error": {
"code": "FORBIDDEN",
"docs": "https://docs.unprice.dev/api-reference/errors/code/FORBIDDEN",
"message": "<string>",
"requestId": "req_1234",
"details": {
"kind": "invalid_config",
"issues": [
{
"path": "config.plans[0].version.features[1].featureSlug",
"message": "<string>"
}
]
}
}
}{
"error": {
"code": "NOT_FOUND",
"docs": "https://docs.unprice.dev/api-reference/errors/code/NOT_FOUND",
"message": "<string>",
"requestId": "req_1234",
"details": {
"kind": "invalid_config",
"issues": [
{
"path": "config.plans[0].version.features[1].featureSlug",
"message": "<string>"
}
]
}
}
}{
"error": {
"code": "CONFLICT",
"docs": "https://docs.unprice.dev/api-reference/errors/code/CONFLICT",
"message": "<string>",
"requestId": "req_1234",
"details": {
"kind": "invalid_config",
"issues": [
{
"path": "config.plans[0].version.features[1].featureSlug",
"message": "<string>"
}
]
}
}
}{
"error": {
"code": "PRECONDITION_FAILED",
"docs": "https://docs.unprice.dev/api-reference/errors/code/PRECONDITION_FAILED",
"message": "<string>",
"requestId": "req_1234",
"details": {
"kind": "invalid_config",
"issues": [
{
"path": "config.plans[0].version.features[1].featureSlug",
"message": "<string>"
}
]
}
}
}{
"error": {
"code": "PAYLOAD_TOO_LARGE",
"docs": "https://docs.unprice.dev/api-reference/errors/code/PAYLOAD_TOO_LARGE",
"message": "<string>",
"requestId": "req_1234",
"details": {
"kind": "invalid_config",
"issues": [
{
"path": "config.plans[0].version.features[1].featureSlug",
"message": "<string>"
}
]
}
}
}{
"error": {
"code": "TOO_MANY_REQUESTS",
"docs": "https://docs.unprice.dev/api-reference/errors/code/TOO_MANY_REQUESTS",
"message": "<string>",
"requestId": "req_1234",
"details": {
"kind": "invalid_config",
"issues": [
{
"path": "config.plans[0].version.features[1].featureSlug",
"message": "<string>"
}
]
}
}
}{
"error": {
"code": "INTERNAL_SERVER_ERROR",
"docs": "https://docs.unprice.dev/api-reference/errors/code/INTERNAL_SERVER_ERROR",
"message": "<string>",
"requestId": "req_1234",
"details": {
"kind": "invalid_config",
"issues": [
{
"path": "config.plans[0].version.features[1].featureSlug",
"message": "<string>"
}
]
}
}
}settle a hold with the actual amount
Settle final usage after work has stopped and release the unused reservation. Actual usage must not exceed the authorized amount. A larger amount returns 409 and leaves the reservation unchanged. Expired open holds still settle against their reservation. The hold id is the idempotency key: the same amount replays, another amount returns 409. A hold retires 1 day after it closes; settling or releasing it after that returns 409.
curl --request POST \
--url https://api.unprice.dev/v1/budgets/settle \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"key": "customer:acme",
"holdId": "h_42",
"amount": "0.05"
}
'import requests
url = "https://api.unprice.dev/v1/budgets/settle"
payload = {
"key": "customer:acme",
"holdId": "h_42",
"amount": "0.05"
}
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({key: 'customer:acme', holdId: 'h_42', amount: '0.05'})
};
fetch('https://api.unprice.dev/v1/budgets/settle', 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.unprice.dev/v1/budgets/settle",
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([
'key' => 'customer:acme',
'holdId' => 'h_42',
'amount' => '0.05'
]),
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://api.unprice.dev/v1/budgets/settle"
payload := strings.NewReader("{\n \"key\": \"customer:acme\",\n \"holdId\": \"h_42\",\n \"amount\": \"0.05\"\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://api.unprice.dev/v1/budgets/settle")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"key\": \"customer:acme\",\n \"holdId\": \"h_42\",\n \"amount\": \"0.05\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.unprice.dev/v1/budgets/settle")
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 \"key\": \"customer:acme\",\n \"holdId\": \"h_42\",\n \"amount\": \"0.05\"\n}"
response = http.request(request)
puts response.read_body{
"holdId": "h_42",
"actual": "<string>",
"released": "<string>",
"expired": true,
"crossed": [
"<string>"
],
"replayed": true,
"balance": {
"remaining": "<string>",
"held": "<string>",
"limits": [
{
"id": "<string>",
"window": "month",
"enforce": "hard",
"amount": "<string>",
"consumed": "<string>",
"held": "<string>",
"remaining": "<string>",
"resetsAt": 123
}
],
"asOf": 123
}
}{
"error": {
"code": "BAD_REQUEST",
"docs": "https://docs.unprice.dev/api-reference/errors/code/BAD_REQUEST",
"message": "<string>",
"requestId": "req_1234",
"details": {
"kind": "invalid_config",
"issues": [
{
"path": "config.plans[0].version.features[1].featureSlug",
"message": "<string>"
}
]
}
}
}{
"error": {
"code": "UNAUTHORIZED",
"docs": "https://docs.unprice.dev/api-reference/errors/code/UNAUTHORIZED",
"message": "<string>",
"requestId": "req_1234",
"details": {
"kind": "invalid_config",
"issues": [
{
"path": "config.plans[0].version.features[1].featureSlug",
"message": "<string>"
}
]
}
}
}{
"error": {
"code": "FORBIDDEN",
"docs": "https://docs.unprice.dev/api-reference/errors/code/FORBIDDEN",
"message": "<string>",
"requestId": "req_1234",
"details": {
"kind": "invalid_config",
"issues": [
{
"path": "config.plans[0].version.features[1].featureSlug",
"message": "<string>"
}
]
}
}
}{
"error": {
"code": "NOT_FOUND",
"docs": "https://docs.unprice.dev/api-reference/errors/code/NOT_FOUND",
"message": "<string>",
"requestId": "req_1234",
"details": {
"kind": "invalid_config",
"issues": [
{
"path": "config.plans[0].version.features[1].featureSlug",
"message": "<string>"
}
]
}
}
}{
"error": {
"code": "CONFLICT",
"docs": "https://docs.unprice.dev/api-reference/errors/code/CONFLICT",
"message": "<string>",
"requestId": "req_1234",
"details": {
"kind": "invalid_config",
"issues": [
{
"path": "config.plans[0].version.features[1].featureSlug",
"message": "<string>"
}
]
}
}
}{
"error": {
"code": "PRECONDITION_FAILED",
"docs": "https://docs.unprice.dev/api-reference/errors/code/PRECONDITION_FAILED",
"message": "<string>",
"requestId": "req_1234",
"details": {
"kind": "invalid_config",
"issues": [
{
"path": "config.plans[0].version.features[1].featureSlug",
"message": "<string>"
}
]
}
}
}{
"error": {
"code": "PAYLOAD_TOO_LARGE",
"docs": "https://docs.unprice.dev/api-reference/errors/code/PAYLOAD_TOO_LARGE",
"message": "<string>",
"requestId": "req_1234",
"details": {
"kind": "invalid_config",
"issues": [
{
"path": "config.plans[0].version.features[1].featureSlug",
"message": "<string>"
}
]
}
}
}{
"error": {
"code": "TOO_MANY_REQUESTS",
"docs": "https://docs.unprice.dev/api-reference/errors/code/TOO_MANY_REQUESTS",
"message": "<string>",
"requestId": "req_1234",
"details": {
"kind": "invalid_config",
"issues": [
{
"path": "config.plans[0].version.features[1].featureSlug",
"message": "<string>"
}
]
}
}
}{
"error": {
"code": "INTERNAL_SERVER_ERROR",
"docs": "https://docs.unprice.dev/api-reference/errors/code/INTERNAL_SERVER_ERROR",
"message": "<string>",
"requestId": "req_1234",
"details": {
"kind": "invalid_config",
"issues": [
{
"path": "config.plans[0].version.features[1].featureSlug",
"message": "<string>"
}
]
}
}
}Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Body
The settle request
The budget's key, chosen by you and unique within the project. Up to 128 letters, digits, and : / _ . @ -, starting with a letter or digit.
^[A-Za-z0-9][A-Za-z0-9:/_.@-]{0,127}$"customer:acme"
The hold, as returned by authorize
^h_[1-9][0-9]{0,15}$"h_42"
Final usage after work has stopped. Must not exceed the authorized amount. Settlement returns the unused reservation. An amount above the reservation returns 409 and leaves the hold unchanged.
^\d{1,19}(\.\d{1,8})?$"0.05"
Response
The settlement
The hold, as returned by authorize
^h_[1-9][0-9]{0,15}$"h_42"
The amount settled
The unused part of the hold, returned
Settled at or after the hold's expiresAt
Limit ids whose consumed amount first exceeded the limit's amount. A hard limit crosses only after recorded usage took its room. Reservations do not trigger crossings. Replays preserve the original result.
True when this answer replays an earlier request instead of applying it again
Show child attributes
Show child attributes