Skip to main content

Go Examples

Complete Go examples for integrating with the LuxCore API using the standard library.

LuxCore Client Package

package luxcore

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"math"
	"net/http"
	"net/url"
	"os"
	"time"
)

const BaseURL = "https://api.lux-core.io/api/v1"

type Client struct {
	APIKey     string
	HTTPClient *http.Client
	BaseURL    string
}

type LuxCoreError struct {
	Message    string
	StatusCode int
	ErrorCode  string
}

func (e *LuxCoreError) Error() string {
	return fmt.Sprintf("LuxCore API error (%d): %s", e.StatusCode, e.Message)
}

func NewClient(apiKey string) *Client {
	if apiKey == "" {
		apiKey = os.Getenv("LUXCORE_API_KEY")
	}
	return &Client{
		APIKey:     apiKey,
		HTTPClient: &http.Client{Timeout: 30 * time.Second},
		BaseURL:    BaseURL,
	}
}

func (c *Client) request(method, path string, body interface{}, params url.Values) ([]byte, error) {
	reqURL := c.BaseURL + path
	if params != nil {
		reqURL += "?" + params.Encode()
	}

	var reqBody io.Reader
	if body != nil {
		jsonBody, err := json.Marshal(body)
		if err != nil {
			return nil, err
		}
		reqBody = bytes.NewBuffer(jsonBody)
	}

	req, err := http.NewRequest(method, reqURL, reqBody)
	if err != nil {
		return nil, err
	}

	req.Header.Set("X-API-Key", c.APIKey)
	req.Header.Set("Content-Type", "application/json")

	resp, err := c.HTTPClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	respBody, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode >= 400 {
		var errResp struct {
			Message string `json:"message"`
			Error   string `json:"error"`
		}
		json.Unmarshal(respBody, &errResp)
		return nil, &LuxCoreError{
			Message:    errResp.Message,
			StatusCode: resp.StatusCode,
			ErrorCode:  errResp.Error,
		}
	}

	return respBody, nil
}

// Payment types
type PaymentRequest struct {
	Amount            int64                  `json:"amount"`
	Currency          string                 `json:"currency"`
	Method            string                 `json:"method"`
	Type              string                 `json:"type"`
	MerchantReference string                 `json:"merchant_reference"`
	Description       string                 `json:"description,omitempty"`
	Customer          Customer               `json:"customer"`
	Payout            *PayoutDetails         `json:"payout,omitempty"`
	Metadata          map[string]interface{} `json:"metadata,omitempty"`
}

type Customer struct {
	Name  string `json:"name"`
	Email string `json:"email"`
	Phone string `json:"phone,omitempty"`
}

type PayoutDetails struct {
	RecipientName string `json:"recipient_name"`
	BankAccount   string `json:"bank_account"`
	BankCode      string `json:"bank_code"`
	Reference     string `json:"reference,omitempty"`
}

type Payment struct {
	TransactionID     string                 `json:"transaction_id"`
	Status            string                 `json:"status"`
	Amount            int64                  `json:"amount"`
	Currency          string                 `json:"currency"`
	Method            string                 `json:"method"`
	Type              string                 `json:"type"`
	MerchantReference string                 `json:"merchant_reference"`
	CreatedAt         time.Time              `json:"created_at"`
	Instructions      *PaymentInstructions   `json:"instructions,omitempty"`
	Metadata          map[string]interface{} `json:"metadata,omitempty"`
}

type PaymentInstructions struct {
	BankName      string `json:"bank_name"`
	AccountNumber string `json:"account_number"`
	Reference     string `json:"reference"`
	Beneficiary   string `json:"beneficiary"`
}

type PaymentListResponse struct {
	Success bool      `json:"success"`
	Data    []Payment `json:"data"`
	Total   int       `json:"total"`
}

// Payment methods
func (c *Client) CreatePayment(req PaymentRequest) (*Payment, error) {
	respBody, err := c.request("POST", "/payments", req, nil)
	if err != nil {
		return nil, err
	}

	var payment Payment
	if err := json.Unmarshal(respBody, &payment); err != nil {
		return nil, err
	}

	return &payment, nil
}

func (c *Client) GetPayment(paymentID string) (*Payment, error) {
	respBody, err := c.request("GET", "/payments/"+paymentID, nil, nil)
	if err != nil {
		return nil, err
	}

	var payment Payment
	if err := json.Unmarshal(respBody, &payment); err != nil {
		return nil, err
	}

	return &payment, nil
}

func (c *Client) ListPayments(filters map[string]string) (*PaymentListResponse, error) {
	params := url.Values{}
	for k, v := range filters {
		params.Set(k, v)
	}

	respBody, err := c.request("GET", "/payments", nil, params)
	if err != nil {
		return nil, err
	}

	var result PaymentListResponse
	if err := json.Unmarshal(respBody, &result); err != nil {
		return nil, err
	}

	return &result, nil
}

func (c *Client) CancelPayment(paymentID string) error {
	_, err := c.request("POST", "/payments/"+paymentID+"/cancel", nil, nil)
	return err
}

// Balance
type BalanceResponse struct {
	Available int64  `json:"available"`
	Pending   int64  `json:"pending"`
	Currency  string `json:"currency"`
}

func (c *Client) GetBalance(currency string) (*BalanceResponse, error) {
	params := url.Values{}
	if currency != "" {
		params.Set("currency", currency)
	}

	respBody, err := c.request("GET", "/balance", nil, params)
	if err != nil {
		return nil, err
	}

	var balance BalanceResponse
	if err := json.Unmarshal(respBody, &balance); err != nil {
		return nil, err
	}

	return &balance, nil
}

// Webhook verification
func VerifyWebhookSignature(payload []byte, signature string, timestamp int64, secret string) error {
	// Check timestamp (reject if older than 5 minutes)
	currentTime := time.Now().Unix()
	if math.Abs(float64(currentTime-timestamp)) > 300 {
		return fmt.Errorf("webhook timestamp too old")
	}

	// Calculate expected signature
	payloadToSign := fmt.Sprintf("%d.%s", timestamp, string(payload))
	mac := hmac.New(sha256.New, []byte(secret))
	mac.Write([]byte(payloadToSign))
	expectedSignature := "sha256=" + hex.EncodeToString(mac.Sum(nil))

	// Compare signatures
	if !hmac.Equal([]byte(signature), []byte(expectedSignature)) {
		return fmt.Errorf("invalid webhook signature")
	}

	return nil
}

Usage Examples

Create a Deposit Payment

package main

import (
	"fmt"
	"log"
	"time"

	"your-project/luxcore"
)

func main() {
	client := luxcore.NewClient("")

	payment, err := client.CreatePayment(luxcore.PaymentRequest{
		Amount:            100000, // $1,000.00 MXN (in centavos)
		Currency:          "MXN",
		Method:            "spei",
		Type:              "deposit",
		MerchantReference: fmt.Sprintf("order_%d", time.Now().Unix()),
		Customer: luxcore.Customer{
			Name:  "Juan Perez",
			Email: "juan@example.com",
			Phone: "+525551234567",
		},
		Metadata: map[string]interface{}{
			"order_id": "12345",
			"source":   "web",
		},
	})
	if err != nil {
		log.Fatalf("Failed to create payment: %v", err)
	}

	fmt.Printf("Payment created: %s\n", payment.TransactionID)
	fmt.Printf("Status: %s\n", payment.Status)

	if payment.Instructions != nil {
		fmt.Printf("Bank: %s\n", payment.Instructions.BankName)
		fmt.Printf("CLABE: %s\n", payment.Instructions.AccountNumber)
		fmt.Printf("Reference: %s\n", payment.Instructions.Reference)
	}
}

Create a Withdrawal (Payout)

payout, err := client.CreatePayment(luxcore.PaymentRequest{
	Amount:            50000,
	Currency:          "MXN",
	Method:            "spei",
	Type:              "withdrawal",
	MerchantReference: fmt.Sprintf("payout_%d", time.Now().Unix()),
	Customer: luxcore.Customer{
		Name:  "Finance Team",
		Email: "finance@company.com",
	},
	Payout: &luxcore.PayoutDetails{
		RecipientName: "Maria Garcia",
		BankAccount:   "012345678901234567",
		BankCode:      "002",
		Reference:     "PAYOUT-001",
	},
})
if err != nil {
	log.Fatal(err)
}

fmt.Printf("Payout created: %s\n", payout.TransactionID)

Webhook Handler (net/http)

package main

import (
	"encoding/json"
	"io"
	"log"
	"net/http"
	"os"
	"strconv"

	"your-project/luxcore"
)

var webhookSecret = os.Getenv("LUXCORE_WEBHOOK_SECRET")

type WebhookPayload struct {
	Event     string          `json:"event"`
	Payment   json.RawMessage `json:"payment"`
	Timestamp int64           `json:"timestamp"`
}

func webhookHandler(w http.ResponseWriter, r *http.Request) {
	// Read body
	body, err := io.ReadAll(r.Body)
	if err != nil {
		http.Error(w, "Failed to read body", http.StatusBadRequest)
		return
	}

	// Get headers
	signature := r.Header.Get("X-Webhook-Signature")
	timestampStr := r.Header.Get("X-Webhook-Timestamp")
	timestamp, _ := strconv.ParseInt(timestampStr, 10, 64)

	// Verify signature
	if err := luxcore.VerifyWebhookSignature(body, signature, timestamp, webhookSecret); err != nil {
		log.Printf("Webhook verification failed: %v", err)
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// Parse payload
	var payload WebhookPayload
	if err := json.Unmarshal(body, &payload); err != nil {
		http.Error(w, "Invalid JSON", http.StatusBadRequest)
		return
	}

	// Process event
	log.Printf("Received webhook event: %s", payload.Event)

	switch payload.Event {
	case "payment.completed":
		log.Println("Payment completed!")
		// Handle completed payment
	case "payment.failed":
		log.Println("Payment failed!")
		// Handle failed payment
	case "payout.completed":
		log.Println("Payout completed!")
		// Handle completed payout
	default:
		log.Printf("Unhandled event: %s", payload.Event)
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(map[string]bool{"received": true})
}

func main() {
	http.HandleFunc("/webhooks/luxcore", webhookHandler)
	log.Println("Starting webhook server on :3000")
	log.Fatal(http.ListenAndServe(":3000", nil))
}

Error Handling

payment, err := client.CreatePayment(req)
if err != nil {
	if luxErr, ok := err.(*luxcore.LuxCoreError); ok {
		switch luxErr.StatusCode {
		case 401:
			log.Println("Invalid API key")
		case 400:
			log.Printf("Validation error: %s", luxErr.Message)
		case 429:
			log.Println("Rate limited - waiting to retry")
			time.Sleep(60 * time.Second)
			// Retry...
		case 500, 503:
			log.Println("Server error - retrying")
			time.Sleep(5 * time.Second)
			// Retry...
		default:
			log.Printf("API error (%d): %s", luxErr.StatusCode, luxErr.Message)
		}
	} else {
		log.Printf("Network error: %v", err)
	}
	return
}

Complete Example with Gin

package main

import (
	"log"
	"net/http"
	"os"

	"github.com/gin-gonic/gin"
	"your-project/luxcore"
)

var client *luxcore.Client

func main() {
	client = luxcore.NewClient(os.Getenv("LUXCORE_API_KEY"))

	r := gin.Default()

	// Create payment endpoint
	r.POST("/api/payments", createPaymentHandler)

	// Webhook endpoint
	r.POST("/webhooks/luxcore", webhookHandler)

	r.Run(":8080")
}

func createPaymentHandler(c *gin.Context) {
	var req struct {
		Amount   int64  `json:"amount" binding:"required"`
		OrderID  string `json:"order_id" binding:"required"`
		Customer struct {
			Name  string `json:"name" binding:"required"`
			Email string `json:"email" binding:"required"`
		} `json:"customer" binding:"required"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	payment, err := client.CreatePayment(luxcore.PaymentRequest{
		Amount:            req.Amount,
		Currency:          "MXN",
		Method:            "spei",
		Type:              "deposit",
		MerchantReference: req.OrderID,
		Customer: luxcore.Customer{
			Name:  req.Customer.Name,
			Email: req.Customer.Email,
		},
	})
	if err != nil {
		if luxErr, ok := err.(*luxcore.LuxCoreError); ok {
			c.JSON(luxErr.StatusCode, gin.H{"error": luxErr.Message})
			return
		}
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Payment creation failed"})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"payment_id":   payment.TransactionID,
		"status":       payment.Status,
		"instructions": payment.Instructions,
	})
}