Skip to main content

Overview

This page provides a complete reference of all transfer status codes returned by the CashQ API. Use these codes to understand the current state of a money transfer.

Status Code Structure

Each transfer status consists of three components:

State

Primary status indicator showing the general transfer state

Substate

Additional detail about the current state

Final

Indicates if the status is terminal (0 = in progress, 1 = complete)

Quick Reference

Key States

StateDescriptionFinalAction Required
60SuccessYesNone - transfer completed
80ErrorYesCheck error details
40ProcessingNoWait for completion
0NewNoTransfer just created
-2Not FoundYesVerify transfer ID

Complete Status Table

StateSubstateFinalDescription
00, 1, 2NoNew - Transfer created
09NoAwaiting confirmation
201NoReady to debit
202, 3NoDebiting account
204NoNot enough funds in account
30-NoVerify
301NoReady to verify
302NoVerify, in process
303NoVerify, unknown
40-NoProcessing
401NoReady to process
402, 3NoIn process
404, 5, 6, 7NoProcessing error
60-Yes✅ Success (final)
80-Yes❌ Error (final)
801, 2, 3NoCancelled by support
804NoNot enough funds
805NoProcessing error
806NoAnother error
-10NoDatabase insertion error (not final)
-20YesPayment not found (final)

Status Categories

Success States

Description: Transfer completed successfullyFinal: YesAction: No action required. Transfer is complete.Example Response:
{
  "status": {
    "result": {
      "state": 60,
      "substate": 0,
      "final": 1,
      "id": "123456789"
    }
  }
}

In-Progress States

Description: Transfer has been created and is being initializedFinal: NoAction: Wait for processing to begin. Status will update automatically.Substates:
  • 0, 1, 2: New transfer
  • 9: Awaiting confirmation
Description: Funds are being debited from merchant accountFinal: NoAction: Wait for debit to complete.Substates:
  • 1: Ready to debit
  • 2, 3: Debiting in progress
  • 4: Not enough funds (may become final error)
Description: Transfer is being verifiedFinal: NoAction: Wait for verification to complete.Substates:
  • 1: Ready to verify
  • 2: Verification in process
  • 3: Verification status unknown
Description: Transfer is being processed by payment providerFinal: NoAction: Wait for processing to complete. This is the most common in-progress state.Substates:
  • 1: Ready to process
  • 2, 3: Processing in progress
  • 4, 5, 6, 7: Processing error (may recover or become final error)

Error States

Description: Transfer failedFinal: Yes (when substate indicates final error)Action: Check error details in the attribute array. Transfer cannot be recovered.Substates:
  • 1, 2, 3: Cancelled by support
  • 4: Not enough funds
  • 5: Processing error
  • 6: Another error
Example with Error Details:
{
  "status": {
    "result": {
      "state": 80,
      "substate": 5,
      "final": 1,
      "attribute": [
        {
          "name": "provider-error-text",
          "value": "Recipient account closed"
        },
        {
          "name": "provider-error-code",
          "value": "100"
        }
      ]
    }
  }
}
Description: Database insertion error occurredFinal: NoAction: This is typically a transient error. The system will retry automatically.
Description: Transfer ID doesn’t existFinal: YesAction: Verify the transfer ID is correct. Check if transfer was created in the same environment (sandbox vs production).Example Response:
{
  "payment_response": {
    "payment_id": null,
    "state": "-2",
    "substate": "0",
    "code": "0",
    "id": "123456789"
  },
  "error": "",
  "success": true
}

Understanding the Final Flag

The final field indicates whether a transfer has reached a terminal state:

Final = 0 (In Progress)

  • Transfer is still being processed
  • Status may change
  • Continue polling for updates
  • Don’t show final result to users yet

Final = 1 (Complete)

  • Transfer has reached a terminal state
  • Status will not change
  • Stop polling for updates
  • Show final result to users (success or failure)

Error Attributes

When a transfer fails (state 80), the attribute array may contain additional error information from the payment provider:

Common Attributes

provider-error-text
string
Human-readable error message from the payment provider
provider-error-code
string
Error code from the payment provider

Example

"attribute": [
  {
    "name": "provider-error-text",
    "value": "Insufficient funds"
  },
  {
    "name": "provider-error-code",
    "value": "100"
  }
]

Handling Status Codes

Basic Status Check

function interpretStatus(statusResult) {
  const { state, substate, final } = statusResult;
  
  // Check if complete
  if (final === 1) {
    if (state === 60) {
      return { status: 'success', message: 'Transfer completed' };
    } else if (state === 80) {
      const error = extractErrorFromAttributes(statusResult.attribute);
      return { status: 'failed', message: error || 'Transfer failed' };
    } else if (state === -2) {
      return { status: 'not_found', message: 'Transfer not found' };
    }
  }
  
  // In progress
  return { status: 'pending', message: getProgressMessage(state, substate) };
}

function getProgressMessage(state, substate) {
  if (state === 0) return 'Transfer initiated';
  if (state === 20) return 'Debiting account';
  if (state === 30) return 'Verifying transfer';
  if (state === 40) return 'Processing transfer';
  return 'Processing';
}

function extractErrorFromAttributes(attributes) {
  if (!attributes || attributes.length === 0) return null;
  
  const errorText = attributes.find(attr => attr.name === 'provider-error-text');
  return errorText?.value || null;
}

Polling Strategy

async function pollUntilFinal(transferId, maxAttempts = 30) {
  for (let i = 0; i < maxAttempts; i++) {
    const response = await fetch(
      `https://api.cashqbot.com/api/status/${transferId}`,
      { headers: { 'API-KEY': apiKey } }
    );
    
    const data = await response.json();
    const result = data.status.result;
    
    // Check if final
    if (result.final === 1) {
      return interpretStatus(result);
    }
    
    // Log progress
    console.log(`Transfer ${transferId}: State ${result.state}, Substate ${result.substate}`);
    
    // Wait before next poll (exponential backoff)
    const delay = Math.min(1000 * Math.pow(1.5, i), 10000);
    await new Promise(resolve => setTimeout(resolve, delay));
  }
  
  throw new Error('Polling timeout - transfer still in progress');
}

User-Friendly Messages

const statusMessages = {
  0: { text: 'Transfer initiated', color: 'blue', icon: 'clock' },
  20: { text: 'Processing payment', color: 'blue', icon: 'gear' },
  30: { text: 'Verifying details', color: 'blue', icon: 'shield' },
  40: { text: 'Transfer in progress', color: 'blue', icon: 'spinner' },
  60: { text: 'Transfer completed', color: 'green', icon: 'check' },
  80: { text: 'Transfer failed', color: 'red', icon: 'x' },
  '-2': { text: 'Transfer not found', color: 'gray', icon: 'question' }
};

function getUserMessage(state) {
  return statusMessages[state] || statusMessages[40];
}

Best Practices

Check Final Flag

Always check the final field to know when to stop polling

Handle All States

Account for all possible states in your code, not just success and error

Extract Error Details

Parse the attribute array for detailed error information

Use Exponential Backoff

Increase polling intervals to reduce API calls