> ## Documentation Index
> Fetch the complete documentation index at: https://flutterwaveinc.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Go

> Learn how to complete a bank transfer using Go.

## Concepts

This guide will walk you through the steps needed to transfer funds using Flutterwave's API with Go. You'll learn how to:

1. **Set up your server app**: Create a Go project and install the required dependencies.
2. **Get bank code**:
   Retrieve a list of bank codes from Flutterwave's API for initiating transactions.
3. **Get Account Details**:
   Use a bank code to fetch and confirm bank account details.
4. **Initiate a transfer**:
   Send money to the resolved bank account via Flutterwave.
5. **Fetch the transfer**:
   Retrieve the status of a transfer to ensure it was processed.
6. **Verify a transaction is valid**:
   Confirm the authenticity of a transaction using Flutterwave's verification endpoint.

## Step 1: Setting up your Server App

To initiate a transfer successfully, you need to whitelist your current IP address. Here is a [quick guide](https://flutterwave.com/mu/support/integrations/how-to-whitelist-ip-addresses-on-your-flutterwave-dashboard) on how to do that.

<Info>
  You can also use the universal address `0.0.0.0` to allow transfers from all
  IP addresses. However, this method offers less control compared to
  specifying a list of acceptable IP addresses.
</Info>

Create a new Go project and initialize a Go module to manage dependencies.

```bash theme={null}
mkdir flutterwave-go && cd flutterwave-go
go mod init flutterwave-go
```

### Installing your Dependencies

Next, install the required dependency.

```bash theme={null}
go get github.com/joho/godotenv
```

### Configuring your Environment

Log into your [Flutterwave dashboard](https://app.flutterwave.com/dashboard) to get your API keys and add the keys to your `.env` file.

```bash theme={null}
FLW_SECRET_KEY=<your_secret_key_here>
FLW_PUBLIC_KEY=<your_public_key_here>
```

### Create the Project Entry Point

Create a `main.go` file in the root directory and initialize the project entry point.

```go theme={null}
package main

import (
    "fmt"
    "log"
    "os"

    "github.com/joho/godotenv"
)

// Load environment variables
var flwSecretKey string
func init() {
    err := godotenv.Load(".env")
    if err != nil {
        log.Fatal("Error loading .env file")
    }

    secretKey := os.Getenv("FLW_SECRET_KEY")
    fmt.Println("Secret Key Loaded:", secretKey)
}
```

## Step 2: Fetch Bank Code

Before you make a transfer to any bank, you need the bank code. It is a unique identifier that every bank has. You will use this to identify the bank you want to transfer to.

```go theme={null}
type Bank struct {
	Code string `json:"code"`
	Name string `json:"name"`
}

// Fetch bank code from Flutterwave API
func getBankCode(country, accountBank string) (Bank, error) {
	url := fmt.Sprintf("https://api.flutterwave.com/v3/banks/%s", country)
	req, _ := http.NewRequest("GET", url, nil)
	req.Header.Add("Authorization", "Bearer "+flwSecretKey)

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return Bank{}, err
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	if resp.StatusCode != 200 {
		return Bank{}, fmt.Errorf("failed to fetch bank list: %s", string(body))
	}

	var result struct {
		Data []Bank `json:"data"`
	}
	if err := json.Unmarshal(body, &result); err != nil {
		return Bank{}, fmt.Errorf("failed to unmarshal response: %w", err)
	}

	// Loop through the result to find the matching bank code
	for _, bank := range result.Data {
		if bank.Code == accountBank {
			fmt.Printf("Selected Bank: %s\n", bank.Name)
			return bank, nil
		}
	}

	return Bank{}, fmt.Errorf("bank not found for code: %s", accountBank)
}
```

## Step 3: Resolve Bank Account

Next, validate the account before making the transfer.

```go theme={null}
type AccountDetails struct {
	AccountNumber string `json:"account_number"`
	AccountName   string `json:"account_name"`
}

// Resolve bank account details
func resolveAccount(accountNumber, accountBank string) (AccountDetails, error) {
	url := "https://api.flutterwave.com/v3/accounts/resolve"
	payload := map[string]string{
		"account_number": accountNumber,
		"account_bank":   accountBank,
	}
	jsonPayload, _ := json.Marshal(payload)

	req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonPayload))
	req.Header.Add("Authorization", "Bearer "+flwSecretKey)
	req.Header.Add("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return AccountDetails{}, err
	}
	defer resp.Body.Close()

	body, _ := ioutil.ReadAll(resp.Body)
	if resp.StatusCode != 200 {
		return AccountDetails{}, fmt.Errorf("failed to resolve account: %s", string(body))
	}

	var result struct {
		Data AccountDetails `json:"data"`
	}
	json.Unmarshal(body, &result)

	fmt.Printf("Account Verified: %+v\n", result.Data)
	return result.Data, nil
}
```

## Step 4: Initiate Transfer

Initiate the transfer once the bank account details have been verified.

```go theme={null}
type TransferResponse struct {
	ID string `json:"id"`
}

// Initiate a bank transfer
func initiateTransfer(dummyData map[string]interface{}, selectedBank Bank) (TransferResponse, error) {
	url := "https://api.flutterwave.com/v3/transfers"
	payload := map[string]interface{}{
		"account_bank":   selectedBank.Code,
		"account_number": dummyData["account_number"],
		"amount":         dummyData["amount"],
		"narration":      dummyData["narration"],
		"currency":       dummyData["currency"],
		"reference":      dummyData["reference"],
		"callback_url":   "https://example.com/callback",
	}
	jsonPayload, _ := json.Marshal(payload)

	req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonPayload))
	req.Header.Add("Authorization", "Bearer "+flwSecretKey)
	req.Header.Add("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return TransferResponse{}, err
	}
	defer resp.Body.Close()

	body, _ := ioutil.ReadAll(resp.Body)
	if resp.StatusCode != 200 {
		return TransferResponse{}, fmt.Errorf("failed to initiate transfer: %s", string(body))
	}

	var result struct {
		Data TransferResponse `json:"data"`
	}
	json.Unmarshal(body, &result)

	fmt.Printf("Transfer Initiated: %+v\n", result.Data)
	return result.Data, nil
}
```

## Step 5: Fetch Transfer Status

Check the status of the transfer using the transfer ID returned from the previous step.

```go theme={null}
type TransferStatus struct {
	Status string `json:"status"`
}

// Fetch the transfer status
func fetchTransferStatus(transferID string) (TransferStatus, error) {
	url := fmt.Sprintf("https://api.flutterwave.com/v3/transfers/%s", transferID)
	req, _ := http.NewRequest("GET", url, nil)
	req.Header.Add("Authorization", "Bearer "+flwSecretKey)

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return TransferStatus{}, err
	}
	defer resp.Body.Close()

	body, _ := ioutil.ReadAll(resp.Body)
	if resp.StatusCode != 200 {
		return TransferStatus{}, fmt.Errorf("failed to fetch transfer status: %s", string(body))
	}

	var result struct {
		Data TransferStatus `json:"data"`
	}
	json.Unmarshal(body, &result)

	fmt.Printf("Transfer Status: %+v\n", result.Data)
	return result.Data, nil
}

```

## Step 6: Transaction Verification

Verify the transaction to confirm the transfer is successful.

```go theme={null}
type TransactionVerification struct {
	Status string  `json:"status"`
	Amount float64 `json:"amount"`
}

// Verify a transaction

func verifyTransfer(transferID int) (TransactionVerification, error) {
        url := fmt.Sprintf("https://api.flutterwave.com/v3/transfers/%s", strconv.Itoa(transferID))
        req, _ := http.NewRequest("GET", url, nil)
        req.Header.Add("Authorization", "Bearer "+flwSecretKey)
        client := &http.Client{}
        resp, err := client.Do(req)
        if err != nil {
                return TransactionVerification{}, err
        }
        defer resp.Body.Close()
        body, _ := io.ReadAll(resp.Body)
        if resp.StatusCode != 200 {
                return TransactionVerification{}, fmt.Errorf("failed to verify transfer: %s", string(body))
        }
        var result struct {
                Data TransactionVerification `json:"data"`
        }
        json.Unmarshal(body, &result)
        fmt.Printf("Trasfer Verified: %+v\n", result.Data)
        return result.Data, nil
}
```

### Calling the Requests

Make the requests to simulate the bank transfer using all the functions created above.

```go theme={null}
package main

import (
        "bytes"
        "encoding/json"
        "fmt"
        "io/ioutil"
        "net/http"
        "os"

        "github.com/joho/godotenv"
)

func main() {
    // Example: Fetch bank code
    country := "NG"         // Nigeria as an example
    accountBank := "044"    // Example bank code
    accountNumber := "1234567890" // Example account number

    // Step 1: Get the bank code
    selectedBank, err := getBankCode(country, accountBank)
    if err != nil {
            fmt.Printf("Error fetching bank code: %v\n", err)
            return
    }

    // Step 2: Resolve account details
    accountDetails, err := resolveAccount(accountNumber, selectedBank.Code)
    if err != nil {
            fmt.Printf("Error resolving account: %v\n", err)
            return
    }

    // Step 3: Initiate transfer
    dummyData := map[string]interface{}{
            "account_number": accountDetails.AccountNumber,
            "amount":         1000,
            "narration":      "Test transfer",
            "currency":       "NGN",
            "reference":      "tx-1234567890", //you can use a helper function or library to generate unique references
    }
    transferResponse, err := initiateTransfer(dummyData, selectedBank)
    if err != nil {
            fmt.Printf("Error initiating transfer: %v\n", err)
            return
    }

    // Step 4: Fetch transfer status
    transferStatus, err := fetchTransferStatus(transferResponse.ID)
    if err != nil {
            fmt.Printf("Error fetching transfer status: %v\n", err)
            return
    }

    // Step 5: Verify transaction
    transactionVerification, err := verifyTransaction(transferResponse.ID)
    if err != nil {
            fmt.Printf("Error verifying transaction: %v\n", err)
            return
    }

    fmt.Printf("Transfer Complete, Transaction Status: %s, Amount: %.2f\n", transactionVerification.Status, transactionVerification.Amount)
}
```

Use the command below to run your application:

```bash theme={null}
go run main.go
```

## Next Step

Check out other [API endpoints](/api-reference) you can integrate.
You can also checkout our [best practices](/best-practices) and [error handling](/common-errors) guides to learn how to build more robust applications.
