Process Airdrop
Send MOVE tokens to a recipient address.
Endpoint
POST /api/airdropAuthentication
Required headers:
Authorization: Bearer YOUR_BEARER_TOKENX-Signature: v1,t=timestamp,s=signature
Request Body
{
"address": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
"amount": "100",
"uniqueHash": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
}Parameters
| Field | Type | Required | Description |
|---|---|---|---|
address | string | Yes | Recipient wallet address (0x + exactly 64 hex characters) |
amount | string/number | Yes | Amount in whole MOVE units (not octas) |
uniqueHash | string | Yes | SHA256 hash (64 hex characters) to prevent duplicates |
Each uniqueHash can only be used once. Generate a new unique hash for each transaction.
Response
Success (200 OK)
{
"success": true,
"transactionHash": "0xabc123def456...",
"recipientAddress": "0x1234567890abcdef...",
"amount": "100",
"timestamp": "2025-11-18T12:00:00Z",
"uniqueHash": "a1b2c3d4..."
}Response Fields
| Field | Type | Description |
|---|---|---|
success | boolean | Always true for successful requests |
transactionHash | string | Blockchain transaction hash for verification |
recipientAddress | string | Echo of the recipient address |
amount | string | Echo of the amount sent |
timestamp | string | ISO 8601 timestamp |
uniqueHash | string | Echo of the unique hash |
Transaction Confirmed: When you receive a 200 OK response, the transaction has been confirmed on-chain. No need for additional verification - the transaction is finalized and irreversible.
The response time includes blockchain confirmation (~1-1.5 seconds), so you can trust that the funds have been transferred.
Error Responses
400 Bad Request
Invalid input parameters:
{
"success": false,
"error": {
"code": "INVALID_ADDRESS",
"message": "Invalid wallet address format. Must be 0x followed by exactly 64 hex characters."
}
}Common validation errors:
INVALID_ADDRESS- Must be0x+ exactly 64 hex charactersINVALID_AMOUNT- Amount must be > 0DUPLICATE_HASH- This uniqueHash was already processedINVALID_HASH- Must be 64-character SHA256 hex string
401 Unauthorized
Authentication failed:
{
"success": false,
"error": {
"code": "INVALID_TOKEN",
"message": "Invalid authentication token"
}
}Common authentication errors:
MISSING_AUTH_HEADER- Authorization header not providedINVALID_TOKEN- Bearer token is invalidUNAUTHORIZED- Invalid or missing signature
429 Too Many Requests
Rate limit exceeded:
{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Please try again later."
}
}Response Headers:
X-RateLimit-Limit- Maximum requests allowed (600/min)X-RateLimit-Remaining- Requests remaining in current windowX-RateLimit-Reset- Unix timestamp when the limit resets
The API uses a fixed window rate limit of 600 requests per minute per IP address. If you exceed this limit, you’ll receive a 429 response and must wait until the window resets.
503 Service Unavailable
API is temporarily paused for maintenance:
{
"success": false,
"error": {
"code": "AIRDROP_PAUSED",
"message": "Airdrop API is currently paused. Please try again later."
}
}When you receive a 503 response, the API has been intentionally paused by administrators. This is typically for maintenance or emergency situations. Implement retry logic with exponential backoff and check back periodically.
500 Internal Server Error
Service or blockchain error:
{
"success": false,
"error": {
"code": "INSUFFICIENT_BALANCE",
"message": "Insufficient treasury balance to process this airdrop"
}
}Common server errors:
INSUFFICIENT_BALANCE- Treasury wallet has insufficient fundsTRANSACTION_FAILED- Blockchain transaction failedCONTRACT_ERROR- Smart contract execution error
Code Example
import crypto from 'crypto';
async function processAirdrop(
apiKey: string,
signingSecret: string,
internalTxId: string, // Your internal transaction ID
userId: string, // Your internal user ID
address: string,
amount: string
): Promise<string> {
// Generate unique hash using YOUR internal identifiers
// IMPORTANT: Customize this based on your system's IDs
const uniqueHash = crypto
.createHash('sha256')
.update(`txn:${internalTxId}:user:${userId}:${address}:${amount}`)
.digest('hex');
const requestBody = { address, amount, uniqueHash };
// Generate signature
const timestamp = Math.floor(Date.now() / 1000);
const bodyString = JSON.stringify(requestBody);
const payload = `v1.${timestamp}.POST./api/airdrop.${bodyString}`;
const signature = crypto.createHmac('sha256', signingSecret).update(payload).digest('hex');
const response = await fetch('https://YOUR_API_DOMAIN/api/airdrop', {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'X-Signature': `v1,t=${timestamp},s=${signature}`,
'Content-Type': 'application/json'
},
body: bodyString
});
const data = await response.json();
if (!data.success) {
throw new Error(data.error.message);
}
return data.transactionHash;
}
// Usage
const txHash = await processAirdrop(
process.env.API_KEY!,
process.env.SIGNING_SECRET!,
'order-12345', // Your internal transaction/order ID
'user-abc-789', // Your internal user ID
'0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef',
'100'
);
console.log('Success! Transaction:', txHash);Best Practices
Unique Hash Generation: Use your internal identifiers (transaction ID, user ID, campaign ID, etc.) combined with the recipient address and amount. This ensures uniqueness in your system and prevents accidental duplicates. The smart contract will reject duplicate hashes automatically.
- Handle errors gracefully - Check
successfield and handleerrorobject - Use proper signatures - All requests require HMAC-SHA256 signatures in the
X-Signatureheader - Verify transactions - Use the transaction hash to verify on the blockchain explorer
- Test on testnet first - Use your testnet bearer token when testing your integration
Transaction Verification
Verify your transaction using the Movement Network RPC:
// After successful airdrop
const result = await processAirdrop(address, amount, uniqueHash);
const txHash = result.transactionHash;
// Verify via RPC
const rpcUrl = 'https://mainnet.movementnetwork.xyz/v1'; // or testnet
const response = await fetch(`${rpcUrl}/transactions/by_hash/${txHash}`);
const tx = await response.json();
console.log('Success:', tx.success);
console.log('Block:', tx.version);
console.log('Timestamp:', tx.timestamp);See Transaction Verification for complete details.
Related
- GET /api/health - Check API health
- Transaction Verification - Verify transactions