Members APITransfers
Claim Pending Transfer
Claim pending transfers sent to your email or phone
POST
/members/me/transfers/claimOverview
Claims all pending transfers sent to the provided email or phone number. The member must own the provided contact information (verified in their account). This endpoint allows members to claim gift transfers that were sent to them before they had an account or before they verified their contact details.
Authentication
Requires a valid Clerk JWT token in the Authorization header.
Request Body
emailbodystringEmail address to claim transfers for. Must be verified in your account.
phonebodystringPhone number to claim transfers for (E.164 format). Must be verified in your account.
Note: Either email or phone must be provided.
Request
curl -X POST "http://localhost:3000/v1/members/me/transfers/claim" \
-H "Authorization: Bearer YOUR_CLERK_JWT" \
-H "Content-Type: application/json" \
-d '{
"email": "myemail@example.com"
}'Response
totalClaimednumberrequiredTotal points claimed from pending transfers
messagestringrequiredSuccess message describing the claim result
Response
{
"totalClaimed": 5000,
"message": "Successfully claimed 5000 points"
}How Claiming Works
Contact Verification Required
- Email: Must be verified in your Clerk account
- Phone: Must be verified in your Clerk account
- Security: Prevents claiming transfers sent to others
- Validation: Real-time verification against your account
Claiming Process
- Identify Transfers: Find all pending transfers sent to the contact
- Verify Ownership: Confirm you own the contact information
- Transfer Points: Move points from escrow to your account
- Update Status: Mark transfers as CLAIMED
- Send Notifications: Notify senders their gifts were claimed
Multiple Claims
- Batch Processing: Claims all pending transfers at once
- No Duplicates: Already claimed transfers are ignored
- Atomic Operation: All transfers claimed together or none
- Total Calculation: Sum of all successfully claimed amounts
Contact Information Requirements
Email Requirements
- Verified: Must be verified in your Clerk account
- Case Insensitive: Matching is case insensitive
- Primary/Secondary: Any verified email can be used
- Domain Matching: Exact domain matching required
Phone Requirements
- E.164 Format: Must be in international format (+1234567890)
- Verified: Must be verified in your Clerk account
- Number Normalization: Numbers normalized for matching
- Country Code: Country code required
Security Measures
Ownership Validation
- Real-time Check: Validates contact ownership at claim time
- Account Verification: Cross-references with Clerk verification status
- No Spoofing: Cannot claim transfers for unverified contacts
- Audit Trail: All claim attempts logged for security
Fraud Prevention
- Rate Limiting: No specific rate limit (secure by design)
- Contact Verification: Strong verification requirements
- Transfer History: Full audit trail of claims
- Sender Notification: Senders notified when gifts are claimed
Use Cases
New Member Onboarding
// Check for pending transfers during onboarding
const checkPendingGifts = async (userContacts: {email?: string, phone?: string}) => {
const results = [];
if (userContacts.email) {
try {
const emailResult = await fetch('/api/members/me/transfers/claim', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email: userContacts.email })
});
const data = await emailResult.json();
if (data.totalClaimed > 0) {
results.push({
contact: userContacts.email,
type: 'email',
claimed: data.totalClaimed
});
}
} catch (error) {
console.error('Email claim failed:', error);
}
}
if (userContacts.phone) {
try {
const phoneResult = await fetch('/api/members/me/transfers/claim', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ phone: userContacts.phone })
});
const data = await phoneResult.json();
if (data.totalClaimed > 0) {
results.push({
contact: userContacts.phone,
type: 'phone',
claimed: data.totalClaimed
});
}
} catch (error) {
console.error('Phone claim failed:', error);
}
}
return results;
};Contact Verification Trigger
// Automatically claim pending transfers when contact is verified
const onContactVerified = async (contact: string, type: 'email' | 'phone') => {
try {
const response = await fetch('/api/members/me/transfers/claim', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ [type]: contact })
});
const result = await response.json();
if (result.totalClaimed > 0) {
// Show success notification
showNotification({
title: 'Gift Points Claimed!',
message: `You've received ${result.totalClaimed} points from pending gifts!`,
type: 'success'
});
// Refresh wallet balance
refreshWalletBalance();
}
} catch (error) {
console.error('Auto-claim failed:', error);
}
};Bulk Contact Processing
// Process multiple contacts for claims
const claimAllContacts = async () => {
const userProfile = await getUserProfile();
const claims = [];
// Process all verified emails
for (const email of userProfile.verifiedEmails) {
try {
const response = await fetch('/api/members/me/transfers/claim', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email })
});
const result = await response.json();
if (result.totalClaimed > 0) {
claims.push({ contact: email, amount: result.totalClaimed });
}
} catch (error) {
console.error(`Email claim failed for ${email}:`, error);
}
}
// Process all verified phones
for (const phone of userProfile.verifiedPhones) {
try {
const response = await fetch('/api/members/me/transfers/claim', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ phone })
});
const result = await response.json();
if (result.totalClaimed > 0) {
claims.push({ contact: phone, amount: result.totalClaimed });
}
} catch (error) {
console.error(`Phone claim failed for ${phone}:`, error);
}
}
return claims;
};Error Handling
Common Errors
| Error Code | Description | Resolution |
|---|---|---|
| Missing Contact | No email or phone provided | Provide either email or phone |
| Unverified Contact | Contact not verified in account | Verify contact in account settings |
| No Transfers | No pending transfers found | No action needed |
| Claim Failed | Generic claim failure | Contact support |
Error Recovery
const handleClaimError = (error: any, contact: string, type: 'email' | 'phone') => {
switch (error.error) {
case 'CLAIM_FAILED':
if (error.message.includes('not verified')) {
// Guide user to verify their contact
showVerificationModal(contact, type);
} else {
// Generic failure - suggest retry
showRetryOption(() => claimTransfers(contact, type));
}
break;
default:
// Unknown error
showErrorMessage('Unable to claim transfers. Please try again later.');
}
};Related Endpoints
- Create Transfer - Send gift transfers that can be claimed
- List Pending Transfers - View transfers available for claiming
- Get Wallet Balance - Check balance after claiming
- Get Profile - View verified contacts eligible for claiming