Skip to main content

Go SDK

The official PayKore Go SDK.

Module: github.com/paykore/paykore-go

danger

All API calls must be made server-side. Never embed your API key in a binary or any context where it can be extracted.


Installation

go get github.com/paykore/paykore-go

Initialisation

import (
paykore "github.com/paykore/paykore-go"
"github.com/paykore/paykore-go/option"
)

client := paykore.NewClient(
option.WithBaseURL("https://api.paykore.com"),
option.WithToken(os.Getenv("PAYKORE_API_KEY")),
)

For sandbox, swap both the base URL and the key:

client := paykore.NewClient(
option.WithBaseURL("https://sandbox.paykore.com"),
option.WithToken(os.Getenv("PAYKORE_SANDBOX_KEY")),
)

Your API key (sk_live_* or sk_test_*) is sent as Authorization: Bearer <key> on every request. Use sk_test_* keys with the sandbox URL and sk_live_* with production — mismatches return 401.


Wallets

// Create a wallet
wallet, err := client.Wallets.CreateWallet(ctx, &paykore.CreateWalletRequest{
UserRef: "user_123",
Currency: paykore.String("NGN"),
})
// wallet.Status == "pending" initially
// account_number is empty until wallet.activated webhook fires

// Get a wallet and its current balance
result, err := client.Wallets.GetWallet(ctx, &paykore.GetWalletRequest{
ID: "wlt-uuid-here",
})
// result.Wallet — the full Wallet struct
// result.BalanceKobo — current posted balance in kobo

// List a wallet's transactions
txns, err := client.Wallets.ListWalletTransactions(ctx, &paykore.ListWalletTransactionsRequest{
ID: "wlt-uuid-here",
Limit: paykore.Int(20),
})
MethodReturns
client.Wallets.CreateWallet(ctx, req)(*CreateWalletResponse, error)
client.Wallets.GetWallet(ctx, req)(*GetWalletResponse, error)
client.Wallets.ListWalletTransactions(ctx, req)(*ListWalletTransactionsResponse, error)
note

CreateWallet returns 202 Accepted — the wallet exists immediately in pending state, but account_number is empty until the MFB provisions it asynchronously. Listen for the wallet.activated webhook before showing the NUBAN to your user.


Transfers

import "github.com/google/uuid"

// P2P transfer — instant, no NIP fee, synchronous 200 response
transfer, err := client.Transfers.P2PTransfer(ctx, &paykore.P2PTransferRequest{
SourceWallet: "source-wallet-uuid",
DestWallet: "dest-wallet-uuid",
Amount: 500000, // kobo — ₦5,000
Reference: uuid.New().String(),
Description: paykore.String("Payment for order #789"),
})

// Bank transfer — async NIP, returns 202, settles via webhook
payout, err := client.Transfers.BankTransfer(ctx, &paykore.BankTransferRequest{
SourceWallet: "source-wallet-uuid",
DestAccount: &paykore.BankAccount{
BankCode: "058",
AccountNumber: "0123456789",
AccountName: "Ada Okafor",
},
Amount: 1000000, // kobo — ₦10,000
Reference: uuid.New().String(),
})
// payout.Status == "processing"
// Final status arrives via transaction.completed or transaction.failed webhook
MethodReturns
client.Transfers.P2PTransfer(ctx, req)(*Transaction, error)
client.Transfers.BankTransfer(ctx, req)(*Transaction, error)

Payments

// Create a QR payment request (merchant side)
qr, err := client.Payments.CreateQRPayment(ctx, &paykore.CreateQRPaymentRequest{
WalletID: "merchant-wallet-uuid",
Amount: 500000,
Reference: "order_789",
ExpiresInSeconds: paykore.Int(300), // default 5 minutes
})
// qr.QRCode — base64-encoded QR image or payload string
// qr.ExpiresAt — show countdown to user

// Pay a QR request (payer side)
payment, err := client.Payments.PayQRPayment(ctx, &paykore.PayQRPaymentRequest{
QRReference: qr.Reference,
SourceWallet: "payer-wallet-uuid",
})

// Initiate a USSD payment
ussd, err := client.Payments.InitiateUSSDPayment(ctx, &paykore.InitiateUSSDPaymentRequest{
WalletID: "wallet-uuid",
Amount: 500000,
Reference: "order_789",
Phone: "+2348012345678", // E.164 format
})
// ussd.UssdCode — display to user e.g. "*123*456#"
// ussd.SessionID — use to poll status if needed
// ussd.ExpiresAt — 3-minute TTL

// Split payment across multiple wallets
splits, err := client.Payments.SplitPayment(ctx, &paykore.SplitPaymentRequest{
SourceWallet: "source-wallet-uuid",
Reference: "order_456",
Splits: []*paykore.SplitEntry{
{WalletID: "seller-wallet-uuid", Amount: 824000},
{WalletID: "platform-wallet-uuid", Amount: 176000},
},
})
// splits — []*Transaction, one per destination
MethodReturns
client.Payments.CreateQRPayment(ctx, req)(*CreateQRPaymentResponse, error)
client.Payments.PayQRPayment(ctx, req)(*Transaction, error)
client.Payments.InitiateUSSDPayment(ctx, req)(*InitiateUSSDPaymentResponse, error)
client.Payments.SplitPayment(ctx, req)([]*Transaction, error)

KYC

// Submit BVN — async, result arrives via kyc.verified or kyc.failed webhook
bvnResult, err := client.KYC.SubmitBVN(ctx, &paykore.SubmitBVNRequest{
UserRef: "user_123",
BVN: "22190000000",
})
// bvnResult.Status == "pending"

// Submit NIN
ninResult, err := client.KYC.SubmitNIN(ctx, &paykore.SubmitNINRequest{
UserRef: "user_123",
NIN: "12345678901",
})

// Get current KYC status for a user
status, err := client.KYC.GetKYCStatus(ctx, "user_123")
for _, v := range status.Verifications {
fmt.Printf("type=%s status=%s\n", v.Type, v.Status)
}
MethodReturns
client.KYC.SubmitBVN(ctx, req)(*SubmitVerificationResponse, error)
client.KYC.SubmitNIN(ctx, req)(*SubmitVerificationResponse, error)
client.KYC.GetKYCStatus(ctx, userRef)(*KYCStatusResponse, error)

Webhooks

// Register an endpoint
endpoint, err := client.Webhooks.CreateWebhook(ctx, &paykore.CreateWebhookRequest{
URL: "https://yourapp.com/webhooks/paykore",
Events: []string{
"transaction.completed",
"transaction.failed",
"wallet.activated",
"kyc.verified",
"kyc.failed",
},
})

// List registered endpoints
endpoints, err := client.Webhooks.ListWebhooks(ctx)

// Delete an endpoint
err = client.Webhooks.DeleteWebhook(ctx, "webhook-uuid")
MethodReturns
client.Webhooks.CreateWebhook(ctx, req)(*WebhookEndpoint, error)
client.Webhooks.ListWebhooks(ctx)([]*WebhookEndpoint, error)
client.Webhooks.DeleteWebhook(ctx, id)error

Error handling

All methods return a standard Go error. Cast to *core.APIError to inspect the code:

import (
"errors"
"github.com/paykore/paykore-go/core"
)

transfer, err := client.Transfers.P2PTransfer(ctx, req)
if err != nil {
var apiErr *core.APIError
if errors.As(err, &apiErr) {
switch apiErr.Body.Error {
case "INSUFFICIENT_FUNDS":
// show user their balance
case "VALIDATION_ERROR":
log.Printf("bad request: %s", apiErr.Body.Message)
default:
log.Printf("paykore: %s — %s (http %d)",
apiErr.Body.Error,
apiErr.Body.Message,
apiErr.StatusCode,
)
}
} else {
// network or timeout — retry with backoff
}
}
FieldTypeDescription
apiErr.StatusCodeintHTTP status code (e.g. 422).
apiErr.Body.ErrorstringMachine-readable code. Branch on this — it's stable across SDK versions.
apiErr.Body.MessagestringHuman-readable description. For logging only.

Raw response access

To read response headers (e.g. Retry-After on a 429), use .WithRawResponse:

rawResp, err := client.Wallets.WithRawResponse.CreateWallet(ctx, req)
if err != nil {
return err
}
retryAfter := rawResp.Header.Get("Retry-After")
wallet := rawResp.Body // *CreateWalletResponse

Next steps