From d095b86192bbcec802ad38486a1c738bd6a9e0a0 Mon Sep 17 00:00:00 2001 From: Andrey Skoskin Date: Thu, 29 Jan 2026 11:40:21 +0300 Subject: [PATCH 1/3] Add Reports API basic implementation --- report.go | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 report.go diff --git a/report.go b/report.go new file mode 100644 index 0000000..9438452 --- /dev/null +++ b/report.go @@ -0,0 +1,141 @@ +package nexmo + +import ( + "encoding/base64" + "encoding/json" + "io/ioutil" + "net/http" + "time" +) + +// Report represents the Report API functions for sending text messages. +// https://developer.vonage.com/en/api/reports +type Report struct { + client *Client +} + +// Product types. +const ( + ProductSMS = "SMS" + ProductSMSTrafficControl = "SMS-TRAFFIC-CONTROL" + ProductVoiceCall = "VOICE-CALL" + ProductVoiceFailed = "VOICE-FAILED" + ProductVoiceTTS = "VOICE-TTS" + ProductInAppVoice = "IN-APP-VOICE" + ProductWebSocketCall = "WEBSOCKET-CALL" + ProductASR = "ASR" + ProductAMD = "AMD" + ProductVerifyAPI = "VERIFY-API" + ProductVerifyV2 = "VERIFY-V2" + ProductNumberInsight = "NUMBER-INSIGHT" + ProductNumberInsightV2 = "NUMBER-INSIGHT-V2" + ProductConversationEvent = "CONVERSATION-EVENT" + ProductConversationMessage = "CONVERSATION-MESSAGE" + ProductMessages = "MESSAGES" + ProductVideoAPI = "VIDEO-API" + ProductNetworkAPIEvent = "NETWORK-API-EVENT" + ProductReportsUsage = "REPORTS-USAGE" +) + +// Direction types. +const ( + DirectionInbound = "inbound" + DirectionOutbound = "outbound" +) + +// RecordsRequest defines a records request message. +type RecordsRequest struct { + AccountID string + ID string + Product string + Direction string +} + +// RecordsResponse defines a records response message. +type RecordsResponse struct { + Links struct { + Self struct { + Href time.Time `json:"href"` + } `json:"self"` + Next struct { + Href string `json:"href"` + } `json:"next"` + } `json:"_links"` + Cursor string `json:"cursor"` + Iv string `json:"iv"` + RequestID string `json:"request_id"` + RequestStatus string `json:"request_status"` + ReceivedAt time.Time `json:"received_at"` + ItemsCount int `json:"items_count"` + IdsNotFound string `json:"ids_not_found"` + Product string `json:"product"` + Records []struct { + AccountID string `json:"account_id"` + MessageID string `json:"message_id"` + AccountRef string `json:"account_ref"` + ClientRef string `json:"client_ref"` + Direction string `json:"direction"` + From string `json:"from"` + To string `json:"to"` + ForcedFrom string `json:"forced_from"` + ChangedFrom string `json:"changed_from"` + Concatenated string `json:"concatenated"` + MessageBody string `json:"message_body"` + Network string `json:"network"` + NetworkName string `json:"network_name"` + Country string `json:"country"` + CountryName string `json:"country_name"` + DateReceived time.Time `json:"date_received"` + DateFinalized time.Time `json:"date_finalized"` + Latency string `json:"latency"` + Status string `json:"status"` + ErrorCode string `json:"error_code"` + ErrorCodeDescription string `json:"error_code_description"` + Currency string `json:"currency"` + TotalPrice string `json:"total_price"` + ID string `json:"id"` + Dcs string `json:"dcs"` + ValidityPeriod string `json:"validity_period"` + IPAddress string `json:"ip_address"` + Udh string `json:"udh"` + WorkflowID string `json:"workflow_id"` + } `json:"records"` +} + +// Send the message using the specified Nexmo API client. +func (c *Report) Send(req *RecordsRequest) (*RecordsResponse, error) { + var r, err = http.NewRequest("GET", apiRootv2+"/v2/reports/records", nil) + if err != nil { + return nil, err + } + + var q = r.URL.Query() + q.Add("account_id", req.AccountID) + q.Add("id", req.ID) + q.Add("product", req.Product) + q.Add("direction", req.Direction) + + var auth = base64.RawURLEncoding.EncodeToString([]byte(c.client.apiKey + ":" + c.client.apiSecret)) + + r.Header.Add("Authorization", "Basic "+auth) + r.Header.Add("Accept", "application/json") + r.Header.Add("Content-Type", "application/json") + + var resp *http.Response + if resp, err = c.client.HTTPClient.Do(r); err != nil { + return nil, err + } + defer resp.Body.Close() + + var body []byte + if body, err = ioutil.ReadAll(resp.Body); err != nil { + return nil, err + } + + var records RecordsResponse + err = json.Unmarshal(body, &records) + if err != nil { + return nil, err + } + return &records, nil +} From 0a266d55003925cf5f8d1c4b6eb8bfee31272a6e Mon Sep 17 00:00:00 2001 From: Andrey Skoskin Date: Thu, 29 Jan 2026 13:26:09 +0300 Subject: [PATCH 2/3] Add Reports API object to Client --- client.go | 2 ++ report.go => reports.go | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) rename report.go => reports.go (96%) diff --git a/client.go b/client.go index 2986cc5..37aa925 100644 --- a/client.go +++ b/client.go @@ -12,6 +12,7 @@ type Client struct { SMS *SMS USSD *USSD Verify *Verification + Reports *Reports HTTPClient *http.Client apiKey string apiSecret string @@ -37,6 +38,7 @@ func NewClient(apiKey, apiSecret string) (*Client, error) { c.SMS = &SMS{c} c.USSD = &USSD{c} c.Verify = &Verification{c} + c.Reports = &Reports{c} c.HTTPClient = http.DefaultClient return c, nil } diff --git a/report.go b/reports.go similarity index 96% rename from report.go rename to reports.go index 9438452..e04b4b3 100644 --- a/report.go +++ b/reports.go @@ -8,9 +8,9 @@ import ( "time" ) -// Report represents the Report API functions for sending text messages. +// Reports represents the Reports API functions for sending text messages. // https://developer.vonage.com/en/api/reports -type Report struct { +type Reports struct { client *Client } @@ -103,7 +103,7 @@ type RecordsResponse struct { } // Send the message using the specified Nexmo API client. -func (c *Report) Send(req *RecordsRequest) (*RecordsResponse, error) { +func (c *Reports) Send(req *RecordsRequest) (*RecordsResponse, error) { var r, err = http.NewRequest("GET", apiRootv2+"/v2/reports/records", nil) if err != nil { return nil, err From 5f0c371b0fe9a7b7788f738faf880904479f3151 Mon Sep 17 00:00:00 2001 From: Andrey Skoskin Date: Fri, 30 Jan 2026 12:19:42 +0300 Subject: [PATCH 3/3] Add Reports API object to Client - account ID --- reports.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/reports.go b/reports.go index e04b4b3..c4efede 100644 --- a/reports.go +++ b/reports.go @@ -45,7 +45,6 @@ const ( // RecordsRequest defines a records request message. type RecordsRequest struct { - AccountID string ID string Product string Direction string @@ -110,7 +109,7 @@ func (c *Reports) Send(req *RecordsRequest) (*RecordsResponse, error) { } var q = r.URL.Query() - q.Add("account_id", req.AccountID) + q.Add("account_id", c.client.apiKey) q.Add("id", req.ID) q.Add("product", req.Product) q.Add("direction", req.Direction)