# Claim Pending Transfer
> Source: /api-reference/members/me/transfers/claim-pending
> Claim pending transfers sent to your email or phone
> Endpoint: POST /members/me/transfers/claim

## Overview [#overview]

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 [#authentication]

Requires a valid Clerk JWT token in the Authorization header.

## Request Body [#request-body]

<ParamField body="email" type="string">
  Email address to claim transfers for. Must be verified in your account.
</ParamField>

<ParamField body="phone" type="string">
  Phone number to claim transfers for (E.164 format). Must be verified in your account.
</ParamField>

**Note**: Either `email` or `phone` must be provided.

<RequestExample>

```bash cURL - Claim by Email
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"
  }'
```

```bash cURL - Claim by Phone
curl -X POST "http://localhost:3000/v1/members/me/transfers/claim" \
  -H "Authorization: Bearer YOUR_CLERK_JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "+1234567890"
  }'
```

```typescript TypeScript
// Claim transfers by email
const claimByEmail = async (email: string) => {
  const response = await fetch('http://localhost:3000/v1/members/me/transfers/claim', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_CLERK_JWT',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ email })
  });
  
  return response.json();
};

// Claim transfers by phone
const claimByPhone = async (phone: string) => {
  const response = await fetch('http://localhost:3000/v1/members/me/transfers/claim', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_CLERK_JWT',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ phone })
  });
  
  return response.json();
};
```

</RequestExample>

## Response [#response]

<ResponseField name="totalClaimed" type="number" required>
  Total points claimed from pending transfers
</ResponseField>

<ResponseField name="message" type="string" required>
  Success message describing the claim result
</ResponseField>

<ResponseExample>

```json 200 Response - Transfers Claimed
{
  "totalClaimed": 5000,
  "message": "Successfully claimed 5000 points"
}
```

```json 200 Response - No Transfers
{
  "totalClaimed": 0,
  "message": "Successfully claimed 0 points"
}
```

```json 200 Response - Multiple Claims
{
  "totalClaimed": 12500,
  "message": "Successfully claimed 12500 points"
}
```

```json 400 Response - Missing Contact
{
  "statusCode": 400,
  "message": "Either email or phone is required to claim transfers"
}
```

```json 400 Response - Contact Not Verified
{
  "statusCode": 400,
  "message": "Contact information not verified in your account",
  "error": "CLAIM_FAILED"
}
```

```json 400 Response - Contact Not Found
{
  "statusCode": 400,
  "message": "No verified contact found matching the provided information",
  "error": "CLAIM_FAILED"
}
```

</ResponseExample>

## How Claiming Works [#how-claiming-works]

### Contact Verification Required [#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 [#claiming-process]
1. **Identify Transfers**: Find all pending transfers sent to the contact
2. **Verify Ownership**: Confirm you own the contact information
3. **Transfer Points**: Move points from escrow to your account
4. **Update Status**: Mark transfers as CLAIMED
5. **Send Notifications**: Notify senders their gifts were claimed

### Multiple Claims [#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 [#contact-information-requirements]

### Email 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 [#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 [#security-measures]

### Ownership Validation [#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 [#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 [#use-cases]

### New Member Onboarding [#new-member-onboarding]
```typescript
// 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 [#contact-verification-trigger]
```typescript
// 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 [#bulk-contact-processing]
```typescript
// 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 [#error-handling]

### Common Errors [#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 [#error-recovery]
```typescript
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 [#related-endpoints]

- [Create Transfer](/api-reference/members/me/transfers/create-transfer) - Send gift transfers that can be claimed
- [List Pending Transfers](/api-reference/members/me/transfers/list-pending) - View transfers available for claiming
- [Get Wallet Balance](/api-reference/members/wallet/get-balance) - Check balance after claiming
- [Get Profile](/api-reference/members/me/get-me) - View verified contacts eligible for claiming
