README.md

# twillio_verify

A Gleam library for sending and verifying SMS codes using the Twilio Verify API.

## Installation

Add `twillio_verify` to your `gleam.toml` dependencies:

```toml
[dependencies]
twillio_verify = { path = "../twillio_verify" }
```

## Configuration

Create a `TwilioConfig` with your Twilio credentials:

```gleam
import twillio_verify.{TwilioConfig}

let config = TwilioConfig(
  account_sid: "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  auth_token: "your_auth_token",
  service_sid: "VAxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
)
```

You can find these values in your [Twilio Console](https://console.twilio.com/):
- **Account SID** and **Auth Token**: Found on the main dashboard
- **Service SID**: Create a Verify Service under Verify > Services

## Usage

### Sending a Verification Code

```gleam
import gleam/httpc
import twillio_verify.{TwilioConfig, Sms}

let config = TwilioConfig(
  account_sid: "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  auth_token: "your_auth_token",
  service_sid: "VAxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
)

// Build the request
let request = twillio_verify.send_verification_request(config, "+1234567890", Sms)

// Send with your HTTP client
let assert Ok(response) = httpc.send(request)

// Parse the response
case twillio_verify.send_verification_response(response) {
  Ok(verification) -> {
    io.println("Verification sent! SID: " <> verification.sid)
    io.println("Status: " <> string.inspect(verification.status))
  }
  Error(error) -> {
    io.println("Error: " <> string.inspect(error))
  }
}
```

### Checking a Verification Code

```gleam
import gleam/httpc
import twillio_verify.{TwilioConfig}

let config = TwilioConfig(
  account_sid: "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  auth_token: "your_auth_token",
  service_sid: "VAxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
)

// Build the request
let request = twillio_verify.check_verification_request(config, "+1234567890", "123456")

// Send with your HTTP client
let assert Ok(response) = httpc.send(request)

// Parse the response
case twillio_verify.check_verification_response(response) {
  Ok(verification) -> {
    case twillio_verify.is_approved(verification) {
      True -> io.println("Code verified successfully!")
      False -> io.println("Invalid code")
    }
  }
  Error(error) -> {
    io.println("Error: " <> string.inspect(error))
  }
}
```

### Available Channels

```gleam
import twillio_verify.{Sms, Call, Email, Whatsapp}

// Send via SMS
twillio_verify.send_verification_request(config, "+1234567890", Sms)

// Send via phone call
twillio_verify.send_verification_request(config, "+1234567890", Call)

// Send via email
twillio_verify.send_verification_request(config, "user@example.com", Email)

// Send via WhatsApp
twillio_verify.send_verification_request(config, "+1234567890", Whatsapp)
```

## Response Types

### SendVerificationResponse / CheckVerificationResponse

Both response types include:

| Field | Type | Description |
|-------|------|-------------|
| `sid` | `String` | Unique identifier for this verification |
| `account_sid` | `String` | Your Twilio Account SID |
| `service_sid` | `String` | The Verify Service SID |
| `to` | `String` | The phone number or email |
| `channel` | `String` | Channel used (sms, call, email, whatsapp) |
| `status` | `VerificationStatus` | Current status (Pending, Approved, Canceled) |
| `valid` | `Bool` | Whether the verification is valid |
| `amount` | `Option(String)` | Amount for PSD2 verifications |
| `payee` | `Option(String)` | Payee for PSD2 verifications |
| `date_created` | `String` | ISO 8601 creation timestamp |
| `date_updated` | `String` | ISO 8601 update timestamp |
| `lookup` | `Lookup` | Carrier lookup information |
| `send_code_attempts` | `List(SendCodeAttempt)` | List of send attempts |
| `url` | `String` | API URL for this verification |

## Error Handling

The library returns `TwilioError` for failures:

```gleam
case twillio_verify.send_verification_response(response) {
  Ok(verification) -> // handle success
  Error(twillio_verify.TwilioApiError(code, message, more_info)) -> {
    // Twilio API error (e.g., invalid phone number)
    io.println("Twilio error " <> int.to_string(code) <> ": " <> message)
  }
  Error(twillio_verify.UnexpectedResponseError(status, body)) -> {
    // Unexpected HTTP response
    io.println("HTTP " <> int.to_string(status) <> ": " <> body)
  }
  Error(twillio_verify.DecodeError(reason)) -> {
    // JSON decode failure
    io.println("Decode error: " <> reason)
  }
}
```

## License

MIT