# Create Transfer
> Source: /api-reference/members/me/transfers/create-transfer
> Transfer points to another member or create pending gift transfer
> Endpoint: POST /members/me/transfers

## Overview [#overview]

Transfer points to another member directly (using their member external ID) or create a pending gift transfer (using email or phone). Pending transfers can be claimed by the recipient later when they join or verify their contact information.

## Authentication [#authentication]

Requires a valid Clerk JWT token in the Authorization header.

## Security [#security]

**Reverification Required**: This endpoint requires reverification if the user hasn't verified their credentials within the last 10 minutes. This is a sensitive action involving point transfers.

## Request Body [#request-body]

<ParamField body="toMemberExternalId" type="string">
  Recipient member external ID (ULID) for existing member transfer. Must be exactly 26 characters.
</ParamField>

<ParamField body="recipientEmail" type="string">
  Recipient email for gift transfer (pending). Valid email format required.
</ParamField>

<ParamField body="recipientPhone" type="string">
  Recipient phone for gift transfer (pending). Must be valid E.164 format (e.g., +1234567890).
</ParamField>

<ParamField body="amount" type="number" required>
  Amount of points to transfer. Must be at least 1 point and within your transfer limits.
</ParamField>

<ParamField body="note" type="string">
  Optional note/message for the transfer. Maximum 500 characters.
</ParamField>

**Note**: Either `toMemberExternalId` OR (`recipientEmail` or `recipientPhone`) must be provided, but not both.

<RequestExample>

```bash cURL - Direct Transfer
curl -X POST "http://localhost:3000/v1/members/me/transfers" \
  -H "Authorization: Bearer YOUR_CLERK_JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "toMemberExternalId": "01ARZ3NDEKTSV4RRFFQ69G5FAV",
    "amount": 1000,
    "note": "Happy birthday!"
  }'
```

```bash cURL - Gift Transfer (Email)
curl -X POST "http://localhost:3000/v1/members/me/transfers" \
  -H "Authorization: Bearer YOUR_CLERK_JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "recipientEmail": "friend@example.com",
    "amount": 500,
    "note": "Gift for you!"
  }'
```

```bash cURL - Gift Transfer (Phone)
curl -X POST "http://localhost:3000/v1/members/me/transfers" \
  -H "Authorization: Bearer YOUR_CLERK_JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "recipientPhone": "+1234567890",
    "amount": 750,
    "note": "Thanks for your help!"
  }'
```

```typescript TypeScript
// Direct transfer to existing member
const directTransfer = await fetch('http://localhost:3000/v1/members/me/transfers', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_CLERK_JWT',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    toMemberExternalId: '01ARZ3NDEKTSV4RRFFQ69G5FAV',
    amount: 1000,
    note: 'Happy birthday!'
  })
});

// Gift transfer to email
const giftTransfer = await fetch('http://localhost:3000/v1/members/me/transfers', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_CLERK_JWT',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    recipientEmail: 'friend@example.com',
    amount: 500,
    note: 'Gift for you!'
  })
});
```

</RequestExample>

## Response [#response]

<ResponseField name="transferId" type="string" required>
  Transfer ID (correlation ID) for tracking the transfer
</ResponseField>

<ResponseField name="correlationId" type="string" required>
  Correlation ID for the transfer transaction (same as transferId)
</ResponseField>

<ResponseField name="amount" type="number" required>
  Amount transferred in points
</ResponseField>

<ResponseField name="status" type="string" required>
  Transfer status: "COMPLETED" for direct transfers, "PENDING" for gift transfers
</ResponseField>

<ResponseField name="expiresAt" type="string">
  Expiration date for pending transfers (ISO 8601 format). Only present for gift transfers.
</ResponseField>

<ResponseExample>

```json 201 Response - Direct Transfer (Completed)
{
  "transferId": "018f1234-5678-9abc-def0-123456789abc",
  "correlationId": "018f1234-5678-9abc-def0-123456789abc",
  "amount": 1000,
  "status": "COMPLETED"
}
```

```json 201 Response - Gift Transfer (Pending)
{
  "transferId": "018f5678-1234-9abc-def0-123456789abc",
  "correlationId": "018f5678-1234-9abc-def0-123456789abc",
  "amount": 500,
  "status": "PENDING",
  "expiresAt": "2025-02-15T00:00:00Z"
}
```

```json 400 Response - Insufficient Balance
{
  "statusCode": 400,
  "message": "Insufficient balance",
  "error": "INSUFFICIENT_BALANCE",
  "details": {
    "currentBalance": 250,
    "requiredAmount": 1000
  }
}
```

```json 400 Response - Self Transfer
{
  "statusCode": 400,
  "message": "You cannot transfer points to yourself",
  "error": "SELF_TRANSFER"
}
```

```json 400 Response - Limit Exceeded
{
  "statusCode": 400,
  "message": "Transfer amount exceeds daily limit",
  "error": "TRANSFER_LIMIT_EXCEEDED",
  "details": {
    "code": "DAILY_LIMIT_EXCEEDED",
    "limit": 100000
  }
}
```

```json 400 Response - Invalid Recipient
{
  "statusCode": 400,
  "message": "Either toMemberExternalId, recipientEmail, or recipientPhone must be provided"
}
```

```json 403 Response - Reverification Required
{
  "statusCode": 403,
  "message": "Reverification required for this sensitive action"
}
```

</ResponseExample>

## Transfer Types [#transfer-types]

### Direct Transfer (Member-to-Member) [#direct-transfer-member-to-member]
- **Recipient**: Existing member identified by external ID
- **Status**: COMPLETED immediately
- **Points**: Transferred instantly to recipient's account
- **Use Case**: Send points to known members

### Gift Transfer (Pending) [#gift-transfer-pending]
- **Recipient**: Email or phone number (not yet a member)
- **Status**: PENDING until claimed
- **Expiration**: 30 days from creation
- **Points**: Held in escrow until claimed or expired
- **Use Case**: Gift points to friends who aren't members yet

## Validation Rules [#validation-rules]

### Amount Limits [#amount-limits]
- **Minimum**: 1 point
- **Maximum**: Based on your tier and transfer limits
- **Check**: Use [Get Transfer Limits](/api-reference/members/me/transfers/get-limits) to verify

### Recipient Validation [#recipient-validation]
- **Member External ID**: Must be valid 26-character ULID
- **Email**: Must be valid email format
- **Phone**: Must be valid E.164 format
- **Self Transfer**: Cannot transfer to yourself

### Balance Check [#balance-check]
- **Sufficient Balance**: Must have enough VALID points
- **Real-time**: Balance checked at transfer time
- **Type**: Only VALID points can be transferred (not CREDIT points)

## Error Handling [#error-handling]

### Common Errors [#common-errors]
| Error Code | Description | Resolution |
|------------|-------------|------------|
| `INSUFFICIENT_BALANCE` | Not enough points | Check wallet balance |
| `SELF_TRANSFER` | Trying to send to self | Use different recipient |
| `TRANSFER_LIMIT_EXCEEDED` | Exceeds daily/monthly limits | Wait or contact support |
| `TRANSFER_FAILED` | Generic transfer failure | Retry or contact support |

### Rate Limiting [#rate-limiting]
- **No specific rate limit** for transfers
- **Security measures** in place for fraud prevention
- **Reverification required** for sensitive actions

## Use Cases [#use-cases]

### Send Birthday Gift [#send-birthday-gift]
```typescript
const sendBirthdayGift = async (recipientEmail: string, amount: number) => {
  try {
    const response = await fetch('/api/members/me/transfers', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        recipientEmail,
        amount,
        note: '🎂 Happy Birthday! Enjoy some points on me!'
      })
    });
    
    const result = await response.json();
    
    if (response.ok) {
      console.log(`Gift sent! Transfer ID: ${result.transferId}`);
      console.log(`Status: ${result.status}`);
      if (result.expiresAt) {
        console.log(`Expires: ${result.expiresAt}`);
      }
    } else {
      handleTransferError(result);
    }
  } catch (error) {
    console.error('Failed to send gift:', error);
  }
};
```

### Transfer to Known Member [#transfer-to-known-member]
```typescript
const transferToMember = async (memberExternalId: string, amount: number, note: string) => {
  try {
    const response = await fetch('/api/members/me/transfers', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        toMemberExternalId: memberExternalId,
        amount,
        note
      })
    });
    
    const result = await response.json();
    
    if (response.ok && result.status === 'COMPLETED') {
      console.log(`Transfer completed! ${amount} points sent.`);
    }
  } catch (error) {
    console.error('Transfer failed:', error);
  }
};
```

### Bulk Gift Campaign [#bulk-gift-campaign]
```typescript
const sendBulkGifts = async (recipients: Array<{email: string, amount: number}>) => {
  const results = await Promise.allSettled(
    recipients.map(({email, amount}) => 
      fetch('/api/members/me/transfers', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          recipientEmail: email,
          amount,
          note: 'Thank you for being an amazing customer!'
        })
      })
    )
  );
  
  const successful = results.filter(r => r.status === 'fulfilled').length;
  console.log(`${successful}/${recipients.length} gifts sent successfully`);
};
```

## Security Notes [#security-notes]

### Reverification [#reverification]
- **Required**: For all transfer operations
- **Timeframe**: Within last 10 minutes
- **Methods**: SMS OTP or email verification
- **Bypass**: Not possible for security reasons

### Fraud Prevention [#fraud-prevention]
- **Monitoring**: Unusual transfer patterns detected
- **Limits**: Daily and monthly transfer limits enforced
- **Validation**: Recipient verification for suspicious activity

## Related Endpoints [#related-endpoints]

- [Get Transfer Limits](/api-reference/members/me/transfers/get-limits) - Check your transfer limits before sending
- [Member Lookup](/api-reference/members/me/transfers/lookup-member) - Find member details before transferring
- [List Pending Transfers](/api-reference/members/me/transfers/list-pending) - View your pending transfers
- [Claim Pending Transfer](/api-reference/members/me/transfers/claim-pending) - Claim gifts sent to you
