Skip to main content

Overview

Payroll APIs enable you to distribute cryptocurrency payments to multiple recipients efficiently. This feature is designed for bulk salary payments, contractor disbursements, and recurring employee compensation.

When to Use Payroll vs Payout

FeaturePayrollPayout
Best ForBulk salary payments, employee disbursementsPersonal withdrawals, large transfers
Batch Processing✅ Multiple recipients in one operation❌ Single recipient per payout
Address Verification⚠️ Optional (higher risk for new addresses)✅ Required (micro-payment confirmation)
Typical Use CasePaying multiple employeesWithdrawing your own funds
Recommended AmountUnder $10,000 USD per recipientAny amount, especially large transfers
Processing MethodsCSV Upload or Direct APIAlways via API

Key Decision Point:

  • Use Payroll when paying multiple employees/contractors simultaneously (especially under $10,000 USD each)
  • Use Payout when withdrawing to your own wallets or for any single transfer exceeding $10,000 USD

⚠️ Critical: Crypto Transactions are Irreversible Once a transaction is confirmed on the blockchain, it cannot be reversed or canceled. For individual payments over $10,000 USD, use Payout APIs with pre-verified addresses to prevent costly address errors.

Why Payout for Large Amounts?

The Payout system requires mandatory address verification:

StepPayoutPayroll
Address Verification✅ Mandatory micro-payment confirmation⚠️ Optional (employee input)
Error Prevention🔒 Pre-verified before any transfer⚠️ Relies on accurate address entry
Best For> $10,000 USD transfers< $10,000 USD per recipient
SetupOne-time verification, reusablePer-batch address input

Verification Process (Payout only):

  1. Register wallet address via Wallet Management APIs
  2. Receive micro-payment (e.g., 0.003621 USDC)
  3. Confirm exact amount received
  4. Address permanently verified for unlimited withdrawals

For detailed information, see How to Manage Wallet and Payout APIs.


How Payroll Works

Processing Methods

MartianPay offers two methods for processing payrolls:

Method 1: Traditional Flow (CSV Upload)

Best For: Dashboard/web operations, manual batch salary processing

Process:

  1. Create Payroll (upload CSV)
  2. Confirm Payroll
  3. Merchant Approval (always required)
  4. Admin Approval (if total > $2,000)
  5. Automatic execution

Approval Requirements:

Total AmountMerchant ApprovalAdmin Approval
≤ $2,000✅ Required❌ Not Required
> $2,000✅ Required✅ Required

Best For: API integrations, automated systems, programmatic payroll

Process: Single API call combines create, confirm, and optionally auto-approve

Approval Requirements:

Single Item AmountMerchant ApprovalAdmin ApprovalExecution
≤ $2,000❌ Not Required❌ Not Required✅ Immediate
> $2,000❌ Not Required✅ RequiredAfter admin approval

Key Advantages:

  • ✅ No merchant approval needed (unlike CSV)
  • ✅ Single API call execution
  • ✅ Automatic approval for amounts ≤ $2,000
  • ✅ Ideal for automated payment systems

Important Notes:

  • CSV Upload: All payrolls created via web CSV upload require merchant approval
  • CSV Upload (total > $2,000): Also requires admin approval after merchant approval
  • Payroll Direct API: No merchant approval required, admin approval only for single items > $2,000
  • CSV threshold is based on total amount, Direct API threshold is based on single item amount
  • Approval amounts are calculated using USD equivalent at creation time
  • During approval, payroll status is pending with approval_status: "in_progress"

💡 Tip: For API integrations, use Payroll Direct API to skip merchant approval and streamline payment processing.

Understanding Payroll Status

Payrolls track progress through two status fields:

1. Payroll Status (status)

Main processing state of the payroll batch:

StatusMeaning
draftInitial state after creation, awaiting confirmation
pendingConfirmed and awaiting approval through the approval workflow
approvedApproved and ready for execution
startedProcessing has begun (transitional state)
swappingCurrently performing currency swaps between assets
executingProcessing normal (Fireblocks) payments
binance_processingProcessing Binance payments
paidAll payments completed successfully
partial_paidSome payments succeeded, some failed
failedAll payments failed
rejectedRejected through the approval workflow, no further processing
canceledPayroll was canceled

2. Approval Status (approval_status)

Approval workflow state:

StatusMeaning
"" (empty)No approval needed yet
in_progressAwaiting approval decision
approvedApproval granted
rejectedApproval denied

3. Payroll Item Status

Each individual payment has its own status:

StatusMeaning
draftInitial state
pendingAwaiting processing
address_verifyingChecking recipient address
address_verifiedAddress confirmed
executingPayment in progress
sentTransaction on blockchain
paidCompleted successfully
failedPayment failed

Typical Status Flows

CSV Upload (always requires merchant approval):

draft → pending (merchant approval) → [pending (admin approval if > $2K)]
→ approved → executing → paid/partial_paid/failed

Direct API (≤ $2,000 per item):

approved (instant) → executing → paid/partial_paid/failed

Direct API (> $2,000 per item):

pending (admin approval only) → approved → executing → paid/partial_paid/failed

API Reference

2. Traditional Flow (CSV Upload)

2.1 Create Payroll

Create a new payroll record for an employee.

For detailed API reference, see: Create Payroll API

First, create a CSV file with the following format:

name,email,phone,amount,coin,network,address,payment_method
John Doe,employee1@example.com,13488888888,30,USDC,Solana Devnet,CNJQ5q3kczhLWYQnh3YkKSwnS1fGJ9ydxvGN3KZuqy3G,normal
Jane Smith,employee2@example.com,13488888888,5,USDC,Ethereum Sepolia,0x36279Ac046498bF0cb742622cCe22F3cE3c2AfD9,binance

Request:

# Basic CSV upload
curl --location --request POST 'https://api.martianpay.com/v1/payrolls' \
--header 'Authorization: Basic {BASE64_ENCODE(api_key + ":")}' \
--form 'file=@/path/to/your/payroll.csv'

# With external_id for idempotency
curl --location --request POST 'https://api.martianpay.com/v1/payrolls' \
--header 'Authorization: Basic {BASE64_ENCODE(api_key + ":")}' \
--form 'file=@/path/to/your/payroll.csv' \
--form 'external_id=ORDER-2024-001'

Form Parameters:

  • file: (Required) CSV file containing payroll data
  • external_id: (Optional) External ID for idempotency. Prevents duplicate payroll creation

Response:

{
"error_code": "success",
"msg": "success",
"data": {
"payroll": {
"id": "payroll_I6mzarIW0qZ4itwGg7xCa9EA",
"created_at": 1750147470,
"updated_at": 1750147470,
"canceled_at": 0,
"merchant_id": "accu_M7PTgveSgMtTtPHbjFgEtAlD",
"external_id": "ORDER-2024-001",
"approval_status": "",
"status": "draft",
"total_item_num": 2,
"total_amount": "35",
"total_service_fee": "4",
"currency": "USD"
},
"items": [
{
"id": "payroll_item_QZmpUMN5R1Gxohg7ADKbsnTW",
"created_at": 1750147470,
"updated_at": 1750147470,
"payroll_id": "payroll_I6mzarIW0qZ4itwGg7xCa9EA",
"payroll": {
"id": "payroll_I6mzarIW0qZ4itwGg7xCa9EA",
"created_at": 1750147470,
"updated_at": 1750147470,
"canceled_at": 0,
"merchant_id": "accu_M7PTgveSgMtTtPHbjFgEtAlD",
"approval_status": "",
"status": "draft",
"total_item_num": 2,
"total_amount": "35",
"total_service_fee": "4",
"currency": "USD"
},
"name": "John Doe",
"email": "employee1@example.com",
"phone": "13488888888",
"amount": "30",
"service_fee": "2",
"exchange_rate_to_usd": "1",
"coin": "USDC",
"network": "Solana Devnet",
"asset_id": "USDC-Solana-TEST",
"address": "CNJQ5q3kczhLWYQnh3YkKSwnS1fGJ9ydxvGN3KZuqy3G",
"address_verified": false,
"status": "draft",
"transactions": null,
"validation": {
"name_valid": true,
"email_valid": true,
"phone_valid": true,
"amount_valid": true,
"coin_valid": true,
"network_valid": true,
"address_valid": true,
"payment_method_valid": true,
"balance_enough": true
},
"differences": {
"name": {
"previous": "",
"current": "John Doe",
"status": "added"
},
"email": {
"previous": "",
"current": "employee1@example.com",
"status": "added"
},
"phone": {
"previous": "",
"current": "13488888888",
"status": "added"
},
"amount": {
"previous": "",
"current": "30",
"status": "added"
},
"coin": {
"previous": "",
"current": "USDC",
"status": "added"
},
"network": {
"previous": "",
"current": "Solana Devnet",
"status": "added"
},
"address": {
"previous": "",
"current": "CNJQ5q3kczhLWYQnh3YkKSwnS1fGJ9ydxvGN3KZuqy3G",
"status": "added"
}
},
"has_monthly_payment": false
},
{
"id": "payroll_item_nYuCYjVs1OvbOfldKD8A47tV",
"created_at": 1750147470,
"updated_at": 1750147470,
"payroll_id": "payroll_I6mzarIW0qZ4itwGg7xCa9EA",
"payroll": {
"id": "payroll_I6mzarIW0qZ4itwGg7xCa9EA",
"created_at": 1750147470,
"updated_at": 1750147470,
"canceled_at": 0,
"merchant_id": "accu_M7PTgveSgMtTtPHbjFgEtAlD",
"approval_status": "",
"status": "draft",
"total_item_num": 2,
"total_amount": "35",
"total_service_fee": "4",
"currency": "USD"
},
"name": "Jane Smith",
"email": "employee1@example.com",
"phone": "13488888888",
"amount": "5",
"service_fee": "2",
"exchange_rate_to_usd": "1",
"coin": "USDC",
"network": "Ethereum Sepolia",
"asset_id": "USDC-Ethereum-TEST",
"address": "0x36279Ac046498bF0cb742622cCe22F3cE3c2AfD9",
"address_verified": true,
"status": "draft",
"transactions": null,
"validation": {
"name_valid": true,
"email_valid": true,
"phone_valid": true,
"amount_valid": true,
"coin_valid": true,
"network_valid": true,
"address_valid": true,
"payment_method_valid": true,
"balance_enough": true
},
"differences": {
"name": {
"previous": "Jane Smith",
"current": "Jane Smith",
"status": "unchanged"
},
"email": {
"previous": "employee2@example.com",
"current": "employee1@example.com",
"status": "unchanged"
},
"phone": {
"previous": "134333333333",
"current": "13488888888",
"status": "modified"
},
"amount": {
"previous": "5",
"current": "5",
"status": "unchanged"
},
"coin": {
"previous": "USDC",
"current": "USDC",
"status": "unchanged"
},
"network": {
"previous": "Ethereum Sepolia",
"current": "Ethereum Sepolia",
"status": "unchanged"
},
"address": {
"previous": "0x36279Ac046498bF0cb742622cCe22F3cE3c2AfD9",
"current": "0x36279Ac046498bF0cb742622cCe22F3cE3c2AfD9",
"status": "unchanged"
}
},
"has_monthly_payment": true
}
],
"swap_items": [
{
"id": "payroll_swap_item_n4rBJt7yuh6fVYCunWxQiJrd",
"lifi_quote_id": "f7800f87-ad2f-4411-b4e5-9a38eb03410e:0",
"created_at": 1750147470,
"updated_at": 1750147470,
"sent_at": null,
"merchant_id": "",
"payroll_id": "payroll_I6mzarIW0qZ4itwGg7xCa9EA",
"payroll": {
"id": "payroll_I6mzarIW0qZ4itwGg7xCa9EA",
"created_at": 1750147470,
"updated_at": 1750147470,
"canceled_at": 0,
"merchant_id": "accu_M7PTgveSgMtTtPHbjFgEtAlD",
"approval_status": "",
"status": "draft",
"total_item_num": 2,
"total_amount": "35",
"total_service_fee": "4",
"currency": "USD"
},
"from_asset_id": "USDC-Ethereum-TEST",
"expected_from_amount": "0",
"estimated_from_amount": "32.776548",
"estimated_from_amount_usd": "32.7715",
"actual_from_amount": "0",
"network_fee": "0.03",
"to_asset_id": "USDC-Solana-TEST",
"expected_to_amount": "32",
"estimated_to_amount": "32.173331",
"estimated_to_amount_min": "32.012464",
"estimated_to_amount_usd": "32.1638",
"actual_to_amount": "0",
"status": "draft"
}
]
}
}

Understanding the Response

How to Check if the Request Was Successful:

FieldValueMeaning
error_code"success"✅ Payroll created
error_codeOther value❌ Error occurred (e.g., "duplicate_external_id", "invalid_csv_format")

Key Status Fields:

FieldValueMeaning
status"draft"📝 Payroll created, awaiting confirmation
status"pending"⏳ Confirmed, awaiting approval
status"approved"✅ Approved, ready for execution
status"executing"🔄 Processing payments
status"paid"Success - All payments completed
status"partial_paid"⚠️ Some payments succeeded, some failed
status"failed"Failed - All payments failed
status"canceled"❌ Manually canceled
approval_status"" (empty)No approval needed yet
approval_status"in_progress"⏳ Awaiting merchant/admin approval
approval_status"approved"✅ All required approvals granted
approval_status"rejected"❌ Approval denied

Payroll Item Status:

Each item in the items array has its own status field:

StatusMeaningAction Required
draftItem createdConfirm payroll to proceed
pendingAwaiting processingWait for execution
address_verifyingChecking recipient addressAutomatic process
address_verifiedAddress confirmedReady for payment
executingPayment in progressMonitor for completion
paid✅ Payment succeededNo action needed
failed❌ Payment failedCheck failure reason

Validation Fields:

The validation object contains fields to verify the validity of payroll item data:

FieldDescription
name_validIndicates if the recipient's name is valid
email_validIndicates if the email address format is valid
phone_validIndicates if the phone number format is valid
amount_validIndicates if the payment amount is valid
coin_validIndicates if the cryptocurrency is supported
network_validIndicates if the blockchain network is supported
address_validIndicates if the wallet address format is valid
payment_method_validIndicates if the payment method is valid (must be "normal" or "binance")
balance_enoughIndicates if your account has sufficient balance

Important: Any field with a false value requires immediate attention. These indicate validation failures that must be corrected before the payroll can be processed successfully.

Using External ID:

  • If you provided an external_id during creation, you can use it to query the payroll:
    • GET /payrolls?external_id=ORDER-2024-001 - Find the specific payroll
    • GET /payrolls/items/list?external_id=ORDER-2024-001 - List items for that payroll
  • The external_id ensures idempotency - attempting to create another payroll with the same external_id will return an error

2.2 Confirm Payroll

Confirm the payroll to initiate the payment process.

For detailed API reference, see: Confirm Payroll API

Before confirming a payroll, all validation checks must pass. If any of the following validation fields returns false, the confirmation will fail:

  • name_valid
  • email_valid
  • phone_valid
  • amount_valid
  • coin_valid
  • network_valid
  • address_valid
  • payment_method_valid
  • balance_enough

Ensure all validation issues are resolved before attempting to confirm the payroll. The system will not process payrolls with invalid data.

Request:

curl --location --request POST 'https://api.martianpay.com/v1/payrolls/payroll_I6mzarIW0qZ4itwGg7xCa9EA/confirm' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic {BASE64_ENCODE(api_key + ":")}'

Response:

{
"error_code": "success",
"msg": "success",
"data": {
"payroll": {
"id": "payroll_I6mzarIW0qZ4itwGg7xCa9EA",
"created_at": 1750147470,
"updated_at": 1750147834,
"canceled_at": 0,
"merchant_id": "accu_M7PTgveSgMtTtPHbjFgEtAlD",
"approval_status": "in_progress",
"status": "pending",
"total_item_num": 2,
"total_amount": "35",
"total_service_fee": "4",
"currency": "USD"
},
"items": [
// ... payroll items
],
"swap_items": [
// ... swap items if any
]
}
}

Understanding the Response

How to Check if the Request Was Successful:

FieldValueMeaning
error_code"success"✅ Confirmation accepted
error_codeOther value❌ Error occurred (e.g., "validation_failed", "already_confirmed")

Status After Confirmation:

FieldValueMeaning
status"pending"✅ Confirmed, now awaiting approval
approval_status"in_progress"⏳ Merchant approval required

Next Steps:

After confirming, the payroll enters pending status with approval_status: "in_progress". You'll need to:

  1. Approve via Dashboard: Log in to MartianPay dashboard to review and approve
  2. Approve via API: Use Approve Payroll API (see Section 4.2)
  3. Monitor Status: Poll the payroll status or subscribe to webhook events

CSV Upload Workflow:

draft → (confirm) → pending + in_progress → (approve) → approved → executing → paid

💡 Important for API Integration: Direct API is the RECOMMENDED method for API integrations. This endpoint can directly execute payroll payments in a single API call, combining create, confirm, and approve steps into one streamlined process.

Use Direct API for: API integrations, automated systems, programmatic payroll processing Use CSV Upload/Approve Workflow for: Dashboard/web manual operations, batch employee salary payments requiring human review

Create and optionally auto-approve a payroll in a single API call. This endpoint combines the create, confirm, and approve steps into one streamlined process.

For detailed API reference, see: Create Payroll Direct API

Key Features:

  • Idempotency: Use external_id to prevent duplicate payroll creation
  • Auto-approval: Optional automatic approval and execution
  • Smart defaults: Automatically fills missing employee information

Request:

curl --location --request POST 'https://api.martianpay.com/v1/payrolls/direct' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic {BASE64_ENCODE(api_key + ":")}' \
--data-raw '{
"external_id": "ORDER-2024-001",
"auto_approve": true,
"items": [
{
"coin": "USDT",
"network": "Tron",
"address": "TN9RRaXkCFtTXRso2GdTZxSxxwufzxLQPP",
"amount": "100",
"payment_method": "normal"
},
{
"name": "John Doe",
"email": "john@example.com",
"phone": "+1234567890",
"coin": "USDT",
"network": "Tron",
"address": "TWd4WrZ9wn84f5x1hZhL4DHvk738ns5jwb",
"amount": "200",
"payment_method": "binance"
}
]
}'

Request Parameters:

FieldTypeRequiredDescription
external_idstringNoExternal ID for idempotency. Prevents duplicate payroll creation
auto_approvebooleanNoIf true, automatically approves and executes the payroll. Default is false
itemsarrayYesArray of payroll items to process
items[].namestringNoEmployee name. If empty, generates "Recipient-" followed by last 6 characters of address
items[].emailstringNoEmployee email. Defaults to "-" if not provided
items[].phonestringNoEmployee phone. Defaults to "-" if not provided
items[].coinstringYesCryptocurrency type (e.g., USDT, USDC)
items[].networkstringYesBlockchain network (e.g., Tron, Ethereum, Solana)
items[].addressstringYesWallet address to send funds to
items[].amountstringYesAmount to send
items[].payment_methodstringNoPayment method: "normal" or "binance". Defaults to "normal"

Payment Method Explanation:

The payment_method field is used to specify the payment method for each employee's payroll. Common values include:

  • normal: Indicates a standard on-chain transfer, where the salary is sent directly to the employee's provided wallet address.
  • binance: Indicates payment via the Binance platform, suitable when the employee's wallet address is associated with Binance.

Choose the appropriate payment_method according to your needs to ensure employees receive their salaries smoothly.

Key Features:

  • Single API Call: Combines create, confirm, and optionally approve in one request
  • Smart Defaults: Automatically generates employee names from wallet addresses when not provided
  • Optional Fields: Name, email, and phone are optional, making it ideal for automated payroll processing
  • Auto-Approval: Set auto_approve: true to bypass the approval workflow and execute immediately
  • Bulk Processing: Send payments to multiple recipients in a single request
  • Mixed Payment Methods: Support both "normal" (Fireblocks) and "binance" payment methods in the same payroll
  • Idempotency Support: Use external_id to prevent duplicate payroll creation

Using External ID for Idempotency:

  • The external_id field ensures that duplicate requests with the same ID won't create multiple payrolls
  • Once a payroll is created with an external_id, subsequent requests with the same ID will return an error
  • You can query payrolls and payroll items using the external_id:
    • GET /payrolls?external_id=ORDER-2024-001 - Find specific payroll
    • GET /payrolls/items/list?external_id=ORDER-2024-001 - List items for that payroll

Response:

{
"error_code": "success",
"msg": "success",
"data": {
"payroll": {
"id": "payroll_xxxxx",
"created_at": 1750147470,
"updated_at": 1750147470,
"merchant_id": "accu_xxxxx",
"external_id": "ORDER-2024-001",
"status": "approved", // or "pending" if auto_approve is false
"approval_status": "approved", // or "in_progress" if auto_approve is false
"total_item_num": 2,
"total_amount": "300",
"total_service_fee": "4",
"currency": "USD"
},
"items": [
{
"id": "payroll_item_xxxxx",
"name": "Recipient-LQQPP", // Auto-generated from address if name not provided
"email": "-",
"phone": "-",
"amount": "100",
"coin": "USDT",
"network": "Tron",
"address": "TN9RRaXkCFtTXRso2GdTZxSxxwufzxLQPP",
"payment_method": "normal",
"status": "approved",
"validation": {
"name_valid": true,
"email_valid": true,
"phone_valid": true,
"amount_valid": true,
"coin_valid": true,
"network_valid": true,
"address_valid": true,
"balance_enough": true
}
},
{
"id": "payroll_item_yyyyy",
"name": "John Doe",
"email": "john@example.com",
"phone": "+1234567890",
"amount": "200",
"coin": "USDT",
"network": "Tron",
"address": "TWd4WrZ9wn84f5x1hZhL4DHvk738ns5jwb",
"payment_method": "binance",
"status": "approved"
// ... validation and other fields
}
],
"swap_items": [],
"binance_from_items": []
}
}

Understanding the Response

How to Check if the Request Was Successful:

FieldValueMeaning
error_code"success"✅ Payroll created and processed
error_codeOther value❌ Error occurred (e.g., "duplicate_external_id", "insufficient_balance")

Key Status Fields (Depends on auto_approve):

When auto_approve: true (Recommended for API):

FieldValueMeaning
status"approved"Auto-approved, executing immediately
approval_status"approved"✅ No manual approval needed

When auto_approve: false (Default):

FieldValueMeaning
status"pending"⏳ Awaiting approval
approval_status"in_progress"⏳ Admin approval required (if total > $2,000)

Approval Behavior:

Single Item Amountauto_approve: trueauto_approve: falseNext Steps
≤ $2,000✅ Executes immediately⚠️ No approvals needed, executes automaticallyMonitor for completion
> $2,000⚠️ Waits for admin approval⚠️ Waits for admin approvalApprove via dashboard or API

Monitoring Payroll Progress:

After creating a Direct API payroll, monitor through:

  1. Polling: Use Get Payroll API to check status and approval_status

  2. Webhooks: Subscribe to payroll and payroll item events (recommended):

    Payroll Batch Events:

    • payroll.created - Payroll batch created
    • payroll.approved - Payroll batch approved
    • payroll.rejected - Payroll batch rejected
    • payroll.canceled - Payroll batch canceled
    • payroll.executing - Payroll batch executing
    • payroll.completed - All payments completed successfully
    • payroll.failed - All payments failed

    Payroll Item Events (recommended for detailed tracking):

    • payroll_item.processing - Individual payment processing
    • payroll_item.succeeded - Individual payment succeeded
    • payroll_item.failed - Individual payment failed
    • payroll_item.address_verification_sent - Verification sent
    • payroll_item.address_verified - Address verified

    💡 Recommendation: Monitor payroll_item.* events for granular per-employee payment tracking. See Section 7: Webhook Events for detailed event documentation.

Next Steps Based on Status:

  • approved: ✅ System processing automatically, monitor for paid status
  • pending + approval_status: "in_progress": Approve via Approve Payroll API
  • executing: 🔄 Payments in progress, wait for completion
  • paid: ✅ Complete! All payments succeeded
  • partial_paid: ⚠️ Check individual item statuses for failures
  • failed: ❌ Check failure reasons, resolve and retry

Use Cases:

  • Automated Payroll Systems: Ideal for systems that need to process payroll without manual intervention
  • Bulk USDT Payments: Efficiently handle multiple USDT transfers on Tron network
  • Mixed Payment Processing: Use different payment processors (Fireblocks and Binance) for different recipients
  • Quick Disbursements: Skip the approval process for urgent payments when auto_approve is enabled

Direct API Workflow:

With auto_approve: true (≤ $2,000 per item):

approved (instant) → executing → paid/partial_paid/failed

With auto_approve: false or > $2,000 per item:

pending + in_progress → (admin approval) → approved → executing → paid/partial_paid/failed

4. Approval Workflow

Both Traditional Flow and Direct API (when auto_approve is false) use the same approval workflow.

4.1 Get Payroll Approval Instance

Get the approval instance for a specific payroll.

For detailed API reference, see: Get Approval Instance API

Request:

curl --location --request GET 'https://api.martianpay.com/v1/approval/detail?resource_id=payroll_I6mzarIW0qZ4itwGg7xCa9EA' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic {BASE64_ENCODE(api_key + ":")}'

Response:

{
"error_code": "success",
"msg": "success",
"data": {
"id": "approval_instance_tkACb5ZRUHkBM00JhQsPpuzz",
"object": "approval_instance",
"merchant_id": "accu_M7PTgveSgMtTtPHbjFgEtAlD",
"status": "pending",
"resource_id": "payroll_I6mzarIW0qZ4itwGg7xCa9EA",
"resource_type": "payroll",
"created_at": 1750147834,
"updated_at": 1750147834,
"records": [
{
"id": "approval_record_G7BWMc5FTnWUIg3sBC1poG6Y",
"action": "start",
"comment": "",
"approver_id": "server-HwTzmQGe2oP9pizy21NsuBEe",
"approver_name": "Jane Smith",
"approver_role": "",
"created_at": 1750147834,
"namespace": "merchant"
}
],
"current_step": {
"id": "approval_step_uKL6OR1NHi5uyfTNPK1i7n3q",
"flow_id": "",
"step_order": 1,
"namespace": "merchant",
"roles": [
"FinanceManager",
"SuperAdmin"
],
"next_on_approve": 2,
"next_on_reject": 0,
"created_at": 1749000373,
"updated_at": 1749000373
}
}
}

4.2 Approve Payroll

Approve a specific payroll request.

For detailed API reference, see: Approve Payroll API

Request:

curl --location --request POST 'https://api.martianpay.com/v1/approval/approval_instance_tkACb5ZRUHkBM00JhQsPpuzz/approve' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic {BASE64_ENCODE(api_key + ":")}' \
--data-raw '{
"comment": "agree"
}'

Response:

{
"error_code": "success",
"msg": "success"
}

4.3 Reject Payroll

Reject a specific payroll request.

For detailed API reference, see: Reject Payroll API

Request:

curl --location --request POST 'https://api.martianpay.com/v1/approval/approval_instance_tkACb5ZRUHkBM00JhQsPpuzz/reject' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic {BASE64_ENCODE(api_key + ":")}' \
--data-raw '{
"comment": "disagree"
}'

Response:

{
"error_code": "success",
"msg": "success"
}

5. Payroll Execution Process

Once a payroll is approved (either through traditional approval workflow or auto-approval in Direct API), the system automatically executes the payments. The execution process differs based on the payment method:

Address Verification Process

For normal payment method:

  • First-time addresses: A micro-transfer is sent for verification
  • Verification email: Employee receives an email with a verification link
  • 72-hour deadline: Employee must verify within 72 hours or the transaction fails
  • Future payments: Once verified, the address doesn't need re-verification

For binance payment method:

  • No address verification: Payments are processed directly through Binance
  • Immediate processing: No micro-transfer or verification email required
  • Suitable for: Binance-associated wallet addresses

Payment Confirmation

After successful execution (regardless of payment method):

  • Confirmation email: Employees receive payment details via email
  • Transaction details: Amount, cryptocurrency, network, and transaction hash
  • Blockchain tracking: Transaction can be verified on blockchain explorer

This dual-method approach ensures:

  • Security: Address verification for standard on-chain transfers
  • Efficiency: Streamlined processing for Binance payments
  • Flexibility: Choose the appropriate method based on recipient needs

6. Common Operations

6.1 List Payrolls

List all payrolls for a merchant.

For detailed API reference, see: List Payrolls API

Request:

curl --location --request GET 'https://api.martianpay.com/v1/payrolls?page=0&page_size=5' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic {BASE64_ENCODE(api_key + ":")}'

Query Parameters:

  • page (required): Page number, starting from 0
  • page_size (required): Items per page (1-50)
  • start_date (optional): Filter by start date (YYYY-MM-DD)
  • end_date (optional): Filter by end date (YYYY-MM-DD)
  • external_id (optional): Filter by external ID to find specific payroll
  • payroll_id (optional): Filter by payroll ID
  • status (optional): Filter by status (draft, pending, approved, paid, etc.)

Response:

{
"error_code": "success",
"msg": "success",
"data": {
"payrolls": [
{
"id": "payroll_I6mzarIW0qZ4itwGg7xCa9EA",
"created_at": 1750147470,
"updated_at": 1750147834,
"canceled_at": 0,
"merchant_id": "accu_M7PTgveSgMtTtPHbjFgEtAlD",
"approval_status": "in_progress",
"status": "pending",
"total_item_num": 2,
"total_amount": "35",
"total_service_fee": "4",
"currency": "USD"
},
{
"id": "payroll_dHQES72TDZZBamNx0gpMOeko",
"created_at": 1750143877,
"updated_at": 1750158632,
"canceled_at": 0,
"merchant_id": "accu_M7PTgveSgMtTtPHbjFgEtAlD",
"approval_status": "rejected",
"status": "rejected",
"total_item_num": 2,
"total_amount": "35",
"total_service_fee": "4",
"currency": "USD"
},
{
"id": "payroll_3CB4JUyTOSWZec5jPa4Y08ok",
"created_at": 1749955685,
"updated_at": 1749956301,
"canceled_at": 0,
"merchant_id": "accu_M7PTgveSgMtTtPHbjFgEtAlD",
"approval_status": "approved",
"status": "paid",
"total_item_num": 2,
"total_amount": "10",
"total_service_fee": "4",
"currency": "USD"
},
{
"id": "payroll_FDsfD98wyjVP3YwhCUApiXvu",
"created_at": 1749955619,
"updated_at": 1749955663,
"canceled_at": 0,
"merchant_id": "accu_M7PTgveSgMtTtPHbjFgEtAlD",
"approval_status": "approved",
"status": "failed",
"total_item_num": 2,
"total_amount": "35",
"total_service_fee": "4",
"currency": "USD"
},
{
"id": "payroll_7gVHYolRb2T36CAYCJC9nGsb",
"created_at": 1749954848,
"updated_at": 1749954900,
"canceled_at": 0,
"merchant_id": "accu_M7PTgveSgMtTtPHbjFgEtAlD",
"approval_status": "approved",
"status": "failed",
"total_item_num": 2,
"total_amount": "35",
"total_service_fee": "4",
"currency": "USD"
}
],
"total": 38
}
}

6.2 Get Payroll Detail

Get the details of a specific payroll request.

For detailed API reference, see: Get Payroll API

Request:

curl --location --request GET 'https://api.martianpay.com/v1/payrolls/payroll_I6mzarIW0qZ4itwGg7xCa9EA' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic {BASE64_ENCODE(api_key + ":")}'

Response:

{
"error_code": "success",
"msg": "success",
"data": {
"payroll": {
"id": "payroll_I6mzarIW0qZ4itwGg7xCa9EA",
"created_at": 1750147470,
"updated_at": 1750159306,
"canceled_at": 0,
"merchant_id": "accu_M7PTgveSgMtTtPHbjFgEtAlD",
"approval_status": "rejected",
"status": "rejected",
"total_item_num": 2,
"total_amount": "35",
"total_service_fee": "4",
"currency": "USD"
},
"items": [
{
"id": "payroll_item_QZmpUMN5R1Gxohg7ADKbsnTW",
"created_at": 1750147470,
"updated_at": 1750159306,
"payroll_id": "payroll_I6mzarIW0qZ4itwGg7xCa9EA",
"payroll": {
"id": "payroll_I6mzarIW0qZ4itwGg7xCa9EA",
"created_at": 1750147470,
"updated_at": 1750159306,
"canceled_at": 0,
"merchant_id": "accu_M7PTgveSgMtTtPHbjFgEtAlD",
"approval_status": "rejected",
"status": "rejected",
"total_item_num": 2,
"total_amount": "35",
"total_service_fee": "4",
"currency": "USD"
},
"name": "John Doe",
"email": "employee1@example.com",
"phone": "13488888888",
"amount": "30",
"service_fee": "2",
"exchange_rate_to_usd": "1",
"coin": "USDC",
"network": "Solana Devnet",
"asset_id": "USDC-Solana-TEST",
"address": "CNJQ5q3kczhLWYQnh3YkKSwnS1fGJ9ydxvGN3KZuqy3G",
"address_verified": false,
"status": "rejected",
"transactions": null,
"validation": {
"name_valid": true,
"email_valid": true,
"phone_valid": true,
"amount_valid": true,
"coin_valid": true,
"network_valid": true,
"address_valid": true,
"payment_method_valid": true,
"balance_enough": true
},
"differences": {
"name": {
"previous": "",
"current": "John Doe",
"status": "added"
},
"email": {
"previous": "",
"current": "employee1@example.com",
"status": "added"
},
"phone": {
"previous": "",
"current": "13488888888",
"status": "added"
},
"amount": {
"previous": "",
"current": "30",
"status": "added"
},
"coin": {
"previous": "",
"current": "USDC",
"status": "added"
},
"network": {
"previous": "",
"current": "Solana Devnet",
"status": "added"
},
"address": {
"previous": "",
"current": "CNJQ5q3kczhLWYQnh3YkKSwnS1fGJ9ydxvGN3KZuqy3G",
"status": "added"
}
},
"has_monthly_payment": false
},
{
"id": "payroll_item_nYuCYjVs1OvbOfldKD8A47tV",
"created_at": 1750147470,
"updated_at": 1750159306,
"payroll_id": "payroll_I6mzarIW0qZ4itwGg7xCa9EA",
"payroll": {
"id": "payroll_I6mzarIW0qZ4itwGg7xCa9EA",
"created_at": 1750147470,
"updated_at": 1750159306,
"canceled_at": 0,
"merchant_id": "accu_M7PTgveSgMtTtPHbjFgEtAlD",
"approval_status": "rejected",
"status": "rejected",
"total_item_num": 2,
"total_amount": "35",
"total_service_fee": "4",
"currency": "USD"
},
"name": "Jane Smith",
"email": "employee1@example.com",
"phone": "13488888888",
"amount": "5",
"service_fee": "2",
"exchange_rate_to_usd": "1",
"coin": "USDC",
"network": "Ethereum Sepolia",
"asset_id": "USDC-Ethereum-TEST",
"address": "0x36279Ac046498bF0cb742622cCe22F3cE3c2AfD9",
"address_verified": true,
"status": "rejected",
"transactions": null,
"validation": {
"name_valid": true,
"email_valid": true,
"phone_valid": true,
"amount_valid": true,
"coin_valid": true,
"network_valid": true,
"address_valid": true,
"payment_method_valid": true,
"balance_enough": true
},
"differences": {
"name": {
"previous": "Jane Smith",
"current": "Jane Smith",
"status": "unchanged"
},
"email": {
"previous": "employee2@example.com",
"current": "employee1@example.com",
"status": "unchanged"
},
"phone": {
"previous": "134333333333",
"current": "13488888888",
"status": "modified"
},
"amount": {
"previous": "5",
"current": "5",
"status": "unchanged"
},
"coin": {
"previous": "USDC",
"current": "USDC",
"status": "unchanged"
},
"network": {
"previous": "Ethereum Sepolia",
"current": "Ethereum Sepolia",
"status": "unchanged"
},
"address": {
"previous": "0x36279Ac046498bF0cb742622cCe22F3cE3c2AfD9",
"current": "0x36279Ac046498bF0cb742622cCe22F3cE3c2AfD9",
"status": "unchanged"
}
},
"has_monthly_payment": true
}
],
"swap_items": [
{
"id": "payroll_swap_item_n4rBJt7yuh6fVYCunWxQiJrd",
"lifi_quote_id": "f7800f87-ad2f-4411-b4e5-9a38eb03410e:0",
"created_at": 1750147470,
"updated_at": 1750159306,
"sent_at": null,
"merchant_id": "",
"payroll_id": "payroll_I6mzarIW0qZ4itwGg7xCa9EA",
"payroll": {
"id": "payroll_I6mzarIW0qZ4itwGg7xCa9EA",
"created_at": 1750147470,
"updated_at": 1750159306,
"canceled_at": 0,
"merchant_id": "accu_M7PTgveSgMtTtPHbjFgEtAlD",
"approval_status": "rejected",
"status": "rejected",
"total_item_num": 2,
"total_amount": "35",
"total_service_fee": "4",
"currency": "USD"
},
"from_asset_id": "USDC-Ethereum-TEST",
"expected_from_amount": "0",
"estimated_from_amount": "32.776548",
"estimated_from_amount_usd": "33",
"actual_from_amount": "0",
"network_fee": "0.03",
"to_asset_id": "USDC-Solana-TEST",
"expected_to_amount": "32",
"estimated_to_amount": "32.173331",
"estimated_to_amount_min": "32.012464",
"estimated_to_amount_usd": "32",
"actual_to_amount": "0",
"status": "rejected"
}
]
}
}

6.3 Cancel Payroll

Cancel a payroll that is in draft or pending status.

For detailed API reference, see: Cancel Payroll API

Request:

curl --location --request POST 'https://api.martianpay.com/v1/payrolls/payroll_I6mzarIW0qZ4itwGg7xCa9EA/cancel' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic {BASE64_ENCODE(api_key + ":")}'

Response:

{
"error_code": "success",
"msg": "success"
}

6.4 List Payroll Items

List payroll items across all payrolls or for a specific payroll.

For detailed API reference, see: List Payroll Items API

Request:

# List all payroll items
curl --location --request GET 'https://api.martianpay.com/v1/payrolls/items/list?page=0&page_size=10' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic {BASE64_ENCODE(api_key + ":")}'

# List items for a specific payroll by external_id
curl --location --request GET 'https://api.martianpay.com/v1/payrolls/items/list?external_id=ORDER-2024-001&page=0&page_size=10' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic {BASE64_ENCODE(api_key + ":")}'

Query Parameters:

  • page (required): Page number, starting from 0
  • page_size (required): Items per page (1-50)
  • start_date (optional): Filter by start date (YYYY-MM-DD)
  • end_date (optional): Filter by end date (YYYY-MM-DD)
  • employee_name (optional): Filter by employee name
  • external_id (optional): Filter by payroll external ID
  • payroll_id (optional): Filter by payroll ID
  • item_external_id (optional): Filter by payroll item external ID

Response:

{
"error_code": "success",
"msg": "success",
"data": {
"payroll_items": [
{
"id": "payroll_item_QZmpUMN5R1Gxohg7ADKbsnTW",
"created_at": 1750147470,
"updated_at": 1750159306,
"payroll_id": "payroll_I6mzarIW0qZ4itwGg7xCa9EA",
"payroll": {
"id": "payroll_I6mzarIW0qZ4itwGg7xCa9EA",
"created_at": 1750147470,
"updated_at": 1750159306,
"merchant_id": "accu_M7PTgveSgMtTtPHbjFgEtAlD",
"external_id": "ORDER-2024-001",
"approval_status": "approved",
"status": "paid",
"total_item_num": 2,
"total_amount": "35",
"total_service_fee": "4",
"currency": "USD"
},
"name": "John Doe",
"email": "john@example.com",
"phone": "13488888888",
"amount": "30",
"service_fee": "2",
"exchange_rate_to_usd": "1",
"coin": "USDT",
"network": "Tron",
"asset_id": "USDT-Tron",
"address": "TXkFhQXyCgDHcjVPnUTuexs5mrGPhTVXYD",
"address_verified": true,
"status": "paid",
"payment_method": "binance",
"is_binance": true,
"binance_tag": "BINANCE-001",
"binance_task_id": "binance_task_ABC123"
}
],
"total": 15
}
}

7. Webhook Events

MartianPay sends webhook notifications for important payroll and payroll item events. These webhooks help you track the status of your payroll transactions in real-time.

7.1 Payroll Events

Event TypeDescriptionTriggered When
payroll.createdPayroll batch createdA new payroll is created (draft status)
payroll.approvedPayroll batch approvedPayroll is approved through approval workflow
payroll.rejectedPayroll batch rejectedPayroll is rejected through approval workflow
payroll.canceledPayroll batch canceledPayroll is canceled by user
payroll.executingPayroll batch executingPayroll starts processing payments
payroll.completedPayroll batch completedAll payments in payroll completed successfully
payroll.failedPayroll batch failedAll payments in payroll failed

7.2 Payroll Item Events

Event TypeDescriptionTriggered When
payroll_item.processingPayroll item processingIndividual payment starts processing
payroll_item.succeededPayroll item succeededIndividual payment completed successfully
payroll_item.failedPayroll item failedIndividual payment failed
payroll_item.address_verification_sentAddress verification sentMicro-transfer sent for address verification
payroll_item.address_verifiedAddress verifiedAddress successfully verified by recipient

7.3 Webhook Payload Example

Here's an example of a payroll webhook event payload:

{
"id": "evt_056qw9fr9PndljykFUqSIf6t",
"object": "event",
"api_version": "2025-01-22",
"created": 1745580845,
"data": {
"object": {
"id": "payroll_I6mzarIW0qZ4itwGg7xCa9EA",
"created_at": 1750147470,
"updated_at": 1750159306,
"merchant_id": "accu_M7PTgveSgMtTtPHbjFgEtAlD",
"external_id": "ORDER-2024-001",
"approval_status": "approved",
"status": "executing",
"total_item_num": 2,
"total_amount": "35",
"total_service_fee": "4",
"currency": "USD"
},
"previous_attributes": {
"status": "approved",
"updated_at": 1750159300
}
},
"livemode": false,
"pending_webhooks": 0,
"type": "payroll.executing"
}

For payroll item events, the data.object will contain the PayrollItem object with details about the individual payment.

7.4 Webhook Event Flow

Typical Payroll Event Sequence:

  1. payroll.created - Payroll is created in draft status
  2. payroll.approved - Payroll is approved (or auto-approved)
  3. payroll.executing - Payment processing begins
  4. For each item:
    • payroll_item.processing - Item starts processing
    • payroll_item.address_verification_sent - (if needed) Verification sent
    • payroll_item.address_verified - (if needed) Address verified
    • payroll_item.succeeded or payroll_item.failed - Final item status
  5. payroll.completed or payroll.failed - Final payroll status

💡 Recommendation: We strongly recommend monitoring payroll_item.* events for granular tracking of individual payments. Item-level events provide the most detailed and actionable information for your payroll operations.

Why Monitor Item Events?

Payroll EventsPayroll Item Events
Track overall batch status✅ Track each individual payment
Limited actionability✅ Immediate notification for failures
Single notification per batch✅ Real-time updates per employee
Cannot identify which payment failed✅ Pinpoint exact failed payments

Event Monitoring Strategy:

PriorityEvents to MonitorUse Case
Highpayroll_item.succeededConfirm individual payment success, update employee records
Highpayroll_item.failedAlert on payment failures, take immediate action
Highpayroll_item.address_verification_sentNotify employees to verify their address
Highpayroll_item.address_verifiedConfirm address verification completed
Mediumpayroll.executingKnow when batch processing starts
Mediumpayroll.completedConfirm entire batch finished
Lowpayroll.createdTrack batch creation (optional)

7.6 Best Practices

  1. Prioritize payroll_item events - Monitor payroll_item.* events for real-time, actionable insights on individual payments. These events let you:

    • Immediately identify and retry failed payments
    • Track payment status per employee
    • Send targeted notifications to employees
    • Update payment records at a granular level
  2. Handle idempotency - Store the event ID (evt_*) to prevent duplicate processing of the same webhook

  3. Monitor address verification flow - Track payroll_item.address_verification_sent and payroll_item.address_verified events to:

    • Send reminder emails to employees who haven't verified
    • Track verification completion rates
    • Alert employees about pending verifications
  4. Reconcile with external_id - Use the external_id field to match webhook events with your internal payroll records

  5. Implement automated retry logic - For payroll_item.failed events:

    • Automatically retry transient failures (network issues, temporary wallet unavailability)
    • Alert administrators for permanent failures (invalid address, insufficient balance)
    • Track retry attempts to prevent infinite loops
  6. Build employee dashboards - Use item events to show real-time payment status to employees in your system

For more details on webhook setup, signature verification, and complete event schemas, see the Webhook Events documentation.