Data Models
iOS SDK: Data Models
Reference guide for the core data structures used throughout the Digital Card Engine SDK.
CardEntity
The primary model representing a complete card with all associated data.
public class CardEntity: Codable {
public let receivedCard: ReceivedCard
public let cardArt: String?
public let isReceiver: Bool?
public let transactionHistory: [Transaction]?
public let events: [CardEvent]?
public let assetType: AssetType?
public let metadata: CardMetadata?
}Properties
| Property | Type | Optional | Description |
|---|---|---|---|
receivedCard | ReceivedCard | No | Core card information (ID, balance, PAN, etc.) |
cardArt | String? | Yes | Base64-encoded image of the card front |
isReceiver | Bool? | Yes | Whether the current user is the card receiver |
transactionHistory | [Transaction]? | Yes | List of transactions (fetched separately via getTransactionHistory) |
events | [CardEvent]? | Yes | Card lifecycle events (fetched separately) |
assetType | AssetType? | Yes | Type categorization for the card |
metadata | CardMetadata? | Yes | Additional extensible metadata |
Usage
// Fetch cards
Task {
do {
let cards: [CardEntity] = try await sdk.getCards()
// Access card details
if let card = cards.first {
let label = card.receivedCard.cardLabel
let balance = card.receivedCard.balance
let last4 = card.receivedCard.last4
}
} catch {
print("Error fetching cards: \(error)")
}
}ReceivedCard
Core card information including identifiers, balance, and cardholder details.
public class ReceivedCard: Codable {
public let giftCardId: String
public let expiryDate: String
public let cardArtId: String
public let balance: Double?
public let name: String?
public let lastName: String?
public let last4: String?
public let message: CardMessage?
public let status: ActivationStatus?
public let cardLabel: String?
}Properties
| Property | Type | Optional | Description |
|---|---|---|---|
giftCardId | String | No | Unique card identifier |
expiryDate | String | No | Expiration date (ISO 8601 format) |
cardArtId | String | No | ID to fetch card artwork |
balance | Double? | Yes | Current card balance |
name | String? | Yes | Cardholder first name |
lastName | String? | Yes | Cardholder last name |
last4 | String? | Yes | Last 4 digits of PAN |
message | CardMessage? | Yes | Optional card message/greeting |
status | ActivationStatus? | Yes | Card activation status |
cardLabel | String? | Yes | Display name for the card |
Usage
let receivedCard = cardEntity.receivedCard
// Display card label
let displayName = receivedCard.cardLabel ?? receivedCard.giftCardId
// Format masked PAN
let maskedPan = receivedCard.last4.map { "•••• \($0)" } ?? "N/A"
// Format balance
let formattedBalance = receivedCard.balance.map {
String(format: "$%.2f", $0)
} ?? "N/A"Transaction
Represents a single card transaction.
public class Transaction: Codable {
public let transactionType: TransactionType
public let merchantCategoryCode: String?
public let transactionDate: String
public let transactionAmount: Double
public let transactionId: String?
public let transactionDescription: String
}Properties
| Property | Type | Optional | Description |
|---|---|---|---|
transactionType | TransactionType | No | Transaction type enum (see below) |
merchantCategoryCode | String? | Yes | Merchant category code (MCC) |
transactionDate | String | No | Transaction date/time (ISO date-time format) |
transactionAmount | Double | No | Absolute transaction amount |
transactionId | String? | Yes | Unique transaction identifier |
transactionDescription | String | No | Description or merchant name |
TransactionType
public enum TransactionType: String, Codable {
case load = "LOAD"
case deduction = "DEDUCTION"
case authorisation = "AUTHORISATION"
}Usage
// Fetch transactions
Task {
do {
let result = try await sdk.getTransactionHistory(card: card)
let transactions = result?.transactionHistory ?? []
// Display transaction
transactions.forEach { txn in
print("\(txn.transactionAmount) on \(txn.transactionDate): \(txn.transactionDescription)")
}
// Filter by type
let loads = transactions.filter { $0.transactionType == .load }
let deductions = transactions.filter { $0.transactionType == .deduction }
} catch {
print("Error: \(error)")
}
}CardEvent
Represents a lifecycle or activity event for a card.
public class CardEvent: Codable {
public let eventTime: String
public let eventType: CardEventType
public let initialBalance: Double
}Properties
| Property | Type | Optional | Description |
|---|---|---|---|
eventTime | String | No | Event date/time (ISO 8601) |
eventType | CardEventType | No | Type enum (see below) |
initialBalance | Double | No | Card balance at the time of the event |
CardEventType
public enum CardEventType: String, Codable {
case purchased = "PURCHASED"
case fundsLoaded = "FUNDS_LOADED"
case sent = "SENT"
case activated = "ACTIVATED"
case declined = "DECLINED"
case expired = "EXPIRED"
}Usage
// Fetch events (events come with transaction history)
Task {
do {
let cardWithEvents = try await sdk.getTransactionHistory(card: card)
let events = cardWithEvents?.events ?? []
// Display recent events
events.prefix(5).forEach { event in
print("\(event.eventType.rawValue) at \(event.eventTime): balance=\(event.initialBalance)")
}
// Filter by type
let fundsLoaded = events.filter { $0.eventType == .fundsLoaded }
let activations = events.filter { $0.eventType == .activated }
} catch {
print("Error: \(error)")
}
}CardMessage
Optional message attached to a card (e.g., gift card greeting).
public class CardMessage: Codable {
public let receiver: String
public let text: String
}Properties
| Property | Type | Optional | Description |
|---|---|---|---|
receiver | String | No | Receiver name/greeting |
text | String | No | Message text |
Usage
if let message = cardEntity.receivedCard.message {
print("To: \(message.receiver)")
print(message.text)
}ActivationStatus
Card activation/lifecycle status.
public enum ActivationStatus: String, Codable {
case sent = "sent"
case activated = "ACTIVE"
case declined = "declined"
case expired = "expired"
case inActivation = "IN_ACTIVATION"
case notActivated = "NOT_ACTIVATED"
case rejected = "REJECTED"
case inProgress = "IN_PROGRESS"
case failed = "FAILED"
case blocked = "BLOCKED"
}Usage
let status = cardEntity.receivedCard.status
switch status {
case .activated:
showCard()
case .blocked:
showLockedState()
case .expired:
showExpiredMessage()
case .declined, .rejected, .failed:
showErrorState()
default:
showPendingState()
}AssetType
Categorization for different card types.
public enum AssetType: String, Codable {
case order = "ORDER"
case giftCard = "GIFT_CARD"
}CardMetadata
Pagination metadata for card transactions and events.
public class CardMetadata: Codable {
public let page: Int
public let totalPages: Int
public let totalElements: Int
public let hasNext: Bool
}Properties
| Property | Type | Optional | Description |
|---|---|---|---|
page | Int | No | Current page number |
totalPages | Int | No | Total number of pages available |
totalElements | Int | No | Total number of elements across pages |
hasNext | Bool | No | Whether more pages are available |
Usage
if let metadata = cardEntity.metadata {
print("Page \(metadata.page) of \(metadata.totalPages)")
print("Total elements: \(metadata.totalElements)")
if metadata.hasNext {
// Load next page
}
}Complete Example
import SwiftUI
struct CardDetailsExample: View {
let sdk: DigitalCardEngine
@State private var cards: [CardEntity] = []
@State private var isLoading = false
@State private var errorMessage: String?
var body: some View {
VStack {
if isLoading {
ProgressView("Loading cards...")
} else if let error = errorMessage {
Text("Error: \(error)")
.foregroundColor(.red)
} else {
List(cards, id: \.receivedCard.giftCardId) { card in
CardRow(card: card)
}
}
}
.task {
await loadCards()
}
}
func loadCards() async {
isLoading = true
errorMessage = nil
do {
// Fetch all cards
cards = try await sdk.getCards()
// Process first card
if let card = cards.first {
let receivedCard = card.receivedCard
print("Card: \(receivedCard.cardLabel ?? "Unknown")")
print("Balance: \(receivedCard.balance ?? 0)")
print("Last 4: \(receivedCard.last4 ?? "N/A")")
print("Status: \(receivedCard.status?.rawValue ?? "Unknown")")
// Fetch transactions and events (they come together)
let result = try await sdk.getTransactionHistory(card: card)
result?.transactionHistory?.forEach { txn in
print("\(txn.transactionType.rawValue): \(txn.transactionAmount) on \(txn.transactionDate)")
}
// Fetch events (included in transaction history result)
result?.events?.forEach { event in
print("\(event.eventType.rawValue) at \(event.eventTime): balance=\(event.initialBalance)")
}
}
} catch {
errorMessage = error.localizedDescription
}
isLoading = false
}
}
struct CardRow: View {
let card: CardEntity
var body: some View {
VStack(alignment: .leading) {
Text(card.receivedCard.cardLabel ?? card.receivedCard.giftCardId)
.font(.headline)
if let balance = card.receivedCard.balance {
Text(String(format: "$%.2f", balance))
.font(.subheadline)
}
if let last4 = card.receivedCard.last4 {
Text("•••• \(last4)")
.font(.caption)
.foregroundColor(.secondary)
}
}
}
}Nullability Guidelines
Many properties are optional to accommodate:
- Partial API responses: Backend may not always return all fields
- Progressive loading: Data fetched incrementally (e.g., transactions loaded separately)
- Optional features: Not all cards have messages, metadata, etc.
Always use optional binding (if let, guard let) or optional chaining (?.) when accessing optional properties.
Type Conversions
Date Formatting
import Foundation
func formatTransactionDate(_ isoDateTime: String) -> String {
let formatter = ISO8601DateFormatter()
guard let date = formatter.date(from: isoDateTime) else {
return isoDateTime
}
let displayFormatter = DateFormatter()
displayFormatter.dateFormat = "MMM dd, yyyy HH:mm"
return displayFormatter.string(from: date)
}
// Usage
let displayDate = formatTransactionDate(transaction.transactionDate)Currency Formatting
func formatAmount(_ amount: Double, currencyCode: String = "USD") -> String {
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.currencyCode = currencyCode
return formatter.string(from: NSNumber(value: amount)) ?? "$0.00"
}
// Usage
let displayAmount = formatAmount(transaction.transactionAmount)Updated 3 months ago
