Fix Binance API Signature Error -1022 in TypeScript for Fiat Withdrawals
Learn how to fix Binance API signature error (-1022) when making fiat withdrawals with nested parameters in TypeScript. Proper parameter formatting and HMAC-SHA256 signature generation.
How to fix Binance API signature error (-1022) when making fiat withdrawals with nested parameters in TypeScript? I’m receiving ‘Signature for this request is not valid’ when trying to withdraw fiat currency using the sapi/v2/fiat/withdraw endpoint. My current implementation stringifies nested objects like accountInfo in the query string, but I’m unsure if this is the correct approach according to Binance’s API documentation. What is the proper way to format POST requests with nested parameters for Binance API signature generation?
Binance API signature error (-1022) occurs when the signature generation for your fiat withdrawal request with nested parameters in TypeScript doesn’t match Binance’s expected format. The “Signature for this request is not valid” error specifically indicates that your HMAC-SHA256 signature calculation is incorrect, likely due to improper handling of nested objects in the sapi/v2/fiat/withdraw endpoint parameters.
Contents
- Understanding Binance API Signature Error -1022
- Binance Fiat Withdrawal API Endpoint Requirements
- Proper Parameter Formatting for Nested Objects
- TypeScript Implementation for Signature Generation
- Complete Fiat Withdrawal Example
- Common Pitfalls and Debugging Tips
- Binance API Authentication Best Practices
- Testing and Validation
Understanding Binance API Signature Error -1022
The error code -1022 from Binance API indicates “Signature for this request is not valid,” which is one of the most common authentication issues developers encounter. This error occurs when the HMAC-SHA256 signature you generate doesn’t match what Binance calculates on their end.
According to the official Binance documentation, signed endpoints require precise signature generation. The signature is an HMAC-SHA256 hash of either the request query string (for GET requests) or the request body (for POST requests), using your API secret as the key.
When working with nested parameters like accountInfo in fiat withdrawal requests, many developers mistakenly stringify these objects as JSON, which leads to signature mismatch. Binance doesn’t accept JSON-encoded bodies for signed requests - all parameters must be sent as URL-encoded form data with proper nesting notation.
Binance Fiat Withdrawal API Endpoint Requirements
The sapi/v2/fiat/withdraw endpoint has specific requirements that differ from standard REST API conventions. Before implementing your solution, it’s crucial to understand these requirements to avoid signature errors.
The official Binance fiat withdrawal documentation states that this endpoint currently only supports BRL withdrawals via bank_transfer. Before calling this API, you must have completed KYC/KYB verification and activated your fiat service on the Binance website.
For TypeScript developers working with nested parameters, the key insight is that Binance expects parameters to be properly encoded in the request body or query string, not as JSON objects. This means you need to flatten nested structures using either dot notation (accountInfo.bankName) or bracket notation (accountInfo[bankName]) before sending the request.
Proper Parameter Formatting for Nested Objects
The root cause of your signature error is likely improper handling of nested parameters in TypeScript. When working with objects like accountInfo that contain nested properties, you must format them according to Binance’s specific requirements.
According to Binance’s signature examples, nested parameters should be flattened using dot notation. For example, if you have an object structure like:
const withdrawalParams = {
amount: "1000.00",
currency: "BRL",
accountInfo: {
bankName: "Banco do Brasil",
accountNumber: "123456789",
branchCode: "1234"
}
};
You need to convert this to a flat structure where nested properties are separated by dots:
const flatParams = {
amount: "1000.00",
currency: "BRL",
accountInfo.bankName: "Banco do Brasil",
accountInfo.accountNumber: "123456789",
accountInfo.branchCode: "1234"
};
Alternatively, you can use bracket notation:
const flatParams = {
amount: "1000.00",
currency: "BRL",
"accountInfo[bankName]": "Banco do Brasil",
"accountInfo[accountNumber]": "123456789",
"accountInfo[branchCode]": "1234"
};
This flattening process is essential because Binance’s signature calculation expects parameters to be in this format, not as nested JSON objects.
TypeScript Implementation for Signature Generation
Implementing proper signature generation in TypeScript requires careful attention to how you construct the request parameters and calculate the HMAC-SHA256 hash. The Binance TypeScript connector provides a reference implementation that follows best practices.
For POST requests with nested parameters, you need to:
- Flatten all nested objects using dot or bracket notation
- Create a query string from the flattened parameters
- Include the timestamp parameter
- Generate the signature using HMAC-SHA256
Here’s a TypeScript function that properly handles nested parameters:
import crypto from 'crypto';
/**
* Flattens nested objects into dot notation or bracket notation
* @param obj The object to flatten
* @param prefix Internal use for recursion
* @param useDotNotation Whether to use dot notation (true) or bracket notation (false)
* @returns Flattened object
*/
function flattenObject(obj: any, prefix = '', useDotNotation = true): Record<string, string> {
const flattened: Record<string, string> = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
const type = typeof obj[key];
const newPrefix = prefix ? (useDotNotation ? `${prefix}.${key}` : `${prefix}[${key}]`) : key;
if (type === 'object' && obj[key] !== null && !Array.isArray(obj[key])) {
Object.assign(flattened, flattenObject(obj[key], newPrefix, useDotNotation));
} else {
flattened[newPrefix] = String(obj[key]);
}
}
}
return flattened;
}
/**
* Generates query string from flattened parameters sorted alphabetically
* @param params Flattened parameters object
* @returns URL-encoded query string
*/
function generateQueryString(params: Record<string, string>): string {
return Object.keys(params)
.sort()
.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
.join('&');
}
/**
* Generates Binance API signature for POST requests
* @param params Request parameters (should include timestamp)
* @param apiSecret Your API secret key
* @returns HMAC-SHA256 signature
*/
function generateSignature(params: Record<string, string>, apiSecret: string): string {
const queryString = generateQueryString(params);
return crypto
.createHmac('sha256', apiSecret)
.update(queryString)
.digest('hex');
}
// Usage example for fiat withdrawal
const withdrawalRequest = {
timestamp: Date.now(),
amount: "1000.00",
currency: "BRL",
accountInfo: {
bankName: "Banco do Brasil",
accountNumber: "123456789",
branchCode: "1234"
}
};
// Flatten the object using dot notation
const flattenedParams = flattenObject(withdrawalRequest, '', true);
// Generate the signature
const signature = generateSignature(flattenedParams, 'YOUR_API_SECRET');
// Add signature to parameters
flattenedParams.signature = signature;
// Now you can make the POST request with these parameters
This implementation properly handles nested parameters and generates the correct signature according to Binance’s requirements.
Complete Fiat Withdrawal Example
Here’s a complete TypeScript example showing how to make a fiat withdrawal request with nested parameters:
import axios from 'axios';
import crypto from 'crypto';
// Configuration
const API_KEY = 'YOUR_API_KEY';
const API_SECRET = 'YOUR_API_SECRET';
const BASE_URL = 'https://api.binance.com';
// Function to create fiat withdrawal
async function createFiatWithdrawal() {
try {
// Request parameters with nested object
const params = {
timestamp: Date.now(),
amount: "1000.00",
currency: "BRL",
accountInfo: {
bankName: "Banco do Brasil",
accountNumber: "123456789",
branchCode: "1234"
}
};
// Flatten the parameters using dot notation
const flattenedParams = flattenObject(params, '', true);
// Generate signature
const signature = generateSignature(flattenedParams, API_SECRET);
flattenedParams.signature = signature;
// Make the POST request
const response = await axios.post(
`${BASE_URL}/sapi/v2/fiat/withdraw`,
flattenedParams,
{
headers: {
'X-MBX-APIKEY': API_KEY
}
}
);
console.log('Withdrawal created successfully:', response.data);
} catch (error) {
if (error.response) {
console.error('Binance API Error:', error.response.data);
} else {
console.error('Error:', error.message);
}
}
}
// Helper functions (same as shown above)
function flattenObject(obj: any, prefix = '', useDotNotation = true): Record<string, string> {
// Implementation from previous section
}
function generateQueryString(params: Record<string, string>): string {
// Implementation from previous section
}
function generateSignature(params: Record<string, string>, apiSecret: string): string {
// Implementation from previous section
}
// Execute the function
createFiatWithdrawal();
This example demonstrates the complete flow from parameter preparation to making the API request with proper signature generation.
Common Pitfalls and Debugging Tips
Even with proper implementation, you might still encounter signature errors. Here are some common pitfalls and debugging tips:
-
Incorrect Parameter Sorting: Binance requires parameters to be sorted alphabetically before signature generation. Double-check that your sorting is case-sensitive.
-
URL Encoding Issues: Ensure all parameter values are properly URL-encoded. The Binance API common rules specify that all parameters must be URL-encoded.
-
Timestamp Mismatch: Your timestamp must be within the API’s allowed time window (typically 30 seconds). Use
Date.now()for millisecond precision. -
Missing Required Parameters: The fiat withdrawal endpoint requires specific parameters. Check the official documentation for all required fields.
-
Incorrect Secret Key: Verify that you’re using the correct API secret key. Test with a known working example if possible.
-
Debugging Signature: To debug signature issues, log the query string before signing and compare it with what Binance expects. According to community discussions, this is the most effective debugging approach.
-
Testing in Sandbox: If available, use Binance’s sandbox environment to test your implementation without affecting real funds.
Binance API Authentication Best Practices
To avoid signature errors and ensure secure API usage, follow these best practices:
-
Store API Keys Securely: Never hardcode API keys in your source code. Use environment variables or secure secret management systems.
-
Use Request Libraries: Consider using the official Binance TypeScript connector which handles many authentication details automatically.
-
Validate Parameters Before Sending: Implement client-side validation to ensure all required parameters are present and properly formatted before making API calls.
-
Handle Rate Limiting: Binance API has rate limits. Implement proper error handling for 429 status codes and exponential backoff retry logic.
-
Monitor API Usage: Keep track of your API usage to stay within rate limits and detect any unusual activity.
-
Regular Key Rotation: Periodically rotate your API keys to enhance security.
-
Use IP Whitelisting: If supported, whitelist your server’s IP address in the Binance API settings for added security.
Testing and Validation
After implementing your solution, proper testing is crucial to ensure everything works correctly:
-
Test with Known Parameters: Use the exact same parameters that Binance provides in their documentation or examples to verify your implementation.
-
Check Timestamp Precision: Ensure you’re using millisecond timestamps as required by Binance’s API.
-
Verify Parameter Order: Confirm that parameters are sorted alphabetically before generating the signature.
-
Test Different Parameter Types: Test with various parameter types (strings, numbers, booleans) to ensure proper formatting.
-
Use Binance’s Testnet: If available, use Binance’s test environment to validate your implementation without risking real funds.
-
Compare with Working Examples: Compare your implementation with the official signature examples to identify any discrepancies.
-
Monitor Response Times: Signature issues might also manifest as unexpected response times or timeout errors.
By following these guidelines and implementing proper parameter flattening and signature generation in TypeScript, you should be able to resolve the Binance API signature error (-1022) when making fiat withdrawals with nested parameters.
Sources
- Fiat Withdraw | Binance Open Platform - Official documentation for the fiat withdrawal API endpoint
- GitHub - binance/binance-signature-examples - Examples of generating HMAC and RSA signature for Binance API
- API Specification Common Rules | Binance Open Platform - Common rules for Binance API requests including signature generation
- GitHub - binance/binance-connector-typescript - Simple Typescript connector to Binance API
- FAQ: Signature for this request is not valid. - Binance Developer Community - Community discussion about signature errors and solutions
Conclusion
The Binance API signature error (-1022) when making fiat withdrawals with nested parameters in TypeScript is a common issue that stems from improper parameter formatting. The key to fixing this error is understanding that Binance doesn’t accept JSON-encoded bodies for signed requests - all parameters must be sent as URL-encoded form data with nested objects properly flattened using dot or bracket notation.
By implementing proper parameter flattening functions, sorting parameters alphabetically, and generating the HMAC-SHA256 signature correctly, you can successfully make fiat withdrawal requests to the sapi/v2/fiat/withdraw endpoint. Remember to include the timestamp parameter and ensure all values are properly URL-encoded before calculating the signature.
Following the TypeScript implementation examples and best practices outlined in this guide will help you avoid signature errors and ensure smooth integration with Binance’s fiat withdrawal API. Always refer to the official Binance documentation for the most current requirements and specifications.