Transfer approvals apply to on-chain stablecoin transfers (wallet transfers,
batch transfers, and bridging) and offramps. Onramps do not support approval
workflows.
How Transfer Approvals Work
Create transfer with approval
Include requireApproval: true when creating a transfer via API.
Transfer enters pending state
Transfer status becomes PENDING_APPROVAL and does not execute.
Admin notification
Dashboard admins receive email notifications about the pending approval.
Approve or reject
Authorized admins review and either approve or reject the transfer.
Execution or cancellation
If approved, transfer executes normally. If rejected, transfer is cancelled.
Implementation Options
Transfer approvals work differently depending on where transactions are initiated:
Dashboard Approvals
When transfers are created in the HIFI Dashboard:
- Members can initiate wallet transfers
- Member-initiated transfers require Admin approval before execution
- Admin-initiated transfers execute without approval
- Members can initiate offramp transactions, and these will always enter the transfer approval flow (require Admin approval)
- Email notifications sent for approvals and rejections
API Approvals
When using the API:
- Include
requireApproval: true when creating transfers
- Transfers enter approval workflow until approved or rejected
- Supported on wallet transfers, batch transfers, bridging, and offramps
- Offramp transactions will enter the transfer approval flow only if
requireApproval: true is set in the request body
- Can be integrated into your application’s approval logic
Creating Transfers with Approval
Add the requireApproval parameter to any supported transaction endpoint.
Request:
curl -X POST "https://sandbox.hifi.com/v2/wallets/transfers" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"requestId": "a40ea2aa-7937-4be9-bb1f-b75f1489bcc6",
"source": {
"userId": "usr_abc123"
},
"destination": {
"userId": "usr_xyz789"
},
"amount": 10000,
"currency": "usdc",
"chain": "POLYGON",
"requireApproval": true
}'
Response:
{
"transferType": "WALLET.TRANSFER",
"transferDetails": {
"id": "xfr_abc123",
"requestId": "a40ea2aa-7937-4be9-bb1f-b75f1489bcc6",
"status": "PENDING_APPROVAL",
"amount": 10000,
"currency": "usdc",
"chain": "POLYGON",
"receipt": {
"approval": {
"id": "apv_xyz789",
"status": "PENDING",
"transferId": "xfr_abc123",
"transferType": "WALLET.TRANSFER",
"createdAt": "2025-02-03T16:11:36.654998+00:00",
"votes": []
}
}
}
}
Supported Endpoints
The requireApproval parameter works with:
| Endpoint | Transfer Type |
|---|
POST /v2/wallets/transfers | Single wallet transfers |
POST /v2/wallets/transfers/batches | Batch transfers (up to 50 recipients) |
POST /v2/wallets/bridges | Cross-chain bridging transfers |
POST /v2/offramps | Offramp transfers (stablecoin to fiat) |
Bridging and Offramp Note: For bridging transfers and offramps, quotes are
generated after approval. This prevents quotes from expiring while
awaiting review.
Listing Pending Approvals
Retrieve all transactions awaiting approval using the List Transaction Approvals endpoint.
Request:
curl -X GET "https://sandbox.hifi.com/v2/transfer-approvals?limit=20&offset=0" \
-H "Authorization: Bearer YOUR_API_KEY"
Query Parameters:
- limit (optional): Number of approvals to return (default: 20, max: 100)
- offset (optional): Number of approvals to skip for pagination (default: 0)
Response:
{
"success": true,
"message": "Pending approvals retrieved successfully",
"count": 2,
"approvals": [
{
"id": "apv_abc123",
"transferId": "xfr_xyz789",
"status": "PENDING",
"transferType": "WALLET.TRANSFER",
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T11:00:00.000Z"
},
{
"id": "apv_def456",
"transferId": "bat_ghi789",
"status": "PENDING",
"transferType": "WALLET.TRANSFER.BATCH",
"createdAt": "2024-01-15T09:15:00.000Z",
"updatedAt": "2024-01-15T09:15:00.000Z"
}
]
}
Use this endpoint to build approval dashboards or automate approval workflows.
Approving Transfers
Approve pending transfers using the Approve Transfer endpoint.
Request:
curl -X POST "https://sandbox.hifi.com/v2/transfer-approvals/apv_abc123/approve" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"comment": "Approved after reviewing transaction details"
}'
Request Fields:
- approvalId (required, path): ID of the approval to approve
- comment (optional): Explanation for the approval decision (max 1000 characters)
Response:
{
"success": true,
"message": "Transfer approved and initiated successfully",
"approvalId": "apv_abc123",
"status": "APPROVED",
"timestamp": "2024-01-15T11:00:00.000Z"
}
After approval, the transfer proceeds to execution immediately.
Rejecting Transfers
Reject pending transfers using the Reject Transfer endpoint.
Request:
curl -X POST "https://sandbox.hifi.com/v2/transfer-approvals/apv_abc123/reject" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"comment": "Transfer amount exceeds daily limit"
}'
Request Fields:
- approvalId (required, path): ID of the approval to reject
- comment (optional): Reason for rejection (max 1000 characters)
Response:
{
"success": true,
"message": "Transfer rejected successfully",
"approvalId": "apv_abc123",
"status": "REJECTED",
"timestamp": "2024-01-15T11:00:00.000Z"
}
Rejected transactions are cancelled and will not execute.
Approval Status Flow
Transactions with requireApproval: true follow this status progression:
| Status | Description |
|---|
| PENDING_APPROVAL | Transaction awaiting admin approval |
| APPROVED | Transaction approved and proceeding to execution |
| REJECTED | Transaction rejected and cancelled |
After approval, transactions move to normal execution statuses (CREATED, INITIATED, PENDING, COMPLETED).
Expiration Times: Transactions in PENDING_APPROVAL status will
automatically expire if not approved or rejected within the following
timeframes: - Onchain transfers (wallet transfers, batch transfers,
bridging): Expire after 1 week - Offramps: Expire after 1 day
Expired transactions are automatically cancelled and cannot be executed.
Status Updates: Subscribe to TRANSFER.APPROVAL.PENDING,
TRANSFER.APPROVAL.APPROVED, and TRANSFER.APPROVAL.REJECTED webhook events
to receive real-time approval notifications. See Webhooks
for setup instructions.
Notifications
Email Notifications
Admins receive notifications when:
- A transaction requires approval (Member-initiated)
- A transaction needs their review
Members receive notifications when:
- Their transaction request is approved
- Their transaction request is rejected (with reason if provided)
Webhook Events
Subscribe to approval events for automated workflows:
| Event Type | Description |
|---|
| TRANSFER.APPROVAL.PENDING | Transaction created, awaiting approval |
| TRANSFER.APPROVAL.APPROVED | Transaction approved, proceeding to execution |
| TRANSFER.APPROVAL.REJECTED | Transaction rejected and cancelled |
Sample Code
Here’s a complete approval workflow implementation:
Create a High-Value Transaction That Requires Approval
To trigger an approval workflow for transactions over a certain threshold (e.g., $10k), include requireApproval: true in your request:async function createHighValueTransfer(amount, destinationUserId) {
const requireApproval = amount > 10000;
const transfer = await fetch('https://sandbox.hifi.com/v2/wallets/transfers', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
requestId: crypto.randomUUID(),
source: { userId: 'usr_treasury' },
destination: { userId: destinationUserId },
amount,
currency: 'usdc',
chain: 'POLYGON',
requireApproval
})
}).then(r => r.json());
if (transfer.transferDetails.status === 'PENDING_APPROVAL') {
notifyApprovers(transfer.transferDetails.id);
}
return transfer;
}
If the transaction is flagged for approval, notify approvers (e.g., by email or internal notification). List Pending Approvals (for Admin Review)
Fetch all pending transaction approvals to display in an admin dashboard:async function fetchPendingApprovals() {
const approvals = await fetch(
'https://sandbox.hifi.com/v2/transfer-approvals?limit=50',
{
headers: { 'Authorization': 'Bearer YOUR_API_KEY' }
}
).then(r => r.json());
return approvals.approvals.map(approval => ({
id: approval.id,
transferId: approval.transferId,
type: approval.transferType,
pendingSince: approval.createdAt
}));
}
Approve a Pending Transaction
Admins can approve a pending transaction by submitting an approval action:async function approveTransfer(approvalId, adminComment) {
const approval = await fetch(
`https://sandbox.hifi.com/v2/transfer-approvals/${approvalId}/approve`,
{
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
comment: adminComment
})
}
).then(r => r.json());
console.log('Transaction approved:', approval.approvalId);
return approval;
}
React to Approval Webhook Events
Use webhook events to automatically notify stakeholders and update your application’s state:function handleApprovalWebhook(event) {
switch (event.eventType) {
case 'TRANSFER.APPROVAL.PENDING':
sendSlackNotification({
message: `Transaction ${event.data.transferId} requires approval`,
amount: event.data.amount,
destination: event.data.destination
});
break;
case 'TRANSFER.APPROVAL.APPROVED':
updateTransferStatus(event.data.transferId, 'APPROVED');
notifyRequester(event.data.initiatorId, 'approved');
break;
case 'TRANSFER.APPROVAL.REJECTED':
notifyRequester(event.data.initiatorId, 'rejected', event.data.comment);
break;
}
}
Subscribe to webhook endpoints to handle TRANSFER.APPROVAL.* events.
Getting Help