Skip to main content
POST
/
v1
/
participants
/
{id}
/
balances
/
hold
Hold participant balance
curl --request POST \
  --url https://api.scrip.dev/v1/participants/{id}/balances/hold \
  --header 'Content-Type: application/json' \
  --header 'X-API-Key: <api-key>' \
  --data '
{
  "asset_id": "550e8400-e29b-41d4-a716-446655440001",
  "description": "Hold for pending order #123",
  "program_id": "550e8400-e29b-41d4-a716-446655440000",
  "amount": "100.00",
  "bucket": "AVAILABLE",
  "earned_from": "2024-01-01T00:00:00Z",
  "earned_to": "2024-12-31T23:59:59Z",
  "idempotency_key": "order-123-hold",
  "lot_ids": [
    "550e8400-e29b-41d4-a716-446655440002"
  ],
  "reference_id": "auth_12345"
}
'
import requests

url = "https://api.scrip.dev/v1/participants/{id}/balances/hold"

payload = {
"asset_id": "550e8400-e29b-41d4-a716-446655440001",
"description": "Hold for pending order #123",
"program_id": "550e8400-e29b-41d4-a716-446655440000",
"amount": "100.00",
"bucket": "AVAILABLE",
"earned_from": "2024-01-01T00:00:00Z",
"earned_to": "2024-12-31T23:59:59Z",
"idempotency_key": "order-123-hold",
"lot_ids": ["550e8400-e29b-41d4-a716-446655440002"],
"reference_id": "auth_12345"
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.text)
const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
asset_id: '550e8400-e29b-41d4-a716-446655440001',
description: 'Hold for pending order #123',
program_id: '550e8400-e29b-41d4-a716-446655440000',
amount: '100.00',
bucket: 'AVAILABLE',
earned_from: '2024-01-01T00:00:00Z',
earned_to: '2024-12-31T23:59:59Z',
idempotency_key: 'order-123-hold',
lot_ids: ['550e8400-e29b-41d4-a716-446655440002'],
reference_id: 'auth_12345'
})
};

fetch('https://api.scrip.dev/v1/participants/{id}/balances/hold', 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.scrip.dev/v1/participants/{id}/balances/hold",
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([
'asset_id' => '550e8400-e29b-41d4-a716-446655440001',
'description' => 'Hold for pending order #123',
'program_id' => '550e8400-e29b-41d4-a716-446655440000',
'amount' => '100.00',
'bucket' => 'AVAILABLE',
'earned_from' => '2024-01-01T00:00:00Z',
'earned_to' => '2024-12-31T23:59:59Z',
'idempotency_key' => 'order-123-hold',
'lot_ids' => [
'550e8400-e29b-41d4-a716-446655440002'
],
'reference_id' => 'auth_12345'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);

$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.scrip.dev/v1/participants/{id}/balances/hold"

payload := strings.NewReader("{\n \"asset_id\": \"550e8400-e29b-41d4-a716-446655440001\",\n \"description\": \"Hold for pending order #123\",\n \"program_id\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"amount\": \"100.00\",\n \"bucket\": \"AVAILABLE\",\n \"earned_from\": \"2024-01-01T00:00:00Z\",\n \"earned_to\": \"2024-12-31T23:59:59Z\",\n \"idempotency_key\": \"order-123-hold\",\n \"lot_ids\": [\n \"550e8400-e29b-41d4-a716-446655440002\"\n ],\n \"reference_id\": \"auth_12345\"\n}")

req, _ := http.NewRequest("POST", url, payload)

req.Header.Add("X-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.scrip.dev/v1/participants/{id}/balances/hold")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"asset_id\": \"550e8400-e29b-41d4-a716-446655440001\",\n \"description\": \"Hold for pending order #123\",\n \"program_id\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"amount\": \"100.00\",\n \"bucket\": \"AVAILABLE\",\n \"earned_from\": \"2024-01-01T00:00:00Z\",\n \"earned_to\": \"2024-12-31T23:59:59Z\",\n \"idempotency_key\": \"order-123-hold\",\n \"lot_ids\": [\n \"550e8400-e29b-41d4-a716-446655440002\"\n ],\n \"reference_id\": \"auth_12345\"\n}")
.asString();
require 'uri'
require 'net/http'

url = URI("https://api.scrip.dev/v1/participants/{id}/balances/hold")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"asset_id\": \"550e8400-e29b-41d4-a716-446655440001\",\n \"description\": \"Hold for pending order #123\",\n \"program_id\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"amount\": \"100.00\",\n \"bucket\": \"AVAILABLE\",\n \"earned_from\": \"2024-01-01T00:00:00Z\",\n \"earned_to\": \"2024-12-31T23:59:59Z\",\n \"idempotency_key\": \"order-123-hold\",\n \"lot_ids\": [\n \"550e8400-e29b-41d4-a716-446655440002\"\n ],\n \"reference_id\": \"auth_12345\"\n}"

response = http.request(request)
puts response.read_body
{
  "amount_processed": "100.00",
  "asset_id": "550e8400-e29b-41d4-a716-446655440001",
  "balance": {
    "available": "1400.00",
    "deferred": "0.00",
    "held": "200.00"
  },
  "journal_entry_id": "550e8400-e29b-41d4-a716-446655440003",
  "lots_processed": [
    {
      "amount": "50.00",
      "id": "550e8400-e29b-41d4-a716-446655440002"
    }
  ],
  "message": "Processed 100.00",
  "operation": "HOLD",
  "program_id": "550e8400-e29b-41d4-a716-446655440000",
  "reference_id": "auth_12345"
}
{
"code": "bad_request",
"details": {
"expected": "uuid",
"field": "asset_id",
"fields": [
{
"expected": "<unknown>",
"field": "amount",
"message": "This field is required",
"reason": "required",
"received": "-10.00"
}
],
"reason": "invalid",
"received": "not-a-uuid"
},
"message": "Invalid request parameters"
}
{
"code": "unauthorized",
"details": {
"expected": "uuid",
"field": "asset_id",
"fields": [
{
"expected": "<unknown>",
"field": "amount",
"message": "This field is required",
"reason": "required",
"received": "-10.00"
}
],
"reason": "invalid",
"received": "not-a-uuid"
},
"message": "Missing or invalid credentials"
}
{
"code": "forbidden",
"details": {
"expected": "uuid",
"field": "asset_id",
"fields": [
{
"expected": "<unknown>",
"field": "amount",
"message": "This field is required",
"reason": "required",
"received": "-10.00"
}
],
"reason": "invalid",
"received": "not-a-uuid"
},
"message": "Insufficient permissions for this action"
}
{
"code": "not_found",
"details": {
"expected": "uuid",
"field": "asset_id",
"fields": [
{
"expected": "<unknown>",
"field": "amount",
"message": "This field is required",
"reason": "required",
"received": "-10.00"
}
],
"reason": "invalid",
"received": "not-a-uuid"
},
"message": "Resource not found"
}
{
"code": "conflict",
"details": {
"expected": "uuid",
"field": "asset_id",
"fields": [
{
"expected": "<unknown>",
"field": "amount",
"message": "This field is required",
"reason": "required",
"received": "-10.00"
}
],
"reason": "invalid",
"received": "not-a-uuid"
},
"message": "Resource already exists or state conflict"
}
{
"code": "unsupported_media_type",
"details": {
"expected": "uuid",
"field": "asset_id",
"fields": [
{
"expected": "<unknown>",
"field": "amount",
"message": "This field is required",
"reason": "required",
"received": "-10.00"
}
],
"reason": "invalid",
"received": "not-a-uuid"
},
"message": "Content-Type must be application/json"
}
{
"code": "unprocessable",
"details": {
"expected": "uuid",
"field": "asset_id",
"fields": [
{
"expected": "<unknown>",
"field": "amount",
"message": "This field is required",
"reason": "required",
"received": "-10.00"
}
],
"reason": "invalid",
"received": "not-a-uuid"
},
"message": "Business rule violation"
}
{
"code": "internal_error",
"message": "An internal error occurred"
}
Moves funds from AVAILABLE to HELD for a participant. Held funds are not spendable and remain reserved until explicitly released or forfeited. Common use cases include authorization holds, fraud review, and pending approval workflows. For assets in LOT mode, hold operations preserve lot-level metadata such as expires_at and matures_at. The hold will fail if the participant does not have sufficient AVAILABLE balance.

Hold/Release Correlation (reference_id)

For LOT mode assets, you can include an optional reference_id to correlate this hold with a future release. Held lots are stamped with the reference, and a subsequent release using the same reference_id will target only those lots. This is useful when a participant has multiple concurrent holds (e.g., multiple pending orders).
  • Format: 1-255 characters, alphanumeric plus ._:@-
  • Only supported on LOT mode assets
  • Not supported for forfeit operations
  • The reference_id is visible on lot responses and journal entries
For usage patterns and examples, see the Balance Operations guide.

Authorizations

X-API-Key
string
header
required

API key passed in the X-API-Key header.

Headers

Idempotency-Key
string

Idempotency key (1-255 printable ASCII chars). Equivalent to the idempotency_key body field; if both are provided they must match. Replays with the same key and identical parameters return the original result; the same key with different parameters returns 409 idempotency_conflict.

Maximum string length: 255

Path Parameters

id
string<uuid>
required

Participant ID

Body

application/json

Hold operation details

asset_id
string<uuid>
required

Asset to operate on

Example:

"550e8400-e29b-41d4-a716-446655440001"

description
string
required

Reason for this operation

Required string length: 1 - 500
Example:

"Hold for pending order #123"

program_id
string<uuid>
required

Program this operation belongs to

Example:

"550e8400-e29b-41d4-a716-446655440000"

amount
string

Amount to process. Omit to process the full balance (SIMPLE) or all matching lots (LOT)

Example:

"100.00"

bucket
enum<string>

Which bucket to forfeit from. Required for forfeit; ignored for hold/release

Available options:
AVAILABLE,
HELD
Example:

"AVAILABLE"

earned_from
string<date-time>

Only process lots earned on or after this time (RFC 3339). LOT mode only.

Example:

"2024-01-01T00:00:00Z"

earned_to
string<date-time>

Only process lots earned on or before this time (RFC 3339). LOT mode only. Must be >= earned_from when both are provided.

Example:

"2024-12-31T23:59:59Z"

idempotency_key
string

Client-provided key to dedupe retries. May also be supplied via the Idempotency-Key HTTP header; when both are present they must match. Identical operations with the same key return the original result; a reused key with different payload returns 409 idempotency_conflict.

Required string length: 1 - 255
Example:

"order-123-hold"

lot_ids
string[]

Restrict to specific lots. LOT mode only

Example:
["550e8400-e29b-41d4-a716-446655440002"]
reference_id
string

Correlation ID linking holds to releases. LOT mode only. Hold stamps lots; release filters by reference.

Example:

"auth_12345"

Response

Hold processed

amount_processed
string

Total amount processed

Example:

"100.00"

asset_id
string<uuid>

Asset ID

Example:

"550e8400-e29b-41d4-a716-446655440001"

balance
object

Balance after the operation

journal_entry_id
string<uuid>

Ledger journal entry created by this operation

Example:

"550e8400-e29b-41d4-a716-446655440003"

lots_processed
object[]

Individual lots affected. Only present for LOT mode assets

message
string

Confirmation message

Example:

"Processed 100.00"

operation
string

Operation performed

Example:

"HOLD"

program_id
string<uuid>

Program ID

Example:

"550e8400-e29b-41d4-a716-446655440000"

reference_id
string

Correlation ID linking this hold/release (if provided)

Example:

"auth_12345"