# Templates API

The Templates API allows you to send WhatsApp template messages to users. Templates are pre-approved message formats for marketing, utility, and authentication purposes.

## Import

```typescript
import { Templates } from 'lua-cli';
```

## Overview

The Templates API enables:
- List WhatsApp templates for a channel
- Get specific template details
- Send template messages to phone numbers
- Use template variables for personalization
- Send bulk messages with templates
- Access button values and actions

## Methods

| Method | Description |
|--------|-------------|
| `Templates.whatsapp.list(channelId, options?)` | List all templates for a WhatsApp channel |
| `Templates.whatsapp.get(channelId, templateId)` | Get a specific template |
| `Templates.whatsapp.send(channelId, templateId, data)` | Send template to phone numbers |

## Template Categories

```typescript
type WhatsAppTemplateCategory =
  | 'AUTHENTICATION'  // OTP, verification codes
  | 'MARKETING'       // Promotional messages
  | 'UTILITY';        // Transactional, notifications
```

## Template Status

```typescript
type WhatsAppTemplateStatus =
  | 'APPROVED'   // Ready to use
  | 'REJECTED'   // Not approved by WhatsApp
  | 'PENDING';   // Awaiting approval
```

## Methods

### `Templates.whatsapp.list(channelId, options?)`

Lists all templates for a WhatsApp channel with pagination.

**Parameters:**
- `channelId` (string) - WhatsApp channel ID
- `options` (object, optional)
  - `page` (number) - Page number (default: 1)
  - `limit` (number) - Results per page (default: 10)
  - `search` (string) - Search by template name

**Returns:** `Promise<PaginatedTemplatesResponse>`
- `templates` - Array of template objects
- `total` - Total template count
- `page` - Current page
- `limit` - Page size
- `totalPages` - Total pages

**Example:**
```typescript
const response = await Templates.whatsapp.list('channel_123', {
  page: 1,
  limit: 20,
  search: 'order'
});

console.log(`Found ${response.total} templates`);
response.templates.forEach(template => {
  console.log(`${template.name} - ${template.status}`);
});
```

### `Templates.whatsapp.get(channelId, templateId)`

Gets a specific template by ID.

**Parameters:**
- `channelId` (string) - WhatsApp channel ID
- `templateId` (string) - Template ID

**Returns:** `Promise<WhatsAppTemplate>`

**Example:**
```typescript
const template = await Templates.whatsapp.get('channel_123', 'template_456');

console.log(template.name);
console.log(template.category);
console.log(template.components);
```

### `Templates.whatsapp.send(channelId, templateId, data)`

Sends a template message to one or more phone numbers.

**Parameters:**
- `channelId` (string) - WhatsApp channel ID
- `templateId` (string) - Template ID
- `data` (object)
  - `phoneNumbers` (string[]) - Array of phone numbers (E.164 format)
  - `values` (object, optional) - Template variable values
    - `header` (object) - Header variables (key-value pairs)
    - `body` (object) - Body variables (key-value pairs)
    - `buttons` (array) - Button values

**Returns:** `Promise<SendTemplateResponse>`
- `results` - Array of successful sends
- `errors` - Array of failed sends
- `totalProcessed` - Total messages processed
- `totalErrors` - Total errors

**Example:**
```typescript
const response = await Templates.whatsapp.send(
  'channel_123',
  'template_456',
  {
    phoneNumbers: ['+1234567890', '+0987654321'],
    values: {
      body: {
        name: 'John Doe',
        order_id: 'ORD-12345'
      }
    }
  }
);

console.log(`Sent ${response.totalProcessed} messages`);
console.log(`Errors: ${response.totalErrors}`);
```

## Template Structure

### Template Components

Templates consist of components:

```typescript
interface WhatsAppTemplate {
  id: string;
  name: string;
  category: 'AUTHENTICATION' | 'MARKETING' | 'UTILITY';
  language: string;
  status: 'APPROVED' | 'REJECTED' | 'PENDING';
  components: [
    {
      type: 'HEADER';
      format: 'TEXT';
      text: string;
    },
    {
      type: 'BODY';
      text: string;
    },
    {
      type: 'FOOTER';
      text: string;
    },
    {
      type: 'BUTTONS';
      buttons: [...]
    }
  ];
}
```

### Button Types

Templates can include buttons:

```typescript
// Quick Reply Button
{
  type: 'QUICK_REPLY',
  text: 'Yes, I confirm'
}

// Call Button
{
  type: 'PHONE_NUMBER',
  text: 'Call Support',
  phone_number: '+1234567890'
}

// URL Button
{
  type: 'URL',
  text: 'Visit Website',
  url: 'https://example.com'
}

// Copy Code Button (for OTP)
{
  type: 'COPY_CODE',
  example: '123456'
}
```

## Complete Examples

### Send Order Confirmation

```typescript
import { LuaTool, Templates } from 'lua-cli';
import { z } from 'zod';

export default class SendOrderConfirmationTool implements LuaTool {
  name = 'send_order_confirmation';
  description = 'Send WhatsApp order confirmation';

  inputSchema = z.object({
    phoneNumber: z.string(),
    orderNumber: z.string(),
    customerName: z.string(),
    totalAmount: z.number()
  });

  async execute(input: z.infer<typeof this.inputSchema>) {
    const channelId = process.env.WHATSAPP_CHANNEL_ID!;
    const templateId = 'order_confirmation_template';

    try {
      const response = await Templates.whatsapp.send(
        channelId,
        templateId,
        {
          phoneNumbers: [input.phoneNumber],
          values: {
            body: {
              customer_name: input.customerName,
              order_number: input.orderNumber,
              total_amount: input.totalAmount.toFixed(2)
            }
          }
        }
      );

      if (response.totalErrors > 0) {
        return {
          success: false,
          error: 'Failed to send confirmation',
          errors: response.errors
        };
      }

      return {
        success: true,
        message: 'Order confirmation sent',
        orderNumber: input.orderNumber
      };
    } catch (error) {
      return {
        success: false,
        error: error instanceof Error ? error.message : 'Send failed'
      };
    }
  }
}
```

### Send OTP Code

```typescript
import { LuaTool, Templates } from 'lua-cli';
import { z } from 'zod';

export default class SendOTPTool implements LuaTool {
  name = 'send_otp';
  description = 'Send OTP verification code via WhatsApp';

  inputSchema = z.object({
    phoneNumber: z.string().describe('Phone number in E.164 format'),
    otp: z.string().length(6).describe('6-digit OTP code')
  });

  async execute(input: z.infer<typeof this.inputSchema>) {
    const channelId = process.env.WHATSAPP_CHANNEL_ID!;
    const templateId = 'otp_verification_template';

    try {
      const response = await Templates.whatsapp.send(
        channelId,
        templateId,
        {
          phoneNumbers: [input.phoneNumber],
          values: {
            body: {
              otp_code: input.otp
            },
            buttons: [
              {
                sub_type: 'COPY_CODE',
                index: '0',
                coupon_code: input.otp
              }
            ]
          }
        }
      );

      return {
        success: response.totalErrors === 0,
        message: response.totalErrors === 0
          ? 'OTP sent successfully'
          : 'Failed to send OTP',
        errors: response.errors
      };
    } catch (error) {
      return {
        success: false,
        error: error instanceof Error ? error.message : 'OTP send failed'
      };
    }
  }
}
```

### Bulk Marketing Campaign

```typescript
import { LuaTool, Templates, Data } from 'lua-cli';
import { z } from 'zod';

export default class SendMarketingCampaignTool implements LuaTool {
  name = 'send_marketing_campaign';
  description = 'Send bulk marketing message to customers';

  inputSchema = z.object({
    campaignName: z.string(),
    offerText: z.string(),
    discountCode: z.string()
  });

  async execute(input: z.infer<typeof this.inputSchema>) {
    // Get opted-in customer phone numbers
    const customers = await Data.get('opted_in_customers');
    const phoneNumbers = customers
      .map(c => c.data.phoneNumber)
      .filter(Boolean);

    if (phoneNumbers.length === 0) {
      return {
        success: false,
        error: 'No opted-in customers found'
      };
    }

    const channelId = process.env.WHATSAPP_CHANNEL_ID!;
    const templateId = 'marketing_offer_template';

    try {
      // Send in batches of 50
      const batchSize = 50;
      const results = [];

      for (let i = 0; i < phoneNumbers.length; i += batchSize) {
        const batch = phoneNumbers.slice(i, i + batchSize);

        const response = await Templates.whatsapp.send(
          channelId,
          templateId,
          {
            phoneNumbers: batch,
            values: {
              body: {
                offer_text: input.offerText,
                discount_code: input.discountCode
              }
            }
          }
        );

        results.push(response);
      }

      const totalSent = results.reduce((sum, r) => sum + r.totalProcessed, 0);
      const totalErrors = results.reduce((sum, r) => sum + r.totalErrors, 0);

      // Log campaign results
      await Data.create('campaign_results', {
        campaignName: input.campaignName,
        totalRecipients: phoneNumbers.length,
        totalSent,
        totalErrors,
        sentAt: new Date().toISOString()
      });

      return {
        success: true,
        message: `Campaign sent to ${totalSent} customers`,
        totalSent,
        totalErrors,
        campaignName: input.campaignName
      };
    } catch (error) {
      return {
        success: false,
        error: error instanceof Error ? error.message : 'Campaign failed'
      };
    }
  }
}
```

### Send Appointment Reminder

```typescript
import { LuaTool, Templates } from 'lua-cli';
import { z } from 'zod';

export default class SendAppointmentReminderTool implements LuaTool {
  name = 'send_appointment_reminder';
  description = 'Send appointment reminder via WhatsApp';

  inputSchema = z.object({
    phoneNumber: z.string(),
    customerName: z.string(),
    appointmentDate: z.string(),
    appointmentTime: z.string(),
    location: z.string()
  });

  async execute(input: z.infer<typeof this.inputSchema>) {
    const channelId = process.env.WHATSAPP_CHANNEL_ID!;
    const templateId = 'appointment_reminder_template';

    try {
      const response = await Templates.whatsapp.send(
        channelId,
        templateId,
        {
          phoneNumbers: [input.phoneNumber],
          values: {
            body: {
              customer_name: input.customerName,
              appointment_date: input.appointmentDate,
              appointment_time: input.appointmentTime,
              location: input.location
            }
          }
        }
      );

      return {
        success: response.totalErrors === 0,
        message: 'Reminder sent successfully'
      };
    } catch (error) {
      return {
        success: false,
        error: error instanceof Error ? error.message : 'Send failed'
      };
    }
  }
}
```

### List and Search Templates

```typescript
import { LuaTool, Templates } from 'lua-cli';
import { z } from 'zod';

export default class ListTemplatesToolimplements LuaTool {
  name = 'list_whatsapp_templates';
  description = 'List available WhatsApp templates';

  inputSchema = z.object({
    search: z.string().optional(),
    category: z.enum(['AUTHENTICATION', 'MARKETING', 'UTILITY']).optional()
  });

  async execute(input: z.infer<typeof this.inputSchema>) {
    const channelId = process.env.WHATSAPP_CHANNEL_ID!;

    try {
      const response = await Templates.whatsapp.list(channelId, {
        search: input.search,
        limit: 50
      });

      // Filter by category if specified
      let templates = response.templates;
      if (input.category) {
        templates = templates.filter(t => t.category === input.category);
      }

      // Only show approved templates
      const approved = templates.filter(t => t.status === 'APPROVED');

      return {
        success: true,
        total: approved.length,
        templates: approved.map(t => ({
          id: t.id,
          name: t.name,
          category: t.category,
          language: t.language,
          components: t.components.length
        }))
      };
    } catch (error) {
      return {
        success: false,
        error: error instanceof Error ? error.message : 'List failed'
      };
    }
  }
}
```

## Phone Number Format

WhatsApp requires phone numbers in E.164 format:

```typescript
// ✅ Correct (E.164 format)
'+1234567890'      // US number
'+442071234567'    // UK number
'+919876543210'    // India number

// ❌ Incorrect
'1234567890'       // Missing + prefix
'(123) 456-7890'   // Formatted
'123-456-7890'     // With dashes
```

## Best Practices

### ✅ DO

- Use approved templates only (check `status === 'APPROVED'`)
- Validate phone numbers in E.164 format
- Send in batches for large recipient lists
- Track campaign results in Data API
- Handle opt-out requests properly
- Use appropriate template categories
- Test templates before bulk sending
- Include clear unsubscribe instructions for marketing
- Respect WhatsApp rate limits

### ❌ DON'T

- Don't send to numbers without consent
- Don't spam users with frequent messages
- Don't use marketing templates for transactional messages
- Don't ignore template variable requirements
- Don't send without validating template status
- Don't exceed recommended batch sizes
- Don't ignore send errors
- Don't forget to log campaign metrics

## Error Handling

```typescript
try {
  const response = await Templates.whatsapp.send(
    channelId,
    templateId,
    { phoneNumbers, values }
  );

  if (response.totalErrors > 0) {
    console.log('Some messages failed:', response.errors);
    // Handle partial failure
  }
} catch (error) {
  if (error.message.includes('template not found')) {
    console.log('Template does not exist or is not approved');
  } else if (error.message.includes('channel')) {
    console.log('Invalid channel ID');
  } else {
    console.log('Send failed:', error.message);
  }
}
```

## Common Patterns

### Validate Template Variables

```typescript
function validateTemplateVariables(
  template: WhatsAppTemplate,
  values: Record<string, string>
): boolean {
  const bodyComponent = template.components.find(c => c.type === 'BODY');
  if (!bodyComponent) return true;

  // Extract variable names from template text ({{variable_name}})
  const variables = bodyComponent.text.match(/\{\{(\w+)\}\}/g);
  if (!variables) return true;

  // Check all variables are provided
  return variables.every(v => {
    const varName = v.replace(/\{\{|\}\}/g, '');
    return values[varName] !== undefined;
  });
}
```

### Format Phone Number to E.164

```typescript
function formatToE164(phone: string, countryCode: string = '+1'): string {
  // Remove all non-digit characters
  const digits = phone.replace(/\D/g, '');

  // Add country code if not present
  if (!phone.startsWith('+')) {
    return `${countryCode}${digits}`;
  }

  return `+${digits}`;
}
```

### Batch Send with Retry

```typescript
async function sendWithRetry(
  channelId: string,
  templateId: string,
  phoneNumbers: string[],
  values: any,
  maxRetries: number = 3
): Promise<SendTemplateResponse> {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await Templates.whatsapp.send(channelId, templateId, {
        phoneNumbers,
        values
      });
    } catch (error) {
      if (attempt === maxRetries) throw error;
      // Wait before retry
      await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
    }
  }
  throw new Error('Max retries exceeded');
}
```

## Related APIs

- [User API](./User.md) - Get user phone numbers
- [Data API](./Data.md) - Store opt-in status and campaign results
- [Jobs API](./Jobs.md) - Schedule template messages

## See Also

- [WhatsApp Business API](https://developers.facebook.com/docs/whatsapp/business-management-api/message-templates)
- [Template Guidelines](https://developers.facebook.com/docs/whatsapp/message-templates/guidelines)
- [Marketing Messages Guide](../guides/MarketingMessages.md)
