Installation
go get github.com/team-telnyx/telnyx-go
Setup
import (
"context"
"fmt"
"os"
"github.com/team-telnyx/telnyx-go"
"github.com/team-telnyx/telnyx-go/option"
)
client := telnyx.NewClient(option.WithAPIKey(os.Getenv("TELNYX_API_KEY")))
All examples below assume `client` is already initialized as shown above.
## Error Handling
All API calls can fail with network errors, rate limits (429), validation errors (422),
or authentication errors (401). Always handle errors in production code:
```go
ctx := context.TODO()
response, err := client.Messages.SendWhatsapp(ctx, telnyx.MessageSendWhatsappParams{
From: telnyx.String("+19452940762"),
To: telnyx.String("+18005551234"),
Type: telnyx.F(telnyx.MessageSendWhatsappParamsTypeWhatsapp),
WhatsappMessage: telnyx.F(telnyx.MessageSendWhatsappParamsWhatsappMessage{
Type: telnyx.F("text"),
Text: telnyx.F(map[string]interface{}{
"body": "Hello from Telnyx!",
}),
}),
})
if err != nil {
var apiErr *telnyx.Error
if errors.As(err, &apiErr) {
fmt.Printf("API error: %d - %s\n", apiErr.StatusCode, apiErr.Message)
}
return err
}
fmt.Println(response.Data.ID)
Common error codes: 401 invalid API key, 403 insufficient permissions,
404 resource not found, 422 validation error (check field formats),
429 rate limited (retry with exponential backoff).
WhatsApp-Specific Errors
- 40008 — Meta catch-all error. Check template parameters, phone number formatting, and 24-hour window rules.
- 131047 — Message failed to send during the 24-hour window. The customer hasn't messaged you first (for non-template messages).
- 131026 — Recipient phone number is not a WhatsApp user.
- 132000 — Template parameter count mismatch. Ensure the number of parameters matches the template definition.
- 132015 — Template paused or disabled by Meta due to quality issues.
Important Notes
- Phone numbers must be in E.164 format (e.g.,
+13125550001). Include the+prefix and country code. - Template messages can be sent anytime. Free-form (session) messages can only be sent within a 24-hour window after the customer last messaged you.
- Template IDs: You can reference templates by Telnyx UUID (
template_id) instead ofname+language. Whentemplate_idis provided, name and language are resolved automatically. - Pagination: List endpoints return paginated results. Use the auto-paging iterator:
iter.Next()in a loop.
Operational Caveats
- The sending phone number must be registered with a WhatsApp Business Account (WABA) and associated with a messaging profile.
- Templates must be in
APPROVEDstatus before they can be used for sending. - Template names must be lowercase with underscores only (e.g.,
order_confirmation). No spaces, hyphens, or uppercase. - When creating templates, provide realistic sample values for body parameters — Meta reviewers check these during approval.
- Category selection matters for billing:
AUTHENTICATIONtemplates get special pricing but must contain an OTP.UTILITYis for transactional messages.MARKETINGfor promotional content. - Meta may reclassify your template category (e.g., UTILITY to MARKETING) which affects billing.
Reference Use Rules
Do not invent Telnyx parameters, enums, response fields, or webhook fields.
- If the parameter, enum, or response field you need is not shown inline in this skill, read references/api-details.md before writing code.
- Before using any operation in
## Additional Operations, read the optional-parameters section and the response-schemas section. - Before reading or matching webhook fields beyond the inline examples, read the webhook payload reference.
Core Tasks
Send a WhatsApp template message
Send a pre-approved template message. Templates can be sent anytime — no 24-hour window restriction.
client.Messages.SendWhatsapp() — POST /messages/whatsapp
| Parameter | Type | Required | Description |
|---|---|---|---|
From |
string (E.164) | Yes | WhatsApp-enabled phone number in +E.164 format |
To |
string (E.164) | Yes | Recipient phone number in +E.164 format |
Type |
string | No | Must be WHATSAPP |
WhatsappMessage |
object | Yes | WhatsApp message object |
MessagingProfileID |
string (UUID) | No | Messaging profile to use |
WebhookURL |
string (URL) | No | Callback URL for delivery status updates |
// Send by template name + language
ctx := context.TODO()
response, err := client.Messages.SendWhatsapp(ctx, telnyx.MessageSendWhatsappParams{
From: telnyx.String("+19452940762"),
To: telnyx.String("+18005551234"),
Type: telnyx.F(telnyx.MessageSendWhatsappParamsTypeWhatsapp),
WhatsappMessage: telnyx.F(telnyx.MessageSendWhatsappParamsWhatsappMessage{
Type: telnyx.F("template"),
Template: telnyx.F(telnyx.MessageSendWhatsappParamsWhatsappMessageTemplate{
Name: telnyx.String("order_confirmation"),
Language: telnyx.F(telnyx.MessageSendWhatsappParamsWhatsappMessageTemplateLanguage{
Code: telnyx.String("en_US"),
}),
Components: telnyx.F([]telnyx.MessageSendWhatsappParamsWhatsappMessageTemplateComponent{
{
Type: telnyx.F("body"),
Parameters: telnyx.F([]telnyx.MessageSendWhatsappParamsWhatsappMessageTemplateComponentParameter{
{Type: telnyx.F("text"), Text: telnyx.String("ORD-12345")},
{Type: telnyx.F("text"), Text: telnyx.String("March 15, 2026")},
}),
},
}),
}),
}),
})
if err != nil {
log.Fatal(err)
}
fmt.Println(response.Data.ID)
// Send by Telnyx template_id (no name/language needed)
ctx := context.TODO()
response, err := client.Messages.SendWhatsapp(ctx, telnyx.MessageSendWhatsappParams{
From: telnyx.String("+19452940762"),
To: telnyx.String("+18005551234"),
Type: telnyx.F(telnyx.MessageSendWhatsappParamsTypeWhatsapp),
WhatsappMessage: telnyx.F(telnyx.MessageSendWhatsappParamsWhatsappMessage{
Type: telnyx.F("template"),
Template: telnyx.F(telnyx.MessageSendWhatsappParamsWhatsappMessageTemplate{
TemplateID: telnyx.String("019cd44b-3a1c-781b-956e-bd33e9fd2ac6"),
Components: telnyx.F([]telnyx.MessageSendWhatsappParamsWhatsappMessageTemplateComponent{
{
Type: telnyx.F("body"),
Parameters: telnyx.F([]telnyx.MessageSendWhatsappParamsWhatsappMessageTemplateComponentParameter{
{Type: telnyx.F("text"), Text: telnyx.String("483291")},
}),
},
}),
}),
}),
})
if err != nil {
log.Fatal(err)
}
fmt.Println(response.Data.ID)
Primary response fields:
response.Data.ID— Message UUIDresponse.Data.To[0].Status—queued,sent,delivered,failedresponse.Data.From.PhoneNumberresponse.Data.Type—WHATSAPP
Send a free-form WhatsApp text message
Send a text message within the 24-hour customer service window.
client.Messages.SendWhatsapp() — POST /messages/whatsapp
ctx := context.TODO()
response, err := client.Messages.SendWhatsapp(ctx, telnyx.MessageSendWhatsappParams{
From: telnyx.String("+19452940762"),
To: telnyx.String("+18005551234"),
Type: telnyx.F(telnyx.MessageSendWhatsappParamsTypeWhatsapp),
WhatsappMessage: telnyx.F(telnyx.MessageSendWhatsappParamsWhatsappMessage{
Type: telnyx.F("text"),
Text: telnyx.F(map[string]interface{}{
"body": "Your order has shipped!",
}),
}),
})
if err != nil {
log.Fatal(err)
}
fmt.Println(response.Data.ID)
List WhatsApp Business Accounts
client.Whatsapp.BusinessAccounts.List() — GET /v2/whatsapp/business_accounts
ctx := context.TODO()
response, err := client.Whatsapp.BusinessAccounts.List(ctx, telnyx.WhatsappBusinessAccountListParams{})
if err != nil {
log.Fatal(err)
}
for _, waba := range response.Data {
fmt.Printf("%s: %s (%s)\n", waba.ID, waba.Name, waba.Status)
}
Primary response fields:
waba.ID— Telnyx WABA UUIDwaba.WabaID— Meta WABA IDwaba.Name— Business namewaba.Status— Account statuswaba.Country— WABA country
List templates for a WABA
client.Whatsapp.Templates.List() — GET /v2/whatsapp/message_templates
| Parameter | Type | Required | Description |
|---|---|---|---|
WabaID |
string (UUID) | Yes | Telnyx WABA UUID |
Category |
string | No | Filter: AUTHENTICATION, MARKETING, UTILITY |
Status |
string | No | Filter: APPROVED, PENDING, REJECTED, DISABLED |
ctx := context.TODO()
response, err := client.Whatsapp.Templates.List(ctx,
telnyx.WhatsappTemplateListParams{
WabaID: telnyx.String("019c1ff0-5c30-7f36-8436-730b1d0b0e56"),
Status: telnyx.String("APPROVED"),
},
)
if err != nil {
log.Fatal(err)
}
for _, tmpl := range response.Data {
fmt.Printf("%s: %s (%s) - %s\n", tmpl.ID, tmpl.Name, tmpl.Category, tmpl.Status)
}
Primary response fields:
tmpl.ID— Telnyx template UUID (use astemplate_idwhen sending)tmpl.Name— Template nametmpl.Category—AUTHENTICATION,MARKETING, orUTILITYtmpl.Language— Language codetmpl.Status—APPROVED,PENDING,REJECTED,DISABLEDtmpl.Components— Template components
Create a message template
client.Whatsapp.Templates.Create() — POST /v2/whatsapp/message_templates
ctx := context.TODO()
response, err := client.Whatsapp.Templates.Create(ctx,
telnyx.WhatsappTemplateCreateParams{
WabaID: telnyx.String("019c1ff0-5c30-7f36-8436-730b1d0b0e56"),
Name: telnyx.String("order_shipped"),
Category: telnyx.String("UTILITY"),
Language: telnyx.String("en_US"),
Components: telnyx.F([]telnyx.WhatsappTemplateCreateParamsComponent{
{
Type: telnyx.F("BODY"),
Text: telnyx.String("Your order {{1}} has been shipped and will arrive by {{2}}."),
Example: telnyx.F(telnyx.WhatsappTemplateCreateParamsComponentExample{
BodyText: telnyx.F([][]string{{"ORD-12345", "March 20, 2026"}}),
}),
},
}),
},
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Template created: %s (status: %s)\n", response.Data.ID, response.Data.Status)
List phone numbers for a WABA
client.Whatsapp.PhoneNumbers.List() — GET /v2/whatsapp/phone_numbers
ctx := context.TODO()
response, err := client.Whatsapp.PhoneNumbers.List(ctx,
telnyx.WhatsappPhoneNumberListParams{
WabaID: telnyx.String("019c1ff0-5c30-7f36-8436-730b1d0b0e56"),
},
)
if err != nil {
log.Fatal(err)
}
for _, pn := range response.Data {
fmt.Printf("%s - quality: %s\n", pn.PhoneNumber, pn.QualityRating)
}
Webhook Verification
Telnyx signs webhooks with Ed25519. Always verify signatures in production:
import "github.com/team-telnyx/telnyx-go/webhook"
event, err := webhook.ConstructEvent(
payload, // []byte — raw request body
request.Header.Get("telnyx-signature-ed25519"),
request.Header.Get("telnyx-timestamp"),
telnyxPublicKey,
)
if err != nil {
log.Printf("Webhook verification failed: %v", err)
http.Error(w, "Invalid signature", http.StatusForbidden)
return
}
Webhooks
These webhook payload fields are inline because they are part of the primary integration path.
Message Delivery Update
| Field | Type | Description |
|---|---|---|
data.event_type |
enum: message.sent, message.finalized | Delivery status event |
data.payload.id |
uuid | Message ID |
data.payload.to[0].status |
string | queued, sent, delivered, read, failed |
data.payload.template_id |
string | Telnyx template UUID (if template message) |
data.payload.template_name |
string | Template name (if template message) |
Template Status Change
| Field | Type | Description |
|---|---|---|
event_type |
string | whatsapp.template.approved, whatsapp.template.rejected, whatsapp.template.disabled |
payload.template_id |
string | Telnyx template UUID |
payload.template_name |
string | Template name |
payload.status |
string | New template status |
payload.reason |
string | Rejection/disable reason |
Template Best Practices
- Naming: Use lowercase with underscores. Be descriptive (e.g.,
appointment_reminder, notmsg1). - Sample values: Provide realistic examples in the
examplefield — Meta reviewers check these. - Category selection:
AUTHENTICATION— OTP/verification codes only. Gets special pricing.UTILITY— Transactional (order updates, shipping, account alerts).MARKETING— Promotional content, offers, newsletters.
- Keep it concise: Meta prefers shorter templates. Avoid unnecessary formatting.
- Parameters: Use
{{1}},{{2}}, etc. for variable content. Always provide the correct number of parameters when sending.
Important Supporting Operations
| Operation | SDK Method | Use Case |
|---|---|---|
| Get template details | client.WhatsappMessageTemplates.Retrieve() |
Check template status |
| Get business profile | client.Whatsapp.PhoneNumbers.Profile.Retrieve() |
View business profile |
| Configure webhooks | client.Whatsapp.BusinessAccounts.Settings.Update() |
Subscribe to events |
Additional Operations
| Operation | SDK Method | Endpoint | Required Params |
|---|---|---|---|
| Send WhatsApp message | client.Messages.SendWhatsapp() |
POST /messages/whatsapp |
From, To, WhatsappMessage |
| List WABAs | client.Whatsapp.BusinessAccounts.List() |
GET /v2/whatsapp/business_accounts |
— |
| Get WABA | client.Whatsapp.BusinessAccounts.Retrieve() |
GET /v2/whatsapp/business_accounts/:id |
WabaID |
| List templates | client.Whatsapp.Templates.List() |
GET /v2/whatsapp/message_templates |
WabaID |
| Get template | client.WhatsappMessageTemplates.Retrieve() |
GET /v2/whatsapp_message_templates/:id |
TemplateID |
| Create template | client.Whatsapp.Templates.Create() |
POST /v2/whatsapp/message_templates |
WabaID, Name, Category, Language, Components |
| List phone numbers | client.Whatsapp.PhoneNumbers.List() |
GET /v2/whatsapp/phone_numbers |
WabaID |
| Configure webhooks | client.Whatsapp.BusinessAccounts.Settings.Update() |
PATCH /v2/whatsapp/business_accounts/:id/settings |
WabaID |