BluePOS Go iOS SDK Operations Guide
This guide describes the operations available after integrating the SDK and callback handling. All SDK calls run through BluePosGoSDK.shared and complete when BluePOS Go returns to your app.
Use a distinct callback URL path and a fresh request ID per operation. Do not start the same operation while it is already pending; the SDK exposes is…InProgress properties and returns an in-progress error when applicable.
Building BasicToken and PaymentCredentials
PaymentCredentialsTo build your basic token for your SDK instance, please create your respective API key under your PayConex account ID and use the following code to generate the basic authentication. For more details, refer to API Authentication | Basic Authentication.
import Foundation
func buildBasicToken(apiKey: String, apiSecret: String) -> String {
let credentials = "\(apiKey):\(apiSecret)"
let encoded = Data(credentials.utf8).base64EncodedString()
return "Basic \(encoded)"
}
/// The credentials variable used throughout this iOS integration guidelines
private var credentials: PaymentCredentials {
PaymentCredentials(
basicToken: buildBasicToken(apiKey, apiSecret),
accountId: accountId.trimmingCharacters(in: .whitespacesAndNewlines),
environment: environment
)
}
Scope DefinitionsDepending on the operation you are running on your device, make sure to add the corresponding scope permissions to your API key being used.
For all the scope permissions, please refer to API Key Management | Scope Definitions.
Shared Credentials
NoteRefund operations require
PaymentCredentials. Payments may also include them. Obtain the token and account ID securely; never commit production credentials to your repository or log them.
let credentials = PaymentCredentials(
basicToken: credentialStore.basicToken,
accountId: credentialStore.accountId,
environment: "STAGING" // "STAGING", "CERT", or "PROD"
)Payment
Start a sale, authorization, or another supported PaymentTransactionType with startPayment. The result is one of .success, .cancelled, .declined, or .failure.
let request = PaymentRequest(
requestId: UUID().uuidString,
amount: Decimal(string: "19.99")!,
tip: Decimal(string: "2.00"),
transactionType: .sale, /// .sale | .auth
currency: "USD",
callbackURL: URL(string: "mymerchantapp://bluepos/payment")!,
customId: "ORDER-1001",
notes: "In-store sale",
credentials: PaymentCredentials(
basicToken: credentials.basicToken,
accountId: credentials.accountId,
environment: "STAGING"
),
requiresReaderReady: true
)
statusText = "Payment started. Waiting for BluePOS Go ..."
BluePosGo.shared.startPayment(request: request) { [weak self] result in
switch result {
case .success(let response):
self?.transactionId = response.transactionId ?? ""
self?.statusText = "Approved: \(response.transactionId ?? "")"
case .cancelled:
self?.statusText = "Customer cancelled"
case .declined(let response):
self?.statusText = "Declined: \(response.processorMessage ?? "")"
case .failure(let error, let response):
self?.statusText = "Payment error: \(error); status: \(response?.status ?? "")"
}
}The completion's PaymentResponse can include the request ID, status, processor message, approval code, transaction ID, and custom ID. Reconcile an approved payment on your backend; do not use the client callback as the only source of truth for an order.
Transaction list
Request available transactions, then retain the transaction ID needed for a follow-up capture or refund.
let request = TransactionListRequest(
requestId: UUID().uuidString,
callbackURL: URL(string: "mymerchantapp://bluepos/transactions")!
)
BluePosGoSDK.shared.getTransactionList(request: request) { result in
switch result {
case .success(let response):
for transaction in response.transactions {
print(transaction.transactionDetails.transactionId ?? "")
}
case .failure(let error, _):
print("Could not load transactions: \(error)")
}
}The callback must include a successful status and a transaction list. A response can also include transactionCount, error code, and error message.
Full refund
Use the original transaction ID. A full refund requires credentials and returns .success or .failure.
let request = FullRefundRequest(
requestId: UUID().uuidString,
transactionId: originalTransactionID,
callbackURL: URL(string: "mymerchantapp://bluepos/refund")!,
credentials: credentials
)
BluePosGoSDK.shared.fullRefund(request: request) { result in
if case .success(let response) = result {
print("Refunded: \(response.transactionId ?? originalTransactionID)")
}
}Do not allow a second full or partial refund while one refund is pending. Check eligibility and remaining refundable amount in your own backend before launching the SDK.
Partial refund
Partial refunds add a positive Decimal amount to the full-refund inputs.
let request = PartialRefundRequest(
requestId: UUID().uuidString,
transactionId: originalTransactionID,
amount: Decimal(string: "5.00")!,
callbackURL: URL(string: "mymerchantapp://bluepos/refund")!,
credentials: credentials
)
BluePosGoSDK.shared.partialRefund(request: request) { result in
// Handle .success or .failure and reconcile the result.
}Use a decimal value you calculate and validate in your payment domain. Do not infer the remaining refund balance solely from the client UI.
Capture an authorization
Capture requires the original authorization transaction ID and a non-empty amount string. Format the amount using a dot decimal separator, independent of device locale.
let amount = String(format: "%.2f", locale: Locale(identifier: "en_US_POSIX"), 19.99)
let request = CaptureRequest(
requestId: UUID().uuidString,
transactionId: authorizationTransactionID,
amount: amount,
callbackURL: URL(string: "mymerchantapp://bluepos/capture")!
)
BluePosGoSDK.shared.capture(request: request) { result in
// CaptureResult is .success(CaptureResponse) or .failure(CaptureError, response:).
}Clear-data read
Clear-data reads deliberately return sensitive cardholder fields. Request them only where your organization is authorized to receive clear cardholder data and already has an approved PCI-compliant handling path.
They are not part of the ordinary payment smoke test. Leave this call disabled unless it is separately included in an authorized handling workflow.
The sample below shows the request and result shape only. It is not a logging or diagnostics example. A real harness must not print PAN, Track 2, basic tokens, or a complete callback URL. Allowlist only non-sensitive fields, such as request id, amount, whether a timeout was set, and the result case name.
let request = ClearDataRequest(
requestId: UUID().uuidString,
callbackURL: URL(string: "mymerchantapp://bluepos/clear-data")!,
amount: Decimal(string: "19.99"),
timeout: nil
)
BluePosGo.shared.clearData(request: request) { result in
switch result {
case .success(let response):
let pan = response.clearPan
let track2 = response.clearTrack2
// Route these only through your approved PCI-compliant processing flow.
// Never log, display unnecessarily, or persist `pan` or `track2`.
case .masked:
// Completed, but clear data was not eligible.
break
case .cancelled:
break
case .failure:
// Present a user-facing error. Do not attach card data or the raw callback URL.
break
}
}ClearDataResult distinguishes a successful clear-data response, a masked response, cancellation, and failure. Never write PAN, Track 2, basic tokens, or complete callback URLs that may contain sensitive data to analytics or application logs.
Reboot the reader
Reboot power-cycles the IDTECH reader that is paired with BluePOS Go over Bluetooth LE. Use it when the reader stops responding and a payment, refund, capture, or clear-data request cannot recover it.
let request = RebootRequest(
requestId: UUID().uuidString,
callbackURL: URL(string: "mymerchantapp://bluepos/reboot")!
)
BluePosGoSDK.shared.reboot(request: request) { result in
switch result {
case .success(let response):
print("Reader rebooted: \(response.readerSerial ?? "unknown")")
case .failure(let error, let response):
print("Reboot failed: \(error); \(response?.errorMessage ?? "")")
}
}Only one reboot can be active at a time. RebootResponse.responseCode and readerSerial are populated by BluePOS Go when available; both are optional.
Error handling and cancellation
Every operation has a typed result and error enum. Error categories include invalid input, BluePOS Go not installed, an operation already in progress, invalid or mismatched callbacks, missing status, and operation-specific failures. Display a safe user-facing message and retain technical detail only in secure diagnostics.
If your screen is dismissed or the user abandons a flow, clear the appropriate pending operation so a new request can start:
func cancelPending() {
BluePosGo.shared.cancelPendingPayment()
BluePosGo.shared.cancelPendingInitialization()
BluePosGo.shared.cancelPendingTransactionList()
BluePosGo.shared.cancelPendingFullRefund()
BluePosGo.shared.cancelPendingPartialRefund()
BluePosGo.shared.cancelPendingCapture()
BluePosGo.shared.cancelPendingClearData()
BluePosGo.shared.cancelPendingReboot()
statusText = "Pending SDK operations cleared."
}Cancel only the flow your application actually owns.
cancelPending…() clears the SDK's local callback association for that request. It does not promise a cancellation, void, or refund at the processor level. A missing callback or abandoned flow stays unresolved until you reconcile it on the backend. Do not treat the cleared operation as failed, and do not fulfill or reverse it from the absence of a callback. Unique request IDs and/or correlationId correlate a request with its result. They are not documented gateway idempotency guarantees.
For more on trace and request ids and their use cases, please refer to API Endpoint Overview | Correlation Identifier and Debugging.
Production readiness
- Generate unguessable, unique request IDs and match them to the order in your backend.
- Never hard-code production Basic tokens or account IDs.
- Persist payment and refund outcomes only after server-side reconciliation.
- Test cancelled, declined, failed, and successful callbacks, including app switching and cold-return behavior.
- Validate transaction and refund eligibility on the server.
- Limit and protect access to cardholder data; clear-data reads may create PCI obligations.
Updated about 2 hours ago
