---
name: api-patterns
description: Resend API integration patterns, authentication, error handling, and rate limiting. Use when implementing API clients, handling authentication, managing rate limits, implementing retry strategies, or building resilient email service integrations.
allowed-tools: Read, Write, Bash, Grep
---

# API Patterns Skill

Comprehensive patterns and best practices for integrating with the Resend API, covering authentication, rate limiting, error handling, and resilient retry strategies.

## Use When

- Implementing Resend API clients in TypeScript/JavaScript
- Building Python-based email service integrations
- Handling API authentication and Bearer tokens
- Managing rate limits (2 requests/second default)
- Implementing exponential backoff retry logic
- Processing API error responses (4xx/5xx codes)
- Building resilient API integrations with error recovery
- Validating API responses and handling edge cases

## Core Patterns

### 1. API Authentication

**Bearer token authentication** for all Resend API requests:

#### TypeScript/JavaScript

```typescript
import { Resend } from 'resend';

// Initialize with API key from environment
const resend = new Resend(process.env.RESEND_API_KEY);

// Or with explicit initialization
const apiKey = process.env.RESEND_API_KEY;
if (!apiKey) {
  throw new Error('RESEND_API_KEY environment variable is not set');
}

const resend = new Resend(apiKey);

// For custom HTTP requests (if needed)
async function makeAuthenticatedRequest(endpoint: string, body: any) {
  const response = await fetch(`https://api.resend.com/${endpoint}`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.RESEND_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(body),
  });

  return response.json();
}
```

#### Python

```python
import os
from resend import Resend

# Initialize with API key from environment
api_key = os.environ.get("RESEND_API_KEY")
if not api_key:
    raise ValueError("RESEND_API_KEY environment variable is not set")

client = Resend(api_key=api_key)

# For custom HTTP requests (if needed)
import httpx

async def make_authenticated_request(endpoint: str, body: dict):
    async with httpx.AsyncClient() as client:
        response = await client.post(
            f"https://api.resend.com/{endpoint}",
            headers={
                "Authorization": f"Bearer {api_key}",
                "Content-Type": "application/json",
            },
            json=body,
        )
        return response.json()
```

### 2. Rate Limiting Handling

**Resend API rate limits**: 2 requests per second per account

#### TypeScript Implementation

```typescript
class ResendAPIClient {
  private requestQueue: Array<() => Promise<any>> = [];
  private isProcessing = false;
  private readonly requestsPerSecond = 2;
  private lastRequestTime = 0;

  async executeWithRateLimit<T>(fn: () => Promise<T>): Promise<T> {
    return new Promise((resolve, reject) => {
      this.requestQueue.push(async () => {
        try {
          const result = await fn();
          resolve(result);
        } catch (error) {
          reject(error);
        }
      });

      this.processQueue();
    });
  }

  private async processQueue() {
    if (this.isProcessing || this.requestQueue.length === 0) {
      return;
    }

    this.isProcessing = true;

    while (this.requestQueue.length > 0) {
      const now = Date.now();
      const timeSinceLastRequest = now - this.lastRequestTime;
      const delayNeeded = (1000 / this.requestsPerSecond) - timeSinceLastRequest;

      if (delayNeeded > 0) {
        await new Promise(resolve => setTimeout(resolve, delayNeeded));
      }

      const request = this.requestQueue.shift();
      if (request) {
        await request();
        this.lastRequestTime = Date.now();
      }
    }

    this.isProcessing = false;
  }

  async sendEmail(payload: any) {
    return this.executeWithRateLimit(() =>
      resend.emails.send(payload)
    );
  }

  async sendBatch(emails: any[]) {
    return this.executeWithRateLimit(() =>
      resend.batch.send(emails)
    );
  }
}
```

#### Python Implementation

```python
import asyncio
import time
from typing import TypeVar, Callable, Coroutine, Any

T = TypeVar('T')

class ResendAPIClient:
    def __init__(self, api_key: str, requests_per_second: int = 2):
        self.client = Resend(api_key=api_key)
        self.request_queue = asyncio.Queue()
        self.is_processing = False
        self.requests_per_second = requests_per_second
        self.last_request_time = 0

    async def execute_with_rate_limit(
        self,
        fn: Callable[[], Coroutine[Any, Any, T]]
    ) -> T:
        await self.request_queue.put(fn)
        asyncio.create_task(self.process_queue())

        # Wait for result (simplified - in production use proper queuing)
        return await fn()

    async def process_queue(self):
        if self.is_processing or self.request_queue.empty():
            return

        self.is_processing = True

        while not self.request_queue.empty():
            now = time.time()
            time_since_last = now - self.last_request_time
            delay_needed = (1.0 / self.requests_per_second) - time_since_last

            if delay_needed > 0:
                await asyncio.sleep(delay_needed)

            try:
                fn = self.request_queue.get_nowait()
                await fn()
                self.last_request_time = time.time()
            except asyncio.QueueEmpty:
                break

        self.is_processing = False

    async def send_email(self, payload: dict):
        async def send():
            return self.client.emails.send(payload)

        return await self.execute_with_rate_limit(send)
```

### 3. Error Response Codes

**HTTP status codes and error handling**:

| Code | Error | Handling Strategy |
|------|-------|-------------------|
| 200 | Success | Process response normally |
| 400 | Bad Request | Validate request payload, check required fields |
| 401 | Unauthorized | Verify API key is correct and valid |
| 403 | Forbidden | Check API key has required permissions |
| 404 | Not Found | Verify resource ID/email address exists |
| 409 | Conflict | Handle duplicate resource creation attempts |
| 429 | Rate Limited | Implement exponential backoff retry |
| 500 | Server Error | Retry with exponential backoff |
| 502 | Bad Gateway | Retry with exponential backoff |
| 503 | Service Unavailable | Retry with exponential backoff |

#### TypeScript Error Handler

```typescript
interface APIError {
  code: number;
  message: string;
  statusText: string;
}

async function handleAPIError(error: any): Promise<void> {
  if (error.response) {
    const status = error.response.status;
    const data = error.response.data;

    switch (status) {
      case 400:
        console.error('Bad Request:', data.message);
        throw new Error(`Invalid request: ${data.message}`);

      case 401:
        console.error('Unauthorized: Check API key');
        throw new Error('Invalid API key. Set RESEND_API_KEY environment variable.');

      case 403:
        console.error('Forbidden: Insufficient permissions');
        throw new Error('API key lacks required permissions.');

      case 404:
        console.error('Not Found:', data.message);
        throw new Error(`Resource not found: ${data.message}`);

      case 409:
        console.error('Conflict: Resource already exists');
        throw new Error(`Duplicate resource: ${data.message}`);

      case 429:
        console.warn('Rate limited: Implement retry');
        throw new Error('Rate limit exceeded. Retry after delay.');

      case 500:
      case 502:
      case 503:
        console.error(`Server error (${status}): Retry recommended`);
        throw new Error(`Server error (${status}). Retry in progress...`);

      default:
        console.error(`Unknown error (${status}):`, data);
        throw new Error(`API error: ${data.message || 'Unknown error'}`);
    }
  }

  throw error;
}
```

#### Python Error Handler

```python
import logging
from typing import Optional, Dict, Any

logger = logging.getLogger(__name__)

class ResendAPIError(Exception):
    """Base exception for Resend API errors"""
    pass

class AuthenticationError(ResendAPIError):
    """API authentication failed"""
    pass

class RateLimitError(ResendAPIError):
    """Rate limit exceeded"""
    pass

class ServerError(ResendAPIError):
    """Server-side error"""
    pass

def handle_api_error(error: Exception, status_code: Optional[int] = None) -> None:
    """Handle Resend API errors based on status code"""

    if status_code == 400:
        logger.error(f"Bad Request: {str(error)}")
        raise ResendAPIError(f"Invalid request: {str(error)}")

    elif status_code == 401:
        logger.error("Unauthorized: Check API key")
        raise AuthenticationError(
            "Invalid API key. Set RESEND_API_KEY environment variable."
        )

    elif status_code == 403:
        logger.error("Forbidden: Insufficient permissions")
        raise AuthenticationError("API key lacks required permissions.")

    elif status_code == 404:
        logger.error(f"Not Found: {str(error)}")
        raise ResendAPIError(f"Resource not found: {str(error)}")

    elif status_code == 409:
        logger.error("Conflict: Resource already exists")
        raise ResendAPIError(f"Duplicate resource: {str(error)}")

    elif status_code == 429:
        logger.warning("Rate limited: Implement retry")
        raise RateLimitError("Rate limit exceeded. Retry after delay.")

    elif status_code in [500, 502, 503]:
        logger.error(f"Server error ({status_code}): Retry recommended")
        raise ServerError(f"Server error ({status_code}). Retry in progress...")

    else:
        logger.error(f"Unknown error: {str(error)}")
        raise ResendAPIError(f"API error: {str(error)}")
```

### 4. Exponential Backoff Retry Strategy

**Resilient retry logic** with exponential backoff for transient failures:

#### TypeScript Implementation

```typescript
interface RetryOptions {
  maxRetries?: number;
  initialDelayMs?: number;
  maxDelayMs?: number;
  backoffMultiplier?: number;
  retryableStatusCodes?: number[];
}

const DEFAULT_RETRY_OPTIONS: Required<RetryOptions> = {
  maxRetries: 5,
  initialDelayMs: 100,
  maxDelayMs: 30000,
  backoffMultiplier: 2,
  retryableStatusCodes: [408, 429, 500, 502, 503, 504],
};

async function withExponentialBackoff<T>(
  fn: () => Promise<T>,
  options: RetryOptions = {}
): Promise<T> {
  const config = { ...DEFAULT_RETRY_OPTIONS, ...options };
  let lastError: Error | null = null;
  let delayMs = config.initialDelayMs;

  for (let attempt = 0; attempt <= config.maxRetries; attempt++) {
    try {
      return await fn();
    } catch (error: any) {
      lastError = error;

      // Check if error is retryable
      const isRetryable =
        (error.response?.status &&
         config.retryableStatusCodes.includes(error.response.status)) ||
        error.code === 'ECONNREFUSED' ||
        error.code === 'ETIMEDOUT';

      if (!isRetryable || attempt === config.maxRetries) {
        throw error;
      }

      // Calculate delay with jitter
      const jitter = Math.random() * 0.1 * delayMs;
      const actualDelay = Math.min(delayMs + jitter, config.maxDelayMs);

      console.warn(
        `Attempt ${attempt + 1} failed. Retrying in ${actualDelay.toFixed(0)}ms...`,
        error.message
      );

      await new Promise(resolve => setTimeout(resolve, actualDelay));
      delayMs = Math.min(delayMs * config.backoffMultiplier, config.maxDelayMs);
    }
  }

  throw lastError || new Error('Retry loop exhausted');
}

// Usage
async function sendEmailWithRetry(payload: any) {
  return withExponentialBackoff(
    () => resend.emails.send(payload),
    {
      maxRetries: 5,
      initialDelayMs: 100,
      maxDelayMs: 10000,
      backoffMultiplier: 2,
    }
  );
}
```

#### Python Implementation

```python
import asyncio
import random
import logging
from typing import TypeVar, Callable, Coroutine, Optional, List
from enum import Enum

logger = logging.getLogger(__name__)
T = TypeVar('T')

class RetryStrategy(Enum):
    EXPONENTIAL = "exponential"
    LINEAR = "linear"

async def with_exponential_backoff(
    fn: Callable[[], Coroutine],
    max_retries: int = 5,
    initial_delay_ms: float = 100,
    max_delay_ms: float = 30000,
    backoff_multiplier: float = 2,
    retryable_status_codes: Optional[List[int]] = None,
) -> T:
    """
    Execute async function with exponential backoff retry

    Args:
        fn: Async function to execute
        max_retries: Maximum retry attempts
        initial_delay_ms: Initial delay in milliseconds
        max_delay_ms: Maximum delay in milliseconds
        backoff_multiplier: Multiplier for each retry
        retryable_status_codes: HTTP status codes to retry on

    Returns:
        Result from function call

    Raises:
        Exception: If all retries exhausted
    """
    if retryable_status_codes is None:
        retryable_status_codes = [408, 429, 500, 502, 503, 504]

    last_error = None
    delay_ms = initial_delay_ms

    for attempt in range(max_retries + 1):
        try:
            return await fn()
        except Exception as error:
            last_error = error

            # Check if error is retryable
            is_retryable = (
                (hasattr(error, 'status_code') and
                 error.status_code in retryable_status_codes) or
                'timeout' in str(error).lower() or
                'connection' in str(error).lower()
            )

            if not is_retryable or attempt == max_retries:
                raise error

            # Calculate delay with jitter
            jitter = random.random() * 0.1 * delay_ms
            actual_delay = min(delay_ms + jitter, max_delay_ms)

            logger.warning(
                f"Attempt {attempt + 1} failed. "
                f"Retrying in {actual_delay:.0f}ms... Error: {str(error)}"
            )

            await asyncio.sleep(actual_delay / 1000)
            delay_ms = min(delay_ms * backoff_multiplier, max_delay_ms)

    if last_error:
        raise last_error
    raise Exception("Retry loop exhausted")
```

### 5. Request Validation

**Validate payloads before sending** to catch errors early:

#### TypeScript Validator

```typescript
interface EmailPayload {
  from: string;
  to: string | string[];
  subject: string;
  html?: string;
  text?: string;
  cc?: string[];
  bcc?: string[];
  reply_to?: string;
  attachments?: Array<{ filename: string; content: Buffer | string }>;
  scheduled_at?: string;
  tags?: Array<{ name: string; value: string }>;
}

function validateEmailPayload(payload: any): { valid: boolean; errors: string[] } {
  const errors: string[] = [];

  // Check required fields
  if (!payload.from) {
    errors.push("'from' field is required");
  }
  if (!payload.to) {
    errors.push("'to' field is required");
  }
  if (!payload.subject) {
    errors.push("'subject' field is required");
  }

  // Validate email addresses
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

  if (payload.from && !emailRegex.test(payload.from)) {
    errors.push(`Invalid 'from' email: ${payload.from}`);
  }

  const recipients = Array.isArray(payload.to) ? payload.to : [payload.to];
  recipients.forEach((email: string) => {
    if (!emailRegex.test(email)) {
      errors.push(`Invalid recipient email: ${email}`);
    }
  });

  // Validate optional email fields
  if (payload.reply_to && !emailRegex.test(payload.reply_to)) {
    errors.push(`Invalid 'reply_to' email: ${payload.reply_to}`);
  }

  if (payload.cc) {
    payload.cc.forEach((email: string) => {
      if (!emailRegex.test(email)) {
        errors.push(`Invalid 'cc' email: ${email}`);
      }
    });
  }

  if (payload.bcc) {
    payload.bcc.forEach((email: string) => {
      if (!emailRegex.test(email)) {
        errors.push(`Invalid 'bcc' email: ${email}`);
      }
    });
  }

  // Validate attachment content
  if (payload.attachments) {
    payload.attachments.forEach((att: any, index: number) => {
      if (!att.filename) {
        errors.push(`Attachment ${index} missing 'filename'`);
      }
      if (!att.content) {
        errors.push(`Attachment ${index} missing 'content'`);
      }
    });
  }

  // Validate scheduled_at format if present
  if (payload.scheduled_at) {
    try {
      new Date(payload.scheduled_at);
    } catch {
      errors.push(`Invalid 'scheduled_at' format: ${payload.scheduled_at}`);
    }
  }

  return {
    valid: errors.length === 0,
    errors,
  };
}

// Usage
async function sendEmailSafely(payload: EmailPayload) {
  const validation = validateEmailPayload(payload);

  if (!validation.valid) {
    console.error('Validation errors:', validation.errors);
    throw new Error(`Payload validation failed: ${validation.errors.join(', ')}`);
  }

  return resend.emails.send(payload);
}
```

#### Python Validator

```python
import re
from typing import Dict, List, Any, Tuple
from datetime import datetime

class EmailPayloadValidator:
    EMAIL_REGEX = r'^[^\s@]+@[^\s@]+\.[^\s@]+$'

    @staticmethod
    def validate_email(email: str) -> bool:
        """Validate email address format"""
        return re.match(EmailPayloadValidator.EMAIL_REGEX, email) is not None

    @staticmethod
    def validate_payload(payload: Dict[str, Any]) -> Tuple[bool, List[str]]:
        """
        Validate email payload before sending

        Returns:
            Tuple of (is_valid, error_list)
        """
        errors = []

        # Check required fields
        if not payload.get('from'):
            errors.append("'from' field is required")
        if not payload.get('to'):
            errors.append("'to' field is required")
        if not payload.get('subject'):
            errors.append("'subject' field is required")

        # Validate email addresses
        if payload.get('from'):
            if not EmailPayloadValidator.validate_email(payload['from']):
                errors.append(f"Invalid 'from' email: {payload['from']}")

        # Validate recipients
        recipients = payload.get('to', [])
        if isinstance(recipients, str):
            recipients = [recipients]

        for email in recipients:
            if not EmailPayloadValidator.validate_email(email):
                errors.append(f"Invalid recipient email: {email}")

        # Validate optional email fields
        if payload.get('reply_to'):
            if not EmailPayloadValidator.validate_email(payload['reply_to']):
                errors.append(f"Invalid 'reply_to' email: {payload['reply_to']}")

        for cc_email in payload.get('cc', []):
            if not EmailPayloadValidator.validate_email(cc_email):
                errors.append(f"Invalid 'cc' email: {cc_email}")

        for bcc_email in payload.get('bcc', []):
            if not EmailPayloadValidator.validate_email(bcc_email):
                errors.append(f"Invalid 'bcc' email: {bcc_email}")

        # Validate attachments
        for i, attachment in enumerate(payload.get('attachments', [])):
            if not attachment.get('filename'):
                errors.append(f"Attachment {i} missing 'filename'")
            if not attachment.get('content'):
                errors.append(f"Attachment {i} missing 'content'")

        # Validate scheduled_at format
        if payload.get('scheduled_at'):
            try:
                datetime.fromisoformat(
                    payload['scheduled_at'].replace('Z', '+00:00')
                )
            except ValueError:
                errors.append(f"Invalid 'scheduled_at' format: {payload['scheduled_at']}")

        return len(errors) == 0, errors

def send_email_safely(client, payload: Dict[str, Any]):
    """Send email with validation"""
    is_valid, errors = EmailPayloadValidator.validate_payload(payload)

    if not is_valid:
        raise ValueError(f"Payload validation failed: {', '.join(errors)}")

    return client.emails.send(payload)
```

## Environment Setup

### Required Environment Variables

```bash
# .env
RESEND_API_KEY=your_resend_api_key_here
```

### .env.example (Safe to Commit)

```bash
# Resend API Configuration
RESEND_API_KEY=your_resend_api_key_here

# Optional: Custom request timeout (ms)
RESEND_REQUEST_TIMEOUT=30000

# Optional: Max retries for transient failures
RESEND_MAX_RETRIES=5

# Optional: Rate limit requests per second
RESEND_RATE_LIMIT=2
```

### Installation

#### TypeScript/JavaScript

```bash
npm install resend
# or
yarn add resend
# or
pnpm add resend
```

#### Python

```bash
pip install resend
```

## Best Practices

### 1. Always Use Environment Variables

```typescript
// CORRECT
const apiKey = process.env.RESEND_API_KEY;

// WRONG - Never hardcode
const apiKey = 're_abc123xyz...';
```

### 2. Implement Graceful Degradation

```typescript
async function sendEmailWithFallback(payload: EmailPayload) {
  try {
    return await resend.emails.send(payload);
  } catch (error) {
    // Log error for monitoring
    console.error('Email send failed:', error);

    // Implement fallback behavior
    // - Queue for retry
    // - Alert administrator
    // - Use alternative service

    throw error;
  }
}
```

### 3. Monitor API Usage

```typescript
interface APIMetrics {
  successCount: number;
  failureCount: number;
  rateLimitHits: number;
  averageResponseTime: number;
}

class APIMonitor {
  private metrics: APIMetrics = {
    successCount: 0,
    failureCount: 0,
    rateLimitHits: 0,
    averageResponseTime: 0,
  };

  recordSuccess(duration: number) {
    this.metrics.successCount++;
    this.updateAverageResponseTime(duration);
  }

  recordFailure(error: any) {
    this.metrics.failureCount++;
    if (error?.response?.status === 429) {
      this.metrics.rateLimitHits++;
    }
  }

  private updateAverageResponseTime(duration: number) {
    const totalRequests = this.metrics.successCount + this.metrics.failureCount;
    const currentAvg = this.metrics.averageResponseTime;
    this.metrics.averageResponseTime =
      (currentAvg * (totalRequests - 1) + duration) / totalRequests;
  }

  getMetrics(): APIMetrics {
    return { ...this.metrics };
  }
}
```

### 4. Implement Circuit Breaker Pattern

```typescript
enum CircuitState {
  CLOSED = 'CLOSED',
  OPEN = 'OPEN',
  HALF_OPEN = 'HALF_OPEN',
}

class CircuitBreaker {
  private state: CircuitState = CircuitState.CLOSED;
  private failureCount = 0;
  private failureThreshold = 5;
  private resetTimeout = 60000; // 1 minute
  private lastFailureTime = 0;

  async execute<T>(fn: () => Promise<T>): Promise<T> {
    if (this.state === CircuitState.OPEN) {
      if (Date.now() - this.lastFailureTime > this.resetTimeout) {
        this.state = CircuitState.HALF_OPEN;
      } else {
        throw new Error('Circuit breaker is OPEN');
      }
    }

    try {
      const result = await fn();
      this.onSuccess();
      return result;
    } catch (error) {
      this.onFailure();
      throw error;
    }
  }

  private onSuccess() {
    this.failureCount = 0;
    this.state = CircuitState.CLOSED;
  }

  private onFailure() {
    this.failureCount++;
    this.lastFailureTime = Date.now();
    if (this.failureCount >= this.failureThreshold) {
      this.state = CircuitState.OPEN;
    }
  }
}
```

## Examples Directory Structure

- `typescript-client/` - Complete TypeScript client setup with authentication
- `python-client/` - Complete Python client setup with authentication
- `error-handling/` - Comprehensive error handling and recovery patterns

See individual example README files for complete code and usage patterns.

## Related Skills

- **email-delivery** - Email sending patterns (single, batch, scheduled)
- **email-templates** - HTML template management and rendering
- **email-webhooks** - Delivery event tracking and status handling

## Security Compliance

This skill follows strict security rules:
- All code examples use placeholder values only
- No real API keys, passwords, or secrets
- Environment variable references in all code
- `.gitignore` protection documented
- Clear guidance on key acquisition

## Resources

- [Resend API Documentation](https://resend.com/docs)
- [Resend API Reference](https://resend.com/docs/api-reference)
- [Authentication Best Practices](https://resend.com/docs/knowledge-base/authentication)
- [Rate Limiting Guide](https://resend.com/docs/knowledge-base/rate-limiting)
- [HTTP Status Codes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status)


---
Source attribution: David-Li0406
Original project: https://github.com/David-Li0406/meta-skill-evloving/blob/ca3a335628981df10c36e00cb9850df2c247ab9a/skill-flow/data/skills-refined-36k/skillsmp/api-patterns-3/SKILL.md
License: Apache-2.0
License information: https://www.apache.org/licenses/LICENSE-2.0
Original upstream instructions; downloaded from Dave AI.

## Upstream license notice

Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.



# Dave AI resource metadata

Creator / publisher: David-Li0406
Original project: https://github.com/David-Li0406/meta-skill-evloving/blob/ca3a335628981df10c36e00cb9850df2c247ab9a/skill-flow/data/skills-refined-36k/skillsmp/api-patterns-3/SKILL.md
Attribution basis: Source repository record

Fields of work: Development & Engineering, Marketing, Product Management
Roles: Backend Developer, Data Engineer, Email Marketer, Growth Marketer, Product Manager
Specialties: API, Backend, Cross Platform
Tools: Resend
Country applicability: Country not specified
Classification basis: Source catalog labels
Instruction SHA-256: ddce495db7c5b245f5bfc79ebbf04a6bd2cdaab99809fe9aebdafe6957477607
