/api/raida/lockers/peek
GETView the contents of a CloudCoin locker without removing coins. Non-destructive read-only operation.
Description
The /api/raida/lockers/peek endpoint allows you to view the contents of a CloudCoin locker without transferring ownership of the coins. This is a non-destructive operation - coins remain in the locker after peeking.
The endpoint queries all 25 RAIDA servers in parallel using the Locker Peek command (0x0853) and requires cloud consensus (13+ successful responses) to return the coin list. This ensures the locker exists and the key is correct before any destructive operations.
This endpoint is perfect for:
- Pre-download verification: Confirm locker key is correct before downloading coins
- Inventory checking: View locker contents without removing coins
- Upload confirmation: Verify coins were uploaded successfully
- Sharing with recipient: Show locker contents before transfer
- Balance verification: Calculate total value before download
- Peek (0x0853): View-only operation, coins remain in locker, can be called multiple times
- Download (0x0854): Transfers ownership, coins removed from locker, destructive operation
Use /api/raida/lockers/peek to verify before using /api/transactions/locker/download.
Parameters
This endpoint requires one query parameter:
Query Parameters
a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6
RAIDA Protocol
This endpoint uses the RAIDA Locker Peek command (0x0853) to query locker contents:
Command Details
Cloud Consensus
The endpoint requires cloud consensus from RAIDA servers to determine if a locker exists:
Consensus Thresholds
- <13 responses: Network issues (503 Service Unavailable)
- <13 successful peeks: Wrong key or locker doesn't exist (404 Not Found)
- 13+ successful peeks: Valid locker, returns coin list (200 OK)
Response
Returns a JSON object with locker contents and RAIDA response details.
Response Properties
raida_id(number): RAIDA server ID (0-24)received(boolean): Whether RAIDA respondedstatus(string): Response status (e.g., "ALL_PASS", "ALL_FAIL")coin_count(number): Number of coins reported by this RAIDA
denomination(string): Human-readable denomination (e.g., "100", "250")serial_number(number): Unique serial numbervalue(number): Numeric value of the coin
Success Response (200 OK)
{
"status": "success",
"operation": "locker_peek",
"successful_peeks": 24,
"responses_received": 25,
"coin_count": 5,
"raida_responses": [
{
"raida_id": 0,
"received": true,
"status": "ALL_PASS",
"coin_count": 5
},
{
"raida_id": 1,
"received": true,
"status": "ALL_PASS",
"coin_count": 5
},
// ... 23 more RAIDA responses ...
],
"coins": [
{
"denomination": "100",
"serial_number": 12345,
"value": 100
},
{
"denomination": "250",
"serial_number": 67890,
"value": 250
},
{
"denomination": "25",
"serial_number": 54321,
"value": 25
},
{
"denomination": "5",
"serial_number": 98765,
"value": 5
},
{
"denomination": "1",
"serial_number": 13579,
"value": 1
}
]
}
Error Response - Invalid Locker Key (400 Bad Request)
{
"status": "error",
"message": "Invalid locker_key (must be 32 hex characters)",
"error_code": 400
}
Error Response - Locker Not Found (404 Not Found)
{
"status": "error",
"message": "Locker not found",
"error_code": 404
}
Error Response - Insufficient RAIDA Responses (503 Service Unavailable)
{
"status": "error",
"message": "Insufficient RAIDA responses",
"error_code": 503
}
Examples
JavaScript (fetch)
const API_HOST = 'http://localhost:8080';
async function peekLocker(lockerKey) {
try {
const response = await fetch(
`${API_HOST}/api/raida/lockers/peek?locker_key=${lockerKey}`
);
if (!response.ok) {
const error = await response.json();
console.error(`Error ${error.error_code}: ${error.message}`);
return;
}
const result = await response.json();
console.log(`Locker Peek Results:`);
console.log(`Successful Peeks: ${result.successful_peeks}/25`);
console.log(`Responses Received: ${result.responses_received}/25`);
console.log(`Total Coins: ${result.coin_count}`);
console.log(`\nCoins in Locker:`);
let totalValue = 0;
result.coins.forEach(coin => {
console.log(` - ${coin.denomination} CloudCoin #${coin.serial_number}`);
totalValue += coin.value;
});
console.log(`\nTotal Value: ${totalValue} CloudCoins`);
} catch (error) {
console.error('Error peeking locker:', error);
}
}
// Example: Peek a locker
const lockerKey = 'a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6';
peekLocker(lockerKey);
cURL
# Peek a locker to view contents
curl -X GET "http://localhost:8080/api/raida/lockers/peek?locker_key=a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
# Example with jq to format JSON output
curl -s -X GET "http://localhost:8080/api/raida/lockers/peek?locker_key=a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6" | jq .
# Extract just the coin count
curl -s -X GET "http://localhost:8080/api/raida/lockers/peek?locker_key=a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6" | jq '.coin_count'
# Extract coin list
curl -s -X GET "http://localhost:8080/api/raida/lockers/peek?locker_key=a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6" | jq '.coins'
Go
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
const ApiHost = "http://localhost:8080"
type Coin struct {
Denomination string `json:"denomination"`
SerialNumber int `json:"serial_number"`
Value int `json:"value"`
}
type RaidaResponse struct {
RaidaID int `json:"raida_id"`
Received bool `json:"received"`
Status string `json:"status"`
CoinCount int `json:"coin_count"`
}
type LockerPeekResponse struct {
Status string `json:"status"`
Operation string `json:"operation"`
SuccessfulPeeks int `json:"successful_peeks"`
ResponsesReceived int `json:"responses_received"`
CoinCount int `json:"coin_count"`
RaidaResponses []RaidaResponse `json:"raida_responses"`
Coins []Coin `json:"coins"`
}
type ErrorResponse struct {
Status string `json:"status"`
Message string `json:"message"`
ErrorCode int `json:"error_code"`
}
func peekLocker(lockerKey string) error {
url := fmt.Sprintf("%s/api/raida/lockers/peek?locker_key=%s", ApiHost, lockerKey)
resp, err := http.Get(url)
if err != nil {
return fmt.Errorf("request failed: %w", err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("read body failed: %w", err)
}
if resp.StatusCode != http.StatusOK {
var errResp ErrorResponse
if err := json.Unmarshal(body, &errResp); err != nil {
return fmt.Errorf("decode error failed: %w", err)
}
return fmt.Errorf("error %d: %s", errResp.ErrorCode, errResp.Message)
}
var result LockerPeekResponse
if err := json.Unmarshal(body, &result); err != nil {
return fmt.Errorf("decode response failed: %w", err)
}
// Display results
fmt.Printf("Locker Peek Results:\n")
fmt.Printf("Successful Peeks: %d/25\n", result.SuccessfulPeeks)
fmt.Printf("Responses Received: %d/25\n", result.ResponsesReceived)
fmt.Printf("Total Coins: %d\n\n", result.CoinCount)
fmt.Println("Coins in Locker:")
totalValue := 0
for _, coin := range result.Coins {
fmt.Printf(" - %s CloudCoin #%d\n", coin.Denomination, coin.SerialNumber)
totalValue += coin.Value
}
fmt.Printf("\nTotal Value: %d CloudCoins\n", totalValue)
return nil
}
func main() {
lockerKey := "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
if err := peekLocker(lockerKey); err != nil {
fmt.Printf("Error: %v\n", err)
}
}
Related Endpoints
/api/transactions/locker/download
Download coins from a locker and transfer ownership to your wallet. Destructive operation that removes coins from locker.
/api/raida/audit
Count total coins stored across the entire RAIDA network. Public endpoint requiring no authentication.
Implementation Notes
- Parallel Execution: All 25 RAIDA requests execute simultaneously for optimal performance
- Timeout: 10-second total timeout for all parallel requests
- Production Ready: Fully implemented and tested
- Read-Only: No modifications to locker contents or coin ownership
- Idempotent: Can be called multiple times without side effects
- No Authentication: Locker key serves as both identifier and password
- Key Confidentiality: Locker keys must be kept secret - anyone with the key can access locker contents
- HTTPS Recommended: Use HTTPS in production to protect locker keys in transit
- Key Length: Must be exactly 32 hex characters (16 bytes) - shorter or longer keys will be rejected
- Rate Limiting: Consider implementing rate limiting to prevent brute-force key guessing
Workflow Example
A typical locker transfer workflow using peek before download:
Complete Workflow
const API_HOST = 'http://localhost:8080';
async function receiveLockerTransfer(lockerKey) {
try {
// Step 1: Peek to verify locker contents
console.log('Step 1: Peeking locker...');
const peekResp = await fetch(
`${API_HOST}/api/raida/lockers/peek?locker_key=${lockerKey}`
);
if (!peekResp.ok) {
const error = await peekResp.json();
throw new Error(`Peek failed: ${error.message}`);
}
const peekData = await peekResp.json();
console.log(`Found ${peekData.coin_count} coins in locker`);
// Step 2: Calculate total value
const totalValue = peekData.coins.reduce((sum, coin) => sum + coin.value, 0);
console.log(`Total value: ${totalValue} CloudCoins`);
// Step 3: Confirm with user (in real app, show UI dialog)
console.log('Confirm download? (yes/no)');
// Assuming user confirms...
// Step 4: Download coins from locker
console.log('Step 2: Downloading coins...');
const downloadResp = await fetch(
`${API_HOST}/api/transactions/locker/download?locker_key=${lockerKey}`
);
if (!downloadResp.ok) {
const error = await downloadResp.json();
throw new Error(`Download failed: ${error.message}`);
}
const downloadData = await downloadResp.json();
console.log(`Successfully downloaded ${downloadData.coins_downloaded} coins`);
console.log(`Files saved to: ${downloadData.import_folder}`);
// Step 5: Verify locker is now empty (optional)
console.log('Step 3: Verifying locker is empty...');
const verifyResp = await fetch(
`${API_HOST}/api/raida/lockers/peek?locker_key=${lockerKey}`
);
const verifyData = await verifyResp.json();
if (verifyData.coin_count === 0) {
console.log('✓ Locker is now empty - transfer complete');
} else {
console.warn(`⚠ Warning: ${verifyData.coin_count} coins still in locker`);
}
} catch (error) {
console.error('Transfer failed:', error.message);
}
}
// Example usage
const receivedLockerKey = 'a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6';
receiveLockerTransfer(receivedLockerKey);