Skip to main content
This page covers everything you need to handle errors gracefully: HTTP codes, commit statuses, signature debugging, and health monitoring.

HTTP Status Codes

CodeMeaningAction
200SuccessParse response normally
400Bad request: invalid body or parametersCheck request schema
401Unauthorized: invalid or missing API key, or signature verification failedCheck x-api-key header and signing format
500Internal server errorRetry; check GET /health
If you’re seeing an unexpected error, join our Discord and the team will help you debug it.

Commit Status

The /commit endpoint returns a status field rather than an HTTP error for action-level outcomes. Always check this field after committing.
StatusDescriptionAction
completedAction processed successfully: balances have been updatedContinue normally
rejectedDeposit failed compliance or risk screening: funds will be refunded to the originating wallet after extended screening is completedNotify the user; do not re-attempt
pendingWaiting for the transaction to land on-chain or undergo compliance screeningPoll /commit again shortly with the same tx_id
failedThe transaction was rejected on-chain: the user’s balance is no longer in a pending stateInform the user; check the on-chain transaction
expiredThe transaction was not confirmed within the required window: the user’s balance is no longer in a pending stateInform the user
A rejected, failed, or expired status still means the commit succeeded. The balance is no longer in a pending state. No further action is required.

Idempotency

/commit is idempotent. If you call it twice with the same tx_id, the second call returns already_processed: true and the same status as the first call. This is safe - use it to confirm commit state after a crash or retry.
const commit = await vanish('/commit', {
  method: 'POST',
  body: JSON.stringify({ tx_id }),
});

if (commit.already_processed) {
  // Already committed - use commit.status to determine what happened
  console.log('Previously resolved:', commit.status);
} else {
  console.log('Freshly committed:', commit.status, commit.balance_changes);
}

Recovering Pending Commits

If a transaction is submitted but /commit is never called - due to a crash, timeout, or network issue - the user’s balance remains in a pending state. Use POST /account/pending on startup to detect and recover these states:
async function recoverPendingCommits(userKeypair: Keypair) {
  const timestamp = Date.now().toString();
  const signature = readSignature(timestamp, userKeypair);

  const pending = await vanish('/account/pending', {
    method: 'POST',
    body: JSON.stringify({
      user_address: userKeypair.publicKey.toBase58(),
      timestamp,
      signature,
    }),
  });

  for (const action of pending) {
    const commit = await vanish('/commit', {
      method: 'POST',
      body: JSON.stringify({ tx_id: action.tx_id }),
    });
    // already_processed: true means it was already committed - safe to skip
    if (!commit.already_processed) {
      console.log(`Resolved ${action.action_type}:`, commit.status);
    }
  }
}

Handling 401 - Signature Errors

The most common cause of a 401 on signed endpoints is a malformed signature message. Check:
  1. Message format - the ToS header line and Details: line must match exactly, including the newlines.
  2. Timestamp - must be Unix time in milliseconds, not seconds. Stale timestamps are rejected.
  3. Signing key - must be the Ed25519 secret key of user_address, not any other key.
  4. Encoding - the signature must be base64-encoded, not base58 or hex.
The most common mistake is passing seconds instead of milliseconds for the timestamp. Use Date.now() in TypeScript or timestamp_millis() in Rust - not Date.now() / 1000 or timestamp().
import * as nacl from 'tweetnacl';
import { Keypair } from '@solana/web3.js';

// Correct signing pattern
const timestamp = Date.now().toString(); // milliseconds

const message = [
  "By signing, I hereby agree to Vanish's Terms of Service and agree to be bound by them (docs.vanish.trade/legal/TOS)",
  "",
  `Details: read:${timestamp}`,
].join('\n');

const sig       = nacl.sign.detached(new TextEncoder().encode(message), keypair.secretKey);
const signature = Buffer.from(sig).toString('base64');

Health Check

Use GET /health to verify API availability or plug it into your monitoring stack for uptime alerts. It requires no signed request - just your API key.
async function checkHealth(): Promise<boolean> {
  const res = await fetch('https://core-api.vanish.trade/health', {
    headers: { 'x-api-key': process.env.VANISH_API_KEY! },
  });
  return res.ok; // true if 200 "healthy"
}

Experiencing an issue not covered here? Join us on Discord - our engineers are available to help.