> For the complete documentation index, see [llms.txt](https://docs.catfee.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.catfee.io/en/getting-started/buy-energy-via-api-on-catfee/go.md).

# Go Example for Calling API

Golang Example for Calling the CatFee.IO Rest API

### Prerequisites

[You need a valid **API Key** and **API Secret**](/en/getting-started/buy-energy-via-api-on-catfee/api-overview.md#apply-api-info).

Make sure your Go environment has access to standard libraries such as `net/http` and `crypto/hmac`.

### Sample Code

```go
package main

import (
	"crypto/hmac"
	"crypto/rand"
	"crypto/sha256"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"
	"time"
)

const (
	APIKey    = "your_api_key"       // Replace with your actual API Key
	APISecret = "your_api_secret"    // Replace with your actual API Secret
	BaseURL   = "https://api.catfee.io"
	Timeout   = 15 * time.Second
)

type apiResponse struct {
	Code   int           `json:"code"`
	Msg    string        `json:"msg"`
	SubMsg string        `json:"sub_msg"`
	Data   *orderPayload `json:"data"`
}

type orderPayload struct {
	ID string `json:"id"`
}

// Generate the current timestamp in ISO 8601 format
func generateTimestamp() string {
	return time.Now().UTC().Format("2006-01-02T15:04:05.000Z")
}

// Build request path including query parameters
func buildRequestPath(path string, queryParams url.Values) string {
	if len(queryParams) == 0 {
		return path
	}

	return path + "?" + queryParams.Encode()
}

// Generate HMAC-SHA256 signature
func generateSignature(timestamp, method, requestPath string) string {
	signString := timestamp + strings.ToUpper(method) + requestPath
	mac := hmac.New(sha256.New, []byte(APISecret))
	mac.Write([]byte(signString))
	signature := mac.Sum(nil)
	return base64.StdEncoding.EncodeToString(signature)
}

// Generate a 32-character idempotency key.
func generateClientOrderID() (string, error) {
	value := make([]byte, 16)
	if _, err := rand.Read(value); err != nil {
		return "", err
	}
	return hex.EncodeToString(value), nil
}

// Create and send HTTP request
func createRequest(url, method, timestamp, signature string) (*http.Response, error) {
	client := &http.Client{Timeout: Timeout}
	req, err := http.NewRequest(method, url, nil)
	if err != nil {
		return nil, err
	}

	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("CF-ACCESS-KEY", APIKey)
	req.Header.Add("CF-ACCESS-SIGN", signature)
	req.Header.Add("CF-ACCESS-TIMESTAMP", timestamp)

	return client.Do(req)
}

func main() {
	method := "POST" // Can be "GET", "PUT", or "DELETE"
	path := "/v1/order"
	clientOrderID, err := generateClientOrderID()
	if err != nil {
		fmt.Println("Failed to generate Client Order ID:", err)
		return
	}

	// Example: Create order
	queryParams := url.Values{}
	queryParams.Set("quantity", "65000")
	queryParams.Set("receiver", "TRON_ADDRESS")
	queryParams.Set("duration", "1h")
	queryParams.Set("client_order_id", clientOrderID)
	queryParams.Set("activate", "true")

	timestamp := generateTimestamp()
	requestPath := buildRequestPath(path, queryParams)
	signature := generateSignature(timestamp, method, requestPath)

	url := BaseURL + requestPath

	fmt.Println("Client Order ID:", clientOrderID)
	resp, err := createRequest(url, method, timestamp, signature)
	if err != nil {
		fmt.Println("Request failed:", err)
		fmt.Println("Retry with the same Client Order ID:", clientOrderID)
		return
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("Failed to read response:", err)
		return
	}

	fmt.Println("HTTP Status:", resp.StatusCode)
	fmt.Println("Response Body:", string(body))

	if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices {
		fmt.Printf("HTTP request failed with status %d\n", resp.StatusCode)
		return
	}

	var result apiResponse
	if err := json.Unmarshal(body, &result); err != nil {
		fmt.Println("Response is not valid JSON:", err)
		return
	}
	if result.Code != 0 {
		message := result.Msg
		if message == "" {
			message = result.SubMsg
		}
		fmt.Printf("API request failed: code=%d, message=%s\n", result.Code, message)
		return
	}
	if result.Data != nil {
		fmt.Println("Order ID:", result.Data.ID)
	}
}
```

***

### Code Explanation

#### `generateTimestamp()`

Generates the current UTC time formatted as an ISO 8601 timestamp using Go’s `time` package.

#### `buildRequestPath()`

Uses `url.Values.Encode()` to URL-encode and sort query parameters. The resulting path is used for both signing and the actual request.

#### `generateSignature()`

Creates a signature string by concatenating `timestamp + method + requestPath`, and then signs it using HMAC-SHA256 with the API Secret. The result is Base64 encoded.

#### `createRequest()`

Builds the HTTP request with appropriate headers (`CF-ACCESS-KEY`, `CF-ACCESS-SIGN`, `CF-ACCESS-TIMESTAMP`) and sends it using the standard `http` package.

#### `main()`

Defines request method and query parameters, generates timestamp, request path, and signature, builds the final URL, and sends the request. Finally, the response is read and printed.

***

### Notes

#### API Key and Secret

Make sure to replace `APIKey` and `APISecret` with your actual credentials from CatFee.IO.

#### Idempotent retries

Use a unique `client_order_id` of no more than 64 characters for each new order, and reuse it after a timeout or connection failure.

#### Response Handling

HTTP `200` does not necessarily mean business success. Always verify that the response body's `code` is `0`.

#### HTTP Methods

This example supports `POST`, but you can change it to `GET`, `PUT`, or `DELETE` depending on your needs.

***

### Summary

This example demonstrates how to securely call the CatFee.IO Rest API using Go, including HMAC-SHA256 signature generation for authentication. You can adjust the code to use different HTTP methods and handle various API responses accordingly.
