Quickstart
1. Get Your Credentials
Contact the Movement team to receive:
- Bearer Token - For authentication
- Signing Secret - For request signatures
- API Endpoint - Your API URL (https://YOUR_API_DOMAIN)
Important: Testnet and mainnet use different bearer tokens and signing secrets. Request separate credentials for each environment.
2. Make Your First Request
All requests require a bearer token. Airdrop requests also require a request signature. Here’s a complete example:
# Note: You'll need to generate the X-Signature header (see step 4)
# The network (mainnet/testnet) is determined by your bearer token
curl -X POST https://YOUR_API_DOMAIN/api/airdrop \
-H "Authorization: Bearer YOUR_BEARER_TOKEN" \
-H "X-Signature: v1,t=1700000000,s=abc123..." \
-H "Content-Type: application/json" \
-d '{
"address": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
"amount": "10",
"uniqueHash": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
}'Expected Response
{
"success": true,
"transactionHash": "0xabc123def456...",
"recipientAddress": "0x1234567890abcdef...",
"amount": "10",
"timestamp": "2025-11-18T12:00:00Z",
"uniqueHash": "a1b2c3d4..."
}3. Generate Unique Hashes
Each transaction needs a unique SHA256 hash (64 hex characters). The hash should be generated from your internal identifiers to ensure uniqueness.
Important: The example below is just one approach. You should use your own internal identifiers (user ID, transaction ID, order ID, campaign ID, etc.) combined with the recipient address and amount to create a hash that’s unique to your system.
import crypto from 'crypto';
// Example: Using internal transaction ID
function generateUniqueHash(
internalTxId: string, // Your internal transaction/order ID
userId: string, // Your internal user ID
address: string,
amount: string
): string {
// Combine your internal identifiers with transaction details
const data = `${internalTxId}:${userId}:${address}:${amount}`;
return crypto.createHash('sha256').update(data).digest('hex');
}
// Usage
const hash = generateUniqueHash(
'order-12345', // Your order ID
'user-abc-789', // Your user ID
'0x1234...', // Recipient address
'10' // Amount
);
console.log(hash); // 64 character hex stringNever reuse a uniqueHash! Each airdrop must have a unique hash, or it will be rejected by the smart contract as a duplicate.
4. Generate Request Signatures (Required)
All requests must include an HMAC-SHA256 signature:
import crypto from 'crypto';
function generateSignature(
signingSecret: string,
method: string,
path: string,
body: object
): string {
const timestamp = Math.floor(Date.now() / 1000);
const bodyString = JSON.stringify(body);
const payload = `v1.${timestamp}.${method}.${path}.${bodyString}`;
const signature = crypto
.createHmac('sha256', signingSecret)
.update(payload)
.digest('hex');
return `v1,t=${timestamp},s=${signature}`;
}
const headers = {
'Authorization': `Bearer ${bearerToken}`,
'X-Signature': generateSignature(signingSecret, 'POST', '/api/airdrop', requestBody),
'Content-Type': 'application/json'
};See Authentication for details.
5. Verify Transaction
Once you receive a transaction hash, query the Movement Network RPC to get transaction details:
RPC Endpoint
Testnet: GET https://testnet.movementnetwork.xyz/v1/transactions/by_hash/{txHash}
Mainnet: GET https://mainnet.movementnetwork.xyz/v1/transactions/by_hash/{txHash}
Code Example
async function verifyTransaction(txHash: string, network: 'mainnet' | 'testnet'): Promise<any> {
const rpcUrl = network === 'testnet'
? 'https://testnet.movementnetwork.xyz/v1'
: 'https://mainnet.movementnetwork.xyz/v1';
const response = await fetch(`${rpcUrl}/transactions/by_hash/${txHash}`);
if (!response.ok) {
throw new Error(`Transaction not found: ${response.statusText}`);
}
const transaction = await response.json();
return transaction;
}
// Usage - verify mainnet transaction
const txHash = '0xabc123...'; // From airdrop response
const txDetails = await verifyTransaction(txHash, 'mainnet');
console.log('Transaction Status:', txDetails.success);
console.log('Block Height:', txDetails.version);
console.log('Timestamp:', txDetails.timestamp);Response Example
{
"version": "12345678",
"hash": "0xabc123...",
"state_change_hash": "0x...",
"event_root_hash": "0x...",
"gas_used": "4",
"success": true,
"vm_status": "Executed successfully",
"accumulator_root_hash": "0x...",
"changes": [...],
"sender": "0x...",
"sequence_number": "0",
"max_gas_amount": "200000",
"gas_unit_price": "100",
"timestamp": "1700000000000000"
}Transaction Confirmation: A transaction is considered final when success: true and it’s included in a block (has a version number).
Visual Explorer: You can also view transactions in the Movement Explorer:
- Testnet:
https://explorer.movementnetwork.xyz/txn/{txHash}?network=bardock+testnet - Mainnet:
https://explorer.movementnetwork.xyz/txn/{txHash}?network=mainnet
Common Errors
401 Unauthorized
Cause: Invalid or missing bearer token
Solution: Check your Authorization: Bearer YOUR_BEARER_TOKEN header
400 Invalid Address
Cause: Address format is incorrect
Solution: Must be 0x followed by exactly 64 hex characters (66 total).
400 Duplicate Hash
Cause: This hash was already used
Solution: Generate a new unique hash
401 Invalid Signature
Cause: Missing or invalid request signature
Solution: Ensure X-Signature header is correctly generated
429 Rate Limit Exceeded
Cause: Too many requests from your IP address
Solution: Wait 60 seconds before retrying. Rate limit is 600 requests per minute (1 per second) per IP
Next Steps
- Authentication - Learn about bearer tokens and signatures
- API Reference - Complete endpoint documentation