diff --git a/bank_transactions/absa_bank_transactions.go b/bank_transactions/absa_bank_transactions.go
new file mode 100644
index 0000000000000000000000000000000000000000..815234210ff778f52642304b2c23fc04fbcb38b4
--- /dev/null
+++ b/bank_transactions/absa_bank_transactions.go
@@ -0,0 +1,268 @@
+package bank_transactions
+
+import (
+	"crypto/tls"
+	"encoding/base64"
+	"github.com/go-resty/resty/v2"
+	"github.com/google/uuid"
+	"gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/errors"
+	"gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/secrets_manager"
+	"gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/string_utils"
+	"gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/struct_utils"
+	"io"
+	"strings"
+	"time"
+)
+
+type AbsaLoginInfo struct {
+	CertExpiry        string
+	CertSerialNumber  string
+	PartialNo         string
+	DeviceFingerprint string
+	AbsaSecretName    string
+	IsDebug           bool
+}
+
+const (
+	sleepTime = time.Second * 2
+)
+
+func GetAbsaTransactions(loginInfo AbsaLoginInfo) ([]byte, error) {
+
+	client, err := setupAbsaClient(loginInfo.AbsaSecretName, loginInfo.IsDebug)
+	if err != nil {
+		return nil, err
+	}
+
+	defer logoff(client)
+
+	// Get Initial session ID
+	err = login(client, loginInfo)
+	if err != nil {
+		return nil, err
+	}
+
+	// Navigate to statement download
+	err = startStatementDownloadProcess(client)
+	if err != nil {
+		return nil, err
+	}
+
+	// Request statement
+	dateString := time.Now().Format("20060102")
+	_, err = statementDownloadProcessCall(client, map[string]string{
+		"page":                "enquiry-statement",
+		"groupselect":         "",
+		"linkallterm":         "false",
+		"buttonClicked":       "proceed",
+		"SelType":             "D",
+		"FAInd":               "false",
+		"systemDate":          dateString,
+		"account_options":     "all",
+		"fromaccountgroup":    "blank",
+		"fromaccount":         "blank",
+		"fromaccountdisplay1": "blank",
+		"showall_option":      "showall",
+		"format_options":      "file",
+		"file_format_options": "csv",
+		"statement_options":   "last",
+		"days":                "7",
+		"startdate":           dateString,
+		"enddate":             dateString,
+		"startnum":            "",
+		"endnum":              "",
+		"ErrorText":           "",
+	})
+	if err != nil {
+		return nil, err
+	}
+
+	// Wait for statement to process
+	for {
+		responseBytes, err := statementDownloadProcessCall(client, map[string]string{
+			"page":          "enquiry-statement-status",
+			"buttonClicked": "proceed",
+			"ErrorText":     "",
+		})
+		if err != nil {
+			return nil, err
+		}
+
+		if strings.Contains(string(responseBytes), "The statement file is available for download") {
+			break
+		}
+		time.Sleep(sleepTime)
+	}
+
+	// Download file
+	statementBytes, err := statementDownloadProcessCall(client, map[string]string{
+		"page":          "enquiry-statement-file",
+		"buttonClicked": "saveas",
+		"filename":      "25591016.csv",
+		"ErrorText":     "",
+	})
+	if err != nil {
+		return nil, err
+	}
+	return statementBytes, nil
+}
+
+func setupAbsaClient(secretName string, isDebug bool) (*resty.Client, error) {
+	// Get cert data
+	credentials, err := getAbsaSecret(secretName, isDebug)
+	if err != nil {
+		return nil, err
+	}
+	certDataString := credentials["cert"]
+	certData, _ := base64.StdEncoding.DecodeString(certDataString)
+
+	privateKeyDataString := credentials["private_key"]
+	privateKeyData, _ := base64.StdEncoding.DecodeString(privateKeyDataString)
+
+	cert, err := tls.X509KeyPair(certData, privateKeyData)
+	if err != nil {
+		return nil, err
+	}
+
+	client := resty.New().
+		SetCertificates(cert)
+	return client, nil
+}
+
+func login(client *resty.Client, loginInfo AbsaLoginInfo) error {
+
+	// Get password
+	credentials, err := getAbsaSecret(loginInfo.AbsaSecretName, loginInfo.IsDebug)
+	if err != nil {
+		return err
+	}
+
+	username := credentials["username"]
+	password := credentials["password"]
+
+	// Get Initial session ID
+	response, err := client.R().
+		SetDoNotParseResponse(true).
+		Get("https://bionline.absa.co.za/businessintegrator/login_new.jsp")
+	if err != nil {
+		return err
+	}
+	time.Sleep(sleepTime)
+
+	// Login
+	universalTracker := uuid.New().String() + "-" + uuid.New().String()
+	response, err = client.R().
+		SetDoNotParseResponse(true).
+		SetFormData(map[string]string{
+			"lastpage":            "login",
+			"buttonClicked":       "proceed",
+			"hasCert":             "Y",
+			"certExpired":         "false",
+			"certExpiry":          loginInfo.CertExpiry,
+			"displayIgnoreButton": "true",
+			"partialNo":           loginInfo.PartialNo,
+			"universalTracker":    universalTracker,
+			"deviceFingerprint":   loginInfo.DeviceFingerprint,
+			"certSerialNo":        loginInfo.CertSerialNumber,
+			"UserID":              username,
+			"password_one":        password,
+		}).
+		Post("https://bionline.absa.co.za/businessintegrator/SignOn")
+	if err != nil {
+		return err
+	}
+
+	responseBytes, err := io.ReadAll(response.RawResponse.Body)
+	if strings.Contains(string(responseBytes), "User already signed on") {
+		// Log out
+		response, err = client.R().
+			SetDoNotParseResponse(true).
+			SetFormData(map[string]string{
+				"buttonClicked": "proceed",
+				"lastpage":      "signedon_to_signoff",
+				"ErrorText":     "",
+			}).
+			Post("https://bionline.absa.co.za/businessintegrator/SignOn")
+		if err != nil {
+			return err
+		}
+
+		// Login again
+		err := login(client, loginInfo)
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func startStatementDownloadProcess(client *resty.Client) error {
+	// Navigate to statement download
+	response, err := client.R().
+		SetDoNotParseResponse(true).
+		SetQueryParam("dojo.preventCache", string_utils.Int64ToString(time.Now().UnixMilli())).
+		SetHeader("Referer", "https://bionline.absa.co.za/businessintegrator/enquiries/menu.jsp").
+		SetHeader("Content-Type", "application/x-www-form-urlencoded").
+		Get("https://bionline.absa.co.za/businessintegrator/EnquireBankStatement")
+	if err != nil {
+		return err
+	}
+
+	responseBytes, _ := io.ReadAll(response.RawResponse.Body)
+
+	// Ensure we are on the "Statement Enquiry" screen
+	if !strings.Contains(string(responseBytes), "Statement Enquiry") {
+		return errors.New("Could not load 'Statement Enquiry' screen")
+	}
+	time.Sleep(sleepTime)
+	return nil
+}
+
+func statementDownloadProcessCall(client *resty.Client, formData map[string]string) ([]byte, error) {
+	response, err := client.R().
+		SetDoNotParseResponse(true).
+		SetFormData(formData).
+		Post("https://bionline.absa.co.za/businessintegrator/EnquireBankStatement")
+	if err != nil {
+		return nil, err
+	}
+
+	responseBytes, err := io.ReadAll(response.RawResponse.Body)
+	time.Sleep(sleepTime)
+	return responseBytes, nil
+}
+
+func logoff(client *resty.Client) error {
+	// Logoff
+	_, err := client.R().
+		SetDoNotParseResponse(true).
+		Get("https://bionline.absa.co.za/businessintegrator/Logoff")
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func getAbsaSecret(secretName string, isDebug bool) (map[string]string, error) {
+	// This secret is manually created on Secrets Manager
+
+	/*
+		Extract the key and cert from the p12 certificate
+		```
+		openssl pkcs12 -in Absa.p12 -nocerts -out userkey.pem -nodes
+		openssl pkcs12 -in Absa.p12 -clcerts -nokeys -out usercert.pem
+		```
+
+		Base64 encode the key and cert and save it in secrets manager
+	*/
+
+	secretJson, _ := secrets_manager.GetSecret(secretName, isDebug)
+	var credentials map[string]string
+	err := struct_utils.UnmarshalJSON([]byte(secretJson), &credentials)
+	if err != nil {
+		return nil, err
+	}
+
+	return credentials, nil
+}