···
14
+
TelnyxAPIBaseURL = "https://api.telnyx.com/v2"
15
+
SendMessagePath = "/messages"
18
+
// Client handles communication with Telnyx API
19
+
type Client struct {
21
+
messagingProfileID string
23
+
httpClient *http.Client
26
+
// NewClient creates a new Telnyx client
27
+
func NewClient(apiKey, messagingProfileID, fromNumber string) *Client {
30
+
messagingProfileID: messagingProfileID,
31
+
fromNumber: fromNumber,
32
+
httpClient: &http.Client{
33
+
Timeout: 10 * time.Second,
38
+
// SendOTP sends an OTP code via SMS
39
+
func (c *Client) SendOTP(ctx context.Context, phoneNumber, code string) error {
40
+
message := fmt.Sprintf("Your Coves verification code is: %s\n\nThis code expires in 10 minutes.", code)
42
+
req := &SendMessageRequest{
46
+
MessagingProfileID: c.messagingProfileID,
49
+
reqBody, err := json.Marshal(req)
51
+
return fmt.Errorf("failed to marshal request: %w", err)
54
+
httpReq, err := http.NewRequestWithContext(ctx, "POST", TelnyxAPIBaseURL+SendMessagePath, bytes.NewReader(reqBody))
56
+
return fmt.Errorf("failed to create request: %w", err)
59
+
httpReq.Header.Set("Authorization", "Bearer "+c.apiKey)
60
+
httpReq.Header.Set("Content-Type", "application/json")
62
+
resp, err := c.httpClient.Do(httpReq)
64
+
return fmt.Errorf("failed to send request: %w", err)
66
+
defer resp.Body.Close()
68
+
body, _ := io.ReadAll(resp.Body)
70
+
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
71
+
var telnyxErr TelnyxErrorResponse
72
+
if err := json.Unmarshal(body, &telnyxErr); err == nil && len(telnyxErr.Errors) > 0 {
73
+
return fmt.Errorf("telnyx API error: %s (code: %s)", telnyxErr.Errors[0].Detail, telnyxErr.Errors[0].Code)
75
+
return fmt.Errorf("telnyx API error: status %d, body: %s", resp.StatusCode, string(body))
78
+
var msgResp SendMessageResponse
79
+
if err := json.Unmarshal(body, &msgResp); err != nil {
80
+
return fmt.Errorf("failed to parse response: %w", err)
83
+
// Check if message was accepted
84
+
if msgResp.Data.ID == "" {
85
+
return fmt.Errorf("message not accepted by Telnyx")
91
+
// SendMessageRequest represents a Telnyx send message request
92
+
type SendMessageRequest struct {
93
+
From string `json:"from"`
94
+
To string `json:"to"`
95
+
Text string `json:"text"`
96
+
MessagingProfileID string `json:"messaging_profile_id"`
99
+
// SendMessageResponse represents a Telnyx send message response
100
+
type SendMessageResponse struct {
101
+
Data MessageData `json:"data"`
104
+
// MessageData represents message data in Telnyx response
105
+
type MessageData struct {
106
+
ID string `json:"id"`
107
+
Status string `json:"status"`
110
+
// TelnyxErrorResponse represents an error response from Telnyx
111
+
type TelnyxErrorResponse struct {
112
+
Errors []TelnyxError `json:"errors"`
115
+
// TelnyxError represents a single error from Telnyx
116
+
type TelnyxError struct {
117
+
Code string `json:"code"`
118
+
Detail string `json:"detail"`
119
+
Title string `json:"title"`