Tapsilat Go is a Go client library for accessing the Tapsilat API. It provides convenient access to Tapsilat's API from applications written in the Go language. You can create an order, get order, get order list, get order status, cancel order, refund order, and manage subscriptions.
go get github.com/tapsilat/tapsilat-gopackage main
import (
"github.com/tapsilat/tapsilat-go"
)
func main() {
// Create API client with your token
api := tapsilat.NewAPI("your_token_here")
// Or with custom endpoint
api := tapsilat.NewCustomAPI("https://custom.endpoint.com/api/v1", "your_token")
}Use this flow to validate newly added submerchant/vpos-related SDK APIs against local panel/backend.
- Start local stack from
panel/backend:
make compose-
Open
http://localhost:8080, login, and generate API key/secret. -
In
tapsilat-go, run local E2E script:
chmod +x scripts/local_e2e.sh
TAPSILAT_API_KEY="<ui_api_key>" \
TAPSILAT_API_SECRET="<ui_api_secret>" \
TAPSILAT_IT_SUBMERCHANT_ID="<submerchant_id>" \
TAPSILAT_IT_SUBORGANIZATION_ID="<suborganization_id>" \
scripts/local_e2e.shOptional:
- Reuse an existing token: set
TAPSILAT_API_TOKEN. - Start stack from script:
scripts/local_e2e.sh --start-stack. - Run only smoke:
scripts/local_e2e.sh --smoke-only. - Run only integration:
scripts/local_e2e.sh --integration-only. - Auto-create submerchant + resolve suborganization IDs before tests:
TAPSILAT_API_KEY="<ui_api_key>" \
TAPSILAT_API_SECRET="<ui_api_secret>" \
scripts/local_e2e.sh --bootstrap-submerchant- Auto-create VPOS + attach it to submerchant via
vpos-submerchantmapping:
TAPSILAT_API_KEY="<ui_api_key>" \
TAPSILAT_API_SECRET="<ui_api_secret>" \
scripts/local_e2e.sh --bootstrap-submerchant --bootstrap-vposThis writes IDs to /tmp/tapsilat_local_e2e_ids.env (override with BOOTSTRAP_OUTPUT_FILE).
BOOTSTRAP_CREATED_SUBMERCHANT_ID/BOOTSTRAP_CREATED_SUBORGANIZATION_ID: raw IDs created/discovered during bootstrap.BOOTSTRAP_CREATED_VPOS_ID/BOOTSTRAP_CREATED_VPOS_SUBMERCHANT_ID: raw VPOS and mapping IDs created during VPOS bootstrap.TAPSILAT_SMOKE_*andTAPSILAT_IT_*: effective IDs used for tests.
If reverse mapping is not yet consistent in backend, script continues with submerchant-only smoke assertions and leaves integration IDs empty instead of failing immediately.
Notes:
- Script sets
User-Agent: Go-http-client/1.1while generating token to match SDK request context and avoid local auth mismatch. - Integration test requires
TAPSILAT_IT_SUBMERCHANT_IDandTAPSILAT_IT_SUBORGANIZATION_ID; otherwise test code skips it.
All API methods require a context.Context parameter. This allows you to control request timeouts and cancellation:
import (
"context"
"time"
"github.com/tapsilat/tapsilat-go"
)
// Simple usage with Background context
response, err := api.CreateOrder(context.Background(), order)
// With timeout - request will be cancelled after 10 seconds
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
response, err := api.CreateOrder(ctx, order)
// With cancellation - you can cancel the request manually
ctx, cancel := context.WithCancel(context.Background())
go func() {
// Cancel after some condition
time.Sleep(5 * time.Second)
cancel()
}()
response, err := api.CreateOrder(ctx, order)package main
import (
"context"
"github.com/tapsilat/tapsilat-go"
)
func main() {
token := "TOKEN"
api := tapsilat.NewAPI(token)
order := tapsilat.Order{
Locale: "tr",
Currency: "TRY",
Amount: 5,
Buyer: tapsilat.OrderBuyer{
Id: "123456789",
Name: "John",
Surname: "Doe",
Email: "john@doe.com",
GsmNumber: "5555555555",
IdentityNumber: "12345678901",
RegistrationDate: "2023-01-01",
RegistrationAddress: "Istanbul",
LastLoginDate: "2023-01-01",
City: "Istanbul",
Country: "Türkiye",
ZipCode: "34000",
Ip: "127.0.0.1",
BirdthDate: "1990-01-01",
},
ShippingAddress: tapsilat.OrderShippingAddress{
Address: "Istanbul",
ZipCode: "34000",
City: "Istanbul",
Country: "Türkiye",
ContactName: "John Doe",
TrackingCode: "123456789",
},
BillingAddress: tapsilat.OrderBillingAddress{
Address: "Istanbul",
ZipCode: "34000",
City: "Istanbul",
Country: "Türkiye",
ContactName: "John Doe",
},
BasketItems: []tapsilat.OrderBasketItem{
{
Id: "1",
Name: "Product 1",
Price: 5,
Category1: "Category 1",
Category2: "Category 2",
ItemType: "VIRTUAL",
},
{
Id: "2",
Name: "Product 2",
Price: 5,
Category1: "Category 1",
Category2: "Category 2",
ItemType: "VIRTUAL",
},
},
}
response, err := api.CreateOrder(context.Background(), order)
if err != nil {
panic(err)
}
println("Order created successfully!")
println("Order ID:", response.OrderID)
println("Reference ID:", response.ReferenceID)
println("Checkout URL:", response.CheckoutURL)
}quantity := 2
basketItem := tapsilat.OrderBasketItem{
Id: "item_001",
Name: "Product Name",
Price: 50.0,
Quantity: &quantity,
ItemType: "PHYSICAL",
}
order := tapsilat.Order{
Locale: "tr",
Currency: "TRY",
Amount: 100.0,
BasketItems: []tapsilat.OrderBasketItem{basketItem},
Buyer: tapsilat.OrderBuyer{
Name: "John",
Surname: "Doe",
Email: "john@doe.com",
},
}amount1 := 50.0
required := true
sequence := 1
paymentTerm := tapsilat.OrderPaymentTerm{
Amount: &amount1,
DueDate: "2024-01-15",
Required: &required,
TermSequence: &sequence,
Status: "pending",
TermReferenceID: "term_ref_1",
}
order := tapsilat.Order{
Locale: "tr",
Currency: "TRY",
Amount: 100.0,
PaymentTerms: []tapsilat.OrderPaymentTerm{paymentTerm},
Buyer: tapsilat.OrderBuyer{
Name: "John",
Surname: "Doe",
Email: "john@doe.com",
},
}The SDK includes built-in validation for common fields:
// GSM Number Validation
cleanGSM, err := tapsilat.ValidateGSMNumber("+90 555 123-45-67")
if err != nil {
log.Fatal(err)
}
fmt.Println(cleanGSM) // Output: +905551234567
// Installments Validation
installments, err := tapsilat.ValidateInstallments("1,2,3,6")
if err != nil {
log.Fatal(err)
}
fmt.Println(installments) // Output: [1 2 3 6]When you create an order, the response automatically includes a checkout URL that you can use to redirect customers for payment:
response, err := api.CreateOrder(context.Background(), order)
if err != nil {
log.Fatal(err)
}
// Checkout URL is automatically included in the response
fmt.Printf("Order ID: %s\n", response.OrderID)
fmt.Printf("Reference ID: %s\n", response.ReferenceID)
fmt.Printf("Checkout URL: %s\n", response.CheckoutURL)
// You can also get the checkout URL separately if needed
checkoutURL, err := api.GetCheckoutURL(context.Background(), response.ReferenceID)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Checkout URL: %s\n", checkoutURL)package main
import (
"context"
"github.com/tapsilat/tapsilat-go"
)
func main() {
token := "TOKEN"
api := tapsilat.NewAPI(token)
order, err := api.GetOrder(context.Background(), "order_reference_id")
if err != nil {
panic(err)
}
println(order)
}package main
import (
"context"
"github.com/tapsilat/tapsilat-go"
)
func main() {
token := "TOKEN"
api := tapsilat.NewAPI(token)
orders, err := api.GetOrders(context.Background(), "page", "limit", "")
if err != nil {
panic(err)
}
println(orders)
}package main
import (
"context"
"github.com/tapsilat/tapsilat-go"
)
func main() {
token := "TOKEN"
api := tapsilat.NewAPI(token)
status, err := api.GetOrderStatus(context.Background(), "order_reference_id")
if err != nil {
panic(err)
}
println(status)
}package main
import (
"context"
"github.com/tapsilat/tapsilat-go"
)
func main() {
token := "TOKEN"
api := tapsilat.NewAPI(token)
payload := tapsilat.CancelOrder{
ReferenceID: "order_reference_id",
}
status, err := api.CancelOrder(context.Background(), payload)
if err != nil {
panic(err)
}
println(status)
}package main
import (
"context"
"github.com/tapsilat/tapsilat-go"
)
func main() {
token := "TOKEN"
api := tapsilat.NewAPI(token)
payload := tapsilat.RefundOrder{
ReferenceID: "order_reference_id",
Amount: "100",
}
status, err := api.RefundOrder(context.Background(), payload)
if err != nil {
panic(err)
}
println(status)
}package main
import (
"context"
"github.com/tapsilat/tapsilat-go"
)
func main() {
token := "TOKEN"
api := tapsilat.NewAPI(token)
subscription := tapsilat.SubscriptionCreateRequest{
Amount: 100.0,
Currency: "TRY",
Title: "Monthly Subscription",
Period: 30,
Cycle: 1,
PaymentDate: 1,
ExternalReferenceID: "ext_sub_123",
SuccessURL: "https://example.com/success",
FailureURL: "https://example.com/failure",
CardID: "card_token_123",
Billing: tapsilat.SubscriptionBilling{
Address: "Istanbul",
City: "Istanbul",
Country: "TR",
ZipCode: "34000",
ContactName: "John Doe",
VatNumber: "1234567890",
},
User: tapsilat.SubscriptionUser{
ID: "user_123",
FirstName: "John",
LastName: "Doe",
Email: "john@doe.com",
Phone: "5555555555",
IdentityNumber: "12345678901",
Address: "Istanbul",
City: "Istanbul",
Country: "TR",
ZipCode: "34000",
},
}
response, err := api.CreateSubscription(context.Background(), subscription)
if err != nil {
panic(err)
}
println("Subscription created successfully!")
println("Reference ID:", response.ReferenceID)
println("Order Reference ID:", response.OrderReferenceID)
}package main
import (
"context"
"github.com/tapsilat/tapsilat-go"
)
func main() {
token := "TOKEN"
api := tapsilat.NewAPI(token)
payload := tapsilat.SubscriptionGetRequest{
ReferenceID: "subscription_reference_id",
// Or use ExternalReferenceID: "ext_sub_123",
}
subscription, err := api.GetSubscription(context.Background(), payload)
if err != nil {
panic(err)
}
println("Subscription Title:", subscription.Title)
println("Amount:", subscription.Amount)
println("Is Active:", subscription.IsActive)
println("Payment Status:", subscription.PaymentStatus)
}package main
import (
"context"
"encoding/json"
"github.com/tapsilat/tapsilat-go"
)
func main() {
token := "TOKEN"
api := tapsilat.NewAPI(token)
// Get first page with 10 items per page
subscriptions, err := api.ListSubscriptions(context.Background(), 1, 10)
if err != nil {
panic(err)
}
println("Total subscriptions:", subscriptions.Total)
println("Total pages:", subscriptions.TotalPages)
// Convert rows to subscription items
if subscriptions.Rows != nil {
rowsJSON, _ := json.Marshal(subscriptions.Rows)
var items []tapsilat.SubscriptionListItem
json.Unmarshal(rowsJSON, &items)
for _, item := range items {
println("Subscription:", item.Title, "- Amount:", item.Amount, "- Status:", item.PaymentStatus)
}
}
}package main
import (
"context"
"github.com/tapsilat/tapsilat-go"
)
func main() {
token := "TOKEN"
api := tapsilat.NewAPI(token)
payload := tapsilat.SubscriptionCancelRequest{
ReferenceID: "subscription_reference_id",
// Or use ExternalReferenceID: "ext_sub_123",
}
err := api.CancelSubscription(context.Background(), payload)
if err != nil {
panic(err)
}
println("Subscription cancelled successfully!")
}package main
import (
"context"
"github.com/tapsilat/tapsilat-go"
)
func main() {
token := "TOKEN"
api := tapsilat.NewAPI(token)
payload := tapsilat.SubscriptionRedirectRequest{
SubscriptionID: "subscription_id",
}
response, err := api.RedirectSubscription(context.Background(), payload)
if err != nil {
panic(err)
}
println("Redirect URL:", response.URL)
}All API methods now require a context.Context as the first parameter for better control over request cancellation and timeouts.
CreateOrder(ctx context.Context, order Order) (OrderResponse, error)GetOrder(ctx context.Context, referenceID string) (OrderDetail, error)GetOrderByConversationID(ctx context.Context, conversationID string) (OrderDetail, error)GetOrderStatus(ctx context.Context, referenceID string) (OrderStatus, error)GetOrders(ctx context.Context, page, perPage, buyerID string) (PaginatedData, error)GetOrderList(ctx context.Context, page, perPage int, startDate, endDate, organizationID, relatedReferenceID string) (PaginatedData, error)GetOrderSubmerchants(ctx context.Context, page, perPage int) (PaginatedData, error)GetCheckoutURL(ctx context.Context, referenceID string) (string, error)
RefundOrder(ctx context.Context, refund RefundOrder) (RefundCancelOrderResponse, error)RefundAllOrder(ctx context.Context, referenceID string) (RefundCancelOrderResponse, error)CancelOrder(ctx context.Context, cancel CancelOrder) (RefundCancelOrderResponse, error)
CreateOrderTerm(ctx context.Context, term OrderPaymentTermCreateDTO) (map[string]interface{}, error)UpdateOrderTerm(ctx context.Context, term OrderPaymentTermUpdateDTO) (map[string]interface{}, error)GetOrderTerm(ctx context.Context, termReferenceID string) (map[string]interface{}, error)DeleteOrderTerm(ctx context.Context, orderID, termReferenceID string) (map[string]interface{}, error)RefundOrderTerm(ctx context.Context, term OrderTermRefundRequest) (map[string]interface{}, error)
CreateSubscription(ctx context.Context, subscription SubscriptionCreateRequest) (SubscriptionCreateResponse, error)GetSubscription(ctx context.Context, payload SubscriptionGetRequest) (SubscriptionDetail, error)ListSubscriptions(ctx context.Context, page, perPage int) (PaginatedData, error)CancelSubscription(ctx context.Context, payload SubscriptionCancelRequest) errorRedirectSubscription(ctx context.Context, payload SubscriptionRedirectRequest) (SubscriptionRedirectResponse, error)
GetOrderTransactions(ctx context.Context, referenceID string) (map[string]interface{}, error)GetOrderPaymentDetails(ctx context.Context, referenceID, conversationID string) (map[string]interface{}, error)OrderTerminate(ctx context.Context, referenceID string) (map[string]interface{}, error)OrderManualCallback(ctx context.Context, referenceID, conversationID string) (map[string]interface{}, error)OrderRelatedUpdate(ctx context.Context, referenceID, relatedReferenceID string) (map[string]interface{}, error)GetOrganizationCurrencies(ctx context.Context) (OrganizationCurrenciesResponse, error)GetOrganizationSettings(ctx context.Context) (OrganizationSettings, error)
CreateSubmerchant(ctx context.Context, payload SubmerchantCreateRequest) (SubmerchantMutationResponse, error)GetSubmerchant(ctx context.Context, id string) (Submerchant, error)ListSubmerchants(ctx context.Context, page, perPage int) (SubmerchantListResponse, error)UpdateSubmerchant(ctx context.Context, id string, payload SubmerchantUpdateRequest) (SubmerchantMutationResponse, error)DeleteSubmerchant(ctx context.Context, id string) (SubmerchantMutationResponse, error)GetSuborganizations(ctx context.Context, page, perPage int) (SuborganizationListResponse, error)GetSuborganization(ctx context.Context, id string) (SuborganizationListItem, error)GetSuborganizationDetail(ctx context.Context, id string) (SuborganizationDetail, error)GetSuborganizationBySubmerchant(ctx context.Context, submerchantID string) (SubmerchantSuborganizationMapping, error)GetSubmerchantBySuborganization(ctx context.Context, suborganizationID string) (SuborganizationSubmerchantMapping, error)ListVpos(ctx context.Context, page, perPage int) (VposListResponse, error)ListVposWithFilter(ctx context.Context, page, perPage int, filter VposListFilter) (VposListResponse, error)CreateVpos(ctx context.Context, payload VposCreateRequest) (VposMutationResponse, error)GetVpos(ctx context.Context, id string) (Vpos, error)UpdateVpos(ctx context.Context, id string, payload VposUpdateRequest) (VposMutationResponse, error)DeleteVpos(ctx context.Context, id string) (VposMutationResponse, error)ListVposAcquirers(ctx context.Context) (VposAcquirerListResponse, error)ListCardSchemes(ctx context.Context) (CardSchemeListResponse, error)ListVposSubmerchants(ctx context.Context, page, perPage int, vposID, externalReferenceID string) (VposSubmerchantListResponse, error)CreateVposSubmerchant(ctx context.Context, payload VposSubmerchantCreateRequest) (VposSubmerchantMutationResponse, error)GetVposSubmerchant(ctx context.Context, id string) (VposSubmerchant, error)UpdateVposSubmerchant(ctx context.Context, id string, payload VposSubmerchantUpdateRequest) (VposSubmerchantMutationResponse, error)DeleteVposSubmerchant(ctx context.Context, id string) (VposSubmerchantMutationResponse, error)
SubmerchantCreateRequest.CurrencyID, SubmerchantUpdateRequest.CurrencyID, VposCreateRequest.Currencies, and VposUpdateRequest.Currencies accept either canonical currency UUIDs or organization currency_unit values such as TRY/USD. The SDK resolves non-UUID refs to UUIDs before sending requests.
# Run all tests
make test
# Run only unit tests
make test-unit
# Run only integration tests (requires TAPSILAT_TOKEN)
make test-integration
# Run smoke tests against local/sandbox panel
make test-smoke
# Run tests with coverage
make test-coverage
# Run specific test groups
make test-validators
make test-orders
make test-apiFor integration tests, set backend verification environment variables:
export TAPSILAT_IT_ENDPOINT=http://localhost:3001/api/v1
export TAPSILAT_IT_TOKEN=your_token_here
export TAPSILAT_IT_SUBMERCHANT_ID=your_submerchant_id
export TAPSILAT_IT_SUBORGANIZATION_ID=your_suborganization_id
export TAPSILAT_IT_VPOS_ID=optional_vpos_id
go test -v ./tests/integration -run TestBackendConsistency_SubmerchantSuborganizationAndScopedVposThis integration test validates real backend behavior via SDK calls:
- submerchant <-> suborganization mapping consistency (both directions)
- suborganization-scoped VPOS listing consistency
- optional
vpos_idread +ListVposSubmerchantsscope validation
For smoke tests, set endpoint/token (and optionally sample ids):
export TAPSILAT_SMOKE_ENDPOINT=http://localhost:3001/api/v1
export TAPSILAT_SMOKE_TOKEN=your_token_here
export TAPSILAT_SMOKE_SUBMERCHANT_ID=
export TAPSILAT_SMOKE_VPOS_ID=
export TAPSILAT_SMOKE_SUBORGANIZATION_ID=
make test-smokeWhen optional IDs are provided, smoke coverage also verifies:
- submerchant <-> suborganization mapping reads
- scoped
ListVposWithFilter(..., VposListFilter{SuborganizationID: ...}) ListVposSubmerchantsfiltered byvpos_id
# Setup development environment
make dev-setup
# This will:
# 1. Download dependencies
# 2. Create .env file from .env.example
# 3. Set up the project for developmenttapsilat-go/
├── tapsilat.go # Main API client
├── dtos.go # Data transfer objects
├── validators.go # Input validation functions
├── tests/
│ ├── unit/ # Unit tests
│ │ ├── validators_test.go
│ │ ├── order_test.go
│ │ └── api_test.go
│ └── integration/ # Integration tests
│ └── integration_test.go
│ └── smoke/ # Local/sandbox smoke tests
│ └── smoke_test.go
├── Makefile # Build and test commands
├── .env.example # Environment variables template
└── README.md
The SDK provides structured error handling:
response, err := api.CreateOrder(context.Background(), order)
if err != nil {
var validationErr *tapsilat.ValidationError
if errors.As(err, &validationErr) {
fmt.Printf("Validation Error: %s (Code: %d)\n", validationErr.Message, validationErr.Code)
return
}
var apiErr *tapsilat.APIError
if errors.As(err, &apiErr) {
fmt.Printf("API Error: status=%d code=%s message=%s raw=%s\n",
apiErr.StatusCode,
apiErr.Code,
apiErr.Message,
apiErr.RawBody,
)
return
}
fmt.Printf("Unexpected Error: %s\n", err.Error())
return
}APIError normalizes HTTP/API failures into these fields:
StatusCode: HTTP status codeStatus: API status field if present, otherwise HTTP status textCode: API error code if presentMessage: APImessageorerrorfield if presentRawBody: original response body for fallback debugging
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Run tests (
make test) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.