/join

POST ASYNC

Consolidates coins to a higher denomination.

POST /api/v1/join
Alias: /consolidate-coins

Description

This endpoint initiates an operation to consolidate coins within a given wallet. The system automatically finds a suitable denomination and exchanges ten coins for a single coin of the next higher denomination (e.g., ten 1-CloudCoin notes become one 10-CloudCoin note). This is useful for optimizing a wallet, especially before transferring coins to a locker.

Asynchronous Operation

This is a long-running, asynchronous operation because it requires communication with the RAIDA to perform the exchange. The API responds immediately with a task ID, and the process runs in the background. You must poll the /tasks/{id} endpoint to get the final result.

Request Body

The request must be a JSON object specifying the wallet to process.

Request Body Parameters

Parameter Type Required Description
name string Yes The name of the wallet in which to consolidate coins.

Example Request Body

{
    "name": "Default"
}

Response

The initial response is a `200 OK` containing a `TaskResponse` object with the ID for the background job.

Initial Response from POST /join

{
    "status": "success",
    "payload": {
        "id": "d1e2f3a4-b5c6-7890-1234-567890abcdef",
        "status": "running",
        "progress": 0,
        "message": "Command Started",
        "data": null
    }
}

Final Result from Polling /tasks/{id}

After the task completes, polling the task status endpoint will show a `completed` status. On success, the `data` field will contain the string "OK".

{
    "status": "success",
    "payload": {
        "id": "d1e2f3a4-b5c6-7890-1234-567890abcdef",
        "status": "completed",
        "progress": 100,
        "message": "Command Completed",
        "data": "OK"
    }
}

Examples

JavaScript Example

const apiHost = 'http://localhost:8006';

// Function to poll the task status
async function pollTask(taskId) {
    const taskResponse = await fetch(`${apiHost}/api/v1/tasks/${taskId}`);
    const taskData = await taskResponse.json();
    const task = taskData.payload;

    console.log(`Task ${taskId} progress: ${task.progress}% - ${task.message}`);

    if (task.status === 'completed') {
        console.log(' Coin consolidation finished successfully:', task.data);
        return true; // Stop polling
    } else if (task.status === 'error') {
        console.error('Task failed:', task.message);
        return true; // Stop polling
    }
    return false; // Continue polling
}

// Main function to start the join process
async function startJoinProcess(walletName) {
    try {
        // Step 1: Call the /join endpoint to start consolidation
        const initialResponse = await fetch(`${apiHost}/api/v1/join`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ name: walletName })
        });

        if (!initialResponse.ok) {
            throw new Error(`HTTP error! status: ${initialResponse.status}`);
        }

        const taskInfo = await initialResponse.json();
        const taskId = taskInfo.payload.id;
        console.log(`Consolidation task created with ID: ${taskId}`);

        // Step 2: Poll for the result
        const pollInterval = setInterval(async () => {
            const isDone = await pollTask(taskId);
            if (isDone) {
                clearInterval(pollInterval);
            }
        }, 3000); // Check every 3 seconds

    } catch (error) {
        console.error('Error initiating join task:', error);
    }
}

// Start the process for the "Default" wallet
startJoinProcess('Default');

cURL Example

# Step 1: Initiate the join task
TASK_ID=$(curl -s -X POST "http://localhost:8006/api/v1/join" \
 -H "Content-Type: application/json" \
 -d '{"name":"Default"}' | jq -r '.payload.id')

echo "Join task started with ID: $TASK_ID"

# Step 2: Poll the task endpoint until finished
while true; do
  RESPONSE=$(curl -s "http://localhost:8006/api/v1/tasks/$TASK_ID")
  STATUS=$(echo $RESPONSE | jq -r '.payload.status')
  echo "Polling task.. Status: $STATUS"
  
  if [[ "$STATUS" == "completed" ]] || [[ "$STATUS" == "error" ]]; then
    echo "Final Response:"
    echo $RESPONSE | jq
    break
  fi
  
  sleep 2
done

Go Example

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"time"
)

type Task struct {
	ID       string      `json:"id"`
	Status   string      `json:"status"`
	Progress int         `json:"progress"`
	Message  string      `json:"message"`
	Data     interface{} `json:"data"`
}

type TaskResponse struct {
	Status  string `json:"status"`
	Payload Task   `json:"payload"`
}

// startJoinProcess initiates the coin consolidation operation.
func startJoinProcess(walletName string) (string, error) {
	apiHost := "http://localhost:8006"
	payload, _ := json.Marshal(map[string]string{"name": walletName})

	resp, err := http.Post(fmt.Sprintf("%s/api/v1/join", apiHost), "application/json", bytes.NewBuffer(payload))
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	var taskResp TaskResponse
	if err := json.NewDecoder(resp.Body).Decode(&taskResp); err != nil {
		return "", err
	}

	if taskResp.Status != "success" {
		return "", fmt.Errorf("API error: %s", taskResp.Payload.Message)
	}

	fmt.Printf("Coin consolidation task started with ID: %s\n", taskResp.Payload.ID)
	return taskResp.Payload.ID, nil
}

// pollTaskStatus checks the status of a task until it completes or fails.
func pollTaskStatus(taskId string) {
	apiHost := "http://localhost:8006"
	for {
		resp, err := http.Get(fmt.Sprintf("%s/api/v1/tasks/%s", apiHost, taskId))
		if err != nil {
			fmt.Printf("Error polling task: %v\n", err)
			return
		}

		var taskResp TaskResponse
		json.NewDecoder(resp.Body).Decode(&taskResp)
		resp.Body.Close()

		fmt.Printf("Polling... Status: %s, Progress: %d%%\n", taskResp.Payload.Status, taskResp.Payload.Progress)

		if taskResp.Payload.Status == "completed" {
			fmt.Printf("Task completed successfully. Result: %v\n", taskResp.Payload.Data)
			return
		} else if taskResp.Payload.Status == "error" {
			fmt.Printf("Task failed: %s\n", taskResp.Payload.Message)
			return
		}

		time.Sleep(3 * time.Second)
	}
}

func main() {
    // Step 1: Start the join process
	taskId, err := startJoinProcess("Default")
	if err != nil {
		panic(err)
	}
    
    // Step 2: Poll for the result
	if taskId != "" {
		pollTaskStatus(taskId)
	}
}