Offline Sync API Reference
API endpoints untuk batch synchronization dan conflict resolution dalam offline-first architecture.
π Authentication
Semua endpoint memerlukan JWT authentication token.
Authorization: Bearer YOUR_JWT_TOKEN
π‘ Endpoints
1. Batch Sync
Sync multiple transactions, payments, dan voids dalam satu request.
POST /api/v1/pos/offline/batch-sync
Content-Type: application/json
Authorization: Bearer YOUR_TOKEN
{
"transactions": [
{
"offline_id": "550e8400-e29b-41d4-a716-446655440000",
"offline_reference": "DEVICE001-20251013-001",
"device_id": "DEVICE001",
"created_at_device": "2025-10-13T10:30:00Z",
"branch_code": "BRN-MST-OSK00001",
"payment_method": "CASH",
"id_user_apps": 5,
"type_transaction": 1,
"subtotal": 30000,
"discount_total": 0,
"tax_total": 3000,
"grand_total": 33000,
"status": "paid",
"payment_status": "paid",
"sync_status": "pending"
}
],
"payments": [],
"voids": [],
"device_id": "DEVICE001",
"synced_at": "2025-10-13T11:00:00Z"
}
Request Body
Array of offline transactions to sync
UUID generated by client (v4)
Unique reference: DEVICE_ID-YYYYMMDD-SEQ
ISO 8601 timestamp when created on device
Branch code (e.g., βBRN-MST-OSK00001β)
Payment method: CASH, QRIS, GOPAY, OVO, DANA, etc.
Transaction type (1 = sales)
Transaction status: draft, paid, void
Payment status: pending_payment, paid, void
Array of offline payments to sync
Array of offline voids to sync
ISO 8601 timestamp when sync initiated
Response (Success)
Overall sync success status
Number of successful syncs
Array of sync results per item
Item type: transaction, payment, void
Server-generated ID (if success)
Server-generated transaction code
Error message (if failed)
Whether conflict was detected
Array of detected conflicts
Unique conflict identifier
Conflict type: transaction, payment, void
duplicate, data_mismatch, constraint_violation
Suggested resolution: keep_server, keep_local, merge
Server timestamp when sync completed
Response Example
{
"code": 200,
"data": {
"success": true,
"total_items": 1,
"success_count": 1,
"failed_count": 0,
"results": [
{
"offline_id": "550e8400-e29b-41d4-a716-446655440000",
"type": "transaction",
"success": true,
"server_id": 185,
"transaction_code": "TRX-MC01-BRN-MST-OSK00001-251013-5UJW-6SWG-7",
"error": null,
"conflict_detected": false
}
],
"conflicts": [],
"synced_at": "2025-10-13T11:00:05Z"
}
}
Response (With Conflict)
{
"code": 200,
"data": {
"success": true,
"total_items": 1,
"success_count": 0,
"failed_count": 1,
"results": [
{
"offline_id": "550e8400-e29b-41d4-a716-446655440000",
"type": "transaction",
"success": false,
"server_id": 185,
"transaction_code": "TRX-MC01-BRN-MST-OSK00001-251013-5UJW-6SWG-7",
"error": "Duplicate transaction detected",
"conflict_detected": true
}
],
"conflicts": [
{
"conflict_id": "550e8400-e29b-41d4-a716-446655440000",
"offline_id": "550e8400-e29b-41d4-a716-446655440000",
"type": "transaction",
"conflict_type": "duplicate",
"local_data": {
"offline_reference": "DEVICE001-20251013-001",
"grand_total": 33000
},
"server_data": {
"id": 185,
"transaction_code": "TRX-MC01-BRN-MST-OSK00001-251013-5UJW-6SWG-7",
"grand_total": 33000
},
"suggested_fix": "keep_server",
"resolution_url": "/api/v1/pos/offline/conflicts/550e8400-e29b-41d4-a716-446655440000/resolve"
}
],
"synced_at": "2025-10-13T11:00:05Z"
}
}
Error Responses
{
"code": 400,
"message": "Invalid request body",
"errors": [
{
"field": "transactions[0].offline_reference",
"message": "offline_reference is required"
}
]
}
2. Resolve Conflict
Resolve detected conflict dengan strategy tertentu.
POST /api/v1/pos/offline/conflicts/550e8400-e29b-41d4-a716-446655440000/resolve
Content-Type: application/json
Authorization: Bearer YOUR_TOKEN
{
"strategy": "keep_server"
}
Path Parameters
Conflict ID from batch sync response
Request Body
Resolution strategy:
keep_server: Keep server data, discard local
keep_local: Keep local data, overwrite server (not yet implemented)
merge: Merge both data (not yet implemented)
Required if strategy is βmergeβ
Response (Success)
{
"code": 200,
"data": {
"conflict_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "resolved",
"message": "Conflict resolved successfully",
"resolved_at": "2025-10-13T11:05:00Z"
}
}
Error Responses
{
"code": 404,
"message": "Conflict not found",
"error": "No conflict with ID: 550e8400-e29b-41d4-a716-446655440000"
}
π Sync Flow Diagram
π Rate Limiting
| Endpoint | Rate Limit | Window |
|---|
| Batch Sync | 10 requests | 1 minute |
| Resolve Conflict | 30 requests | 1 minute |
π‘ Best Practices
Batch Size
Limit batch size to 50 transactions per request untuk optimal performance.
Retry Logic
Implement exponential backoff untuk retry:
- 1st retry: 5 seconds
- 2nd retry: 10 seconds
- 3rd retry: 30 seconds
- Max retries: 3
Idempotency
Gunakan offline_reference sebagai idempotency key. Server akan detect duplicate dan return existing data.
Error Handling
try {
final response = await apiService.batchSync(request);
// Handle success
for (final result in response.results) {
if (result.success) {
await updateLocalTransaction(result);
} else {
await markAsFailed(result);
}
}
// Handle conflicts
if (response.conflicts.isNotEmpty) {
await showConflictDialog(response.conflicts);
}
} on DioException catch (e) {
if (e.response?.statusCode == 401) {
// Token expired, refresh and retry
await refreshToken();
return retry();
} else if (e.type == DioExceptionType.connectionTimeout) {
// Network timeout, queue for retry
await queueForRetry();
} else {
// Other errors
await logError(e);
}
}
π§ͺ Testing
Postman Collection
Download Postman collection: offline-sync-api.postman_collection.json
REST Client Examples
See complete examples in: api/pos/offline-sync.http
π Support