/api/transactions/locker/put-no-sum
GETUpload CloudCoins from your wallet to a RAIDA locker using per-coin authentication. Each coin is individually verified by the RAIDA, providing per-coin pass/fail results.
Description
The /api/transactions/locker/put-no-sum endpoint uploads CloudCoins from your wallet to the RAIDA cloud locker system using per-coin authentication. Unlike the standard locker upload which uses an XOR checksum, this endpoint authenticates each coin individually with its Authenticity Number (AN), giving per-coin pass/fail results.
This endpoint uses RAIDA command 0x0850 (cmd_store). Each coin is individually authenticated — the RAIDA checks each coin's AN and returns a per-coin bitmask showing which coins passed and which failed. Only coins achieving 13+ RAIDA confirmations are moved to the Locker folder.
The endpoint performs a multi-phase operation:
- Coin Selection: Selects coins from Bank and Fracked folders using greedy selection (largest denominations first). Auto make-change if exact amount cannot be met.
- RAIDA Store: Sends per-coin POWN-format packets to all 25 RAIDAs in parallel via TCP. Each coin carries its AN and a per-RAIDA derived locker code as the PAN.
- Per-Coin Consensus: Each RAIDA returns a bitmask indicating which coins passed. Coins with 13+ RAIDA passes are considered accepted.
- File Management: Only accepted coins are moved to the Locker folder. Failed coins remain in Bank/Fracked.
The locker_key parameter is essentially a password. Anyone with this key can download the coins from the locker. Keep it secret and share it securely with the intended recipient only.
Comparison with Locker Upload
| Feature | Locker Upload (0x0852) | Locker Put No-Sum (0x0850) |
|---|---|---|
| Authentication | XOR checksum of all ANs (all-or-nothing) | Per-coin AN verification (individual results) |
| Bytes per coin | 5 (DN + SN only) | 37 (DN + SN + AN + PAN) |
| Failure granularity | All coins fail if any AN is wrong | Only bad coins fail; good coins still accepted |
| Transport | TCP, unencrypted | TCP, unencrypted |
| Best for | Trusted coins, smaller batches | Mixed-quality coins, when per-coin results matter |
Parameters
This endpoint requires both locker_key and amount.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
locker_key |
string | Yes | Any string of characters (e.g., "ABC-1234"). This becomes the password to access the locker. |
amount |
integer | Yes | Upload coins totaling this many whole CloudCoin units. Uses greedy selection (largest denominations first) with auto make-change. |
wallet_path |
string | No | Full path to the wallet directory containing the coins. If omitted, uses the default wallet. |
wallet |
string | No | Wallet name (alternative to wallet_path). Looks up wallet in standard locations. |
Locker Key Format
The locker_key can be any string. We recommend a format like "ABC-1234" for easy sharing, but any characters work.
Example locker_key values:
CUP-1974
MySecret2025
ABC-DEFG-1234
gift-for-alice
Important: The same locker_key always accesses the same locker. Keep your locker_key secret and share it securely with the intended recipient only. Anyone with the locker_key can download the coins.
RAIDA Protocol Details
This endpoint uses the RAIDA Store command (0x0850) with per-coin POWN-style authentication.
Command Code
0x0850 (Command Group: 0x08 = Locker, Command: 0x50 = Store / Put No-Sum)
Request Body Format
N x [DN(1 byte) + SN(4 bytes) + AN(16 bytes) + PAN(16 bytes)]
Body size = N x 37 bytes, where N is the number of coins. Each coin carries:
- DN (1 byte): Denomination code
- SN (4 bytes): Serial number, big-endian
- AN (16 bytes): Authenticity Number for this specific RAIDA
- PAN (16 bytes): Per-RAIDA derived locker code (same for all coins in the batch)
PAN Derivation
The PAN is not a random value. It is the per-RAIDA locker code derived from the locker key:
locker_code[raida_id] = MD5(str(raida_id) + parts[0] + "-" + parts[1])
locker_code[12..15] = 0xFFFFFFFF
The same locker code is used as PAN for every coin in the batch on a given RAIDA.
Response Status Codes
- 241 (ALL_PASS): All coins accepted by this RAIDA
- 242 (ALL_FAIL): No coins accepted by this RAIDA
- 243 (MIXED): Some coins passed, some failed. Response body contains a bitmask (1 bit per coin, LSB-first)
Bitmask Format (Status 243)
The response body is a bitmask with 1 bit per coin, packed LSB-first:
bit = (body[i / 8] >> (i % 8)) & 1
// 1 = coin accepted, 0 = coin rejected
Consensus Requirement
Each coin is evaluated independently. A coin is considered accepted if 13 or more out of 25 RAIDAs report it as passed.
Response
Returns a JSON object with per-coin results showing exactly which coins were accepted and which failed.
Example: Success (All Coins Accepted)
{
"status": "success",
"operation": "locker_put_no_sum",
"amount_requested": 500,
"coins_sent": 3,
"coins_accepted": 3,
"coins_moved": 3,
"value_accepted": 500,
"locker_key": "CUP-1974",
"raida_responded": 25,
"coin_results": [
{
"serial_number": 1234567,
"denomination": 100,
"raida_pass": 25,
"accepted": true
},
{
"serial_number": 2345678,
"denomination": 100,
"raida_pass": 24,
"accepted": true
},
{
"serial_number": 3456789,
"denomination": 100,
"raida_pass": 100,
"accepted": true
}
],
"task_id": "a1b2c3d4"
}
Example: Partial Success (Mixed Results)
{
"status": "success",
"operation": "locker_put_no_sum",
"amount_requested": 200,
"coins_sent": 3,
"coins_accepted": 2,
"coins_moved": 2,
"value_accepted": 110,
"locker_key": "MY-LOCKER",
"raida_responded": 25,
"coin_results": [
{
"serial_number": 1111111,
"denomination": 100,
"raida_pass": 24,
"accepted": true
},
{
"serial_number": 2222222,
"denomination": 10,
"raida_pass": 25,
"accepted": true
},
{
"serial_number": 3333333,
"denomination": 100,
"raida_pass": 3,
"accepted": false
}
],
"task_id": "e5f6g7h8"
}
Response Properties
serial_number, denomination, raida_pass (number of RAIDAs that accepted this coin), and accepted (true if 13+ passes).Error Responses
The endpoint returns appropriate HTTP status codes with JSON error messages.
HTTP 400 - Bad Request
- Missing or empty
locker_keyparameter - Missing
amountparameter - Invalid amount (must be greater than 0)
- Cannot make exact change for requested amount
- Invalid wallet path
HTTP 500 - Internal Server Error
- Put failed - no coins accepted by RAIDA consensus
- Insufficient RAIDA responses (fewer than 13 RAIDAs responded)
- Transport not initialized
Example Error Response
{
"status": "error",
"operation": "locker_put_no_sum",
"message": "Put failed - no coins accepted by RAIDA consensus",
"locker_key": "MY-KEY",
"raida_responded": 25,
"coins_sent": 3,
"coins_accepted": 0
}
Examples
cURL
# Upload 500 CloudCoins to locker with per-coin authentication
curl "http://localhost:8080/api/transactions/locker/put-no-sum?locker_key=CUP-1974&amount=500"
# Upload 100 CloudCoins from a specific wallet
curl "http://localhost:8080/api/transactions/locker/put-no-sum?locker_key=GIFT-CODE&amount=100&wallet_path=/path/to/wallet"
# Upload 1 CloudCoin (small test)
curl "http://localhost:8080/api/transactions/locker/put-no-sum?locker_key=TEST-KEY&amount=1"
# Upload using a named wallet
curl "http://localhost:8080/api/transactions/locker/put-no-sum?locker_key=ABC-1234&amount=50&wallet=MyWallet"
JavaScript (fetch)
const API_HOST = 'http://localhost:8080';
// Upload coins to locker with per-coin authentication
async function lockerPutNoSum(lockerKey, amount, walletPath = null) {
let url = `${API_HOST}/api/transactions/locker/put-no-sum?` +
`locker_key=${encodeURIComponent(lockerKey)}&` +
`amount=${amount}`;
if (walletPath) {
url += `&wallet_path=${encodeURIComponent(walletPath)}`;
}
const response = await fetch(url);
const result = await response.json();
if (result.status === 'success') {
console.log(`Accepted ${result.coins_accepted}/${result.coins_sent} coins`);
console.log(`Value accepted: ${result.value_accepted} CC`);
// Check per-coin results
for (const coin of result.coin_results) {
const status = coin.accepted ? 'ACCEPTED' : 'REJECTED';
console.log(` SN ${coin.serial_number} (${coin.denomination} CC): ` +
`${coin.raida_pass}/25 RAIDA - ${status}`);
}
} else {
console.error('Put failed:', result.message);
}
return result;
}
// Examples:
// Upload 500 CloudCoins
lockerPutNoSum('CUP-1974', 500);
// Upload 100 CloudCoins from specific wallet
lockerPutNoSum('GIFT-CODE', 100, 'E:/Wallets/MyWallet');
// Upload 1 CloudCoin (test)
lockerPutNoSum('TEST-KEY', 1);
Go
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
)
const ApiHost = "http://localhost:8080"
type CoinResult struct {
SerialNumber int `json:"serial_number"`
Denomination float64 `json:"denomination"`
RaidaPass int `json:"raida_pass"`
Accepted bool `json:"accepted"`
}
type LockerPutNoSumResponse struct {
Status string `json:"status"`
Operation string `json:"operation"`
AmountReq int `json:"amount_requested"`
CoinsSent int `json:"coins_sent"`
CoinsAccepted int `json:"coins_accepted"`
CoinsMoved int `json:"coins_moved"`
ValueAccepted int `json:"value_accepted"`
LockerKey string `json:"locker_key"`
RaidaResponded int `json:"raida_responded"`
CoinResults []CoinResult `json:"coin_results"`
TaskID string `json:"task_id"`
Message string `json:"message,omitempty"`
}
func lockerPutNoSum(lockerKey string, amount int, walletPath string) (*LockerPutNoSumResponse, error) {
params := url.Values{}
params.Add("locker_key", lockerKey)
params.Add("amount", fmt.Sprintf("%d", amount))
if walletPath != "" {
params.Add("wallet_path", walletPath)
}
fullURL := fmt.Sprintf("%s/api/transactions/locker/put-no-sum?%s",
ApiHost, params.Encode())
resp, err := http.Get(fullURL)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
var result LockerPutNoSumResponse
json.Unmarshal(body, &result)
return &result, nil
}
func main() {
result, err := lockerPutNoSum("CUP-1974", 500, "")
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Status: %s\n", result.Status)
fmt.Printf("Coins: %d sent, %d accepted\n",
result.CoinsSent, result.CoinsAccepted)
fmt.Printf("Value accepted: %d CC\n", result.ValueAccepted)
// Print per-coin results
for _, coin := range result.CoinResults {
status := "REJECTED"
if coin.Accepted {
status = "ACCEPTED"
}
fmt.Printf(" SN %d (%g CC): %d/25 RAIDA - %s\n",
coin.SerialNumber, coin.Denomination,
coin.RaidaPass, status)
}
}
Related Endpoints
/api/transactions/locker/upload
Upload coins using XOR-sum verification (all-or-nothing authentication). Faster for trusted coins.
/api/locker/peek
View the contents of a locker without downloading the coins. Check what's inside before downloading.
/api/transactions/locker/download
Download coins from a locker to your wallet using the locker key.
Implementation Notes
- Test First: Use
amount=1when testing to minimize risk - Check Balance: Ensure wallet has coins before uploading
- Review Results: Always check the
coin_resultsarray to see which coins were accepted - Handle Partial Success: If
coins_accepted < coins_sent, failed coins remain in the wallet and may need frack-fix - Secure Keys: Use memorable but unpredictable locker keys
- Share Safely: Only share locker keys through secure channels
- Low raida_pass count: Coin's ANs may be out of sync with the RAIDA. Run frack-fix on the wallet first.
- 0 coins accepted: All coins may be counterfeit or have corrupted ANs. Check coin details.
- Partial acceptance: Some coins passed, others failed. Failed coins stay in Bank/Fracked. The accepted value (not the requested amount) is logged in the transaction.
- Insufficient change: If exact change can't be made after 3 auto-break attempts, the request fails with HTTP 400.