### Complete Integration Example - Entrupy SDK Source: https://developer.entrupy.com/docs/mobile-sdks/android/integration-guide/core-authentication-workflow/performing-an-authentication This example demonstrates the full authentication and capture workflow, including authorization checks, metadata preparation, and starting the capture process with a callback. ```kotlin import com.entrupy.sdk.app.EntrupyApp import com.entrupy.sdk.listeners.CaptureCallback import com.entrupy.sdk.model.ConfigMetadata import com.entrupy.sdk.model.ProductCategory class CaptureManager { private val entrupyApp = EntrupyApp.sharedInstance() fun startAuthentication( brandId: String, category: ProductCategory, customerItemId: String? ) { // Step 1: Check authorization if (!entrupyApp.isAuthorizationValid()) { // Trigger re-authorization flow onAuthorizationRequired() return } // Step 2: Prepare metadata val metadata = ConfigMetadata( brandId = brandId, productCategory = category, customerItemId = customerItemId ) // Step 3: Start capture entrupyApp.startCapture( configMetadata = metadata, callback = object : CaptureCallback { override fun onCaptureStarted() { Log.d("Entrupy", "Capture started for brand: $brandId") } override fun onCaptureError(errorCode: Int, description: String) { handleCaptureError(description) } } ) } private fun handleCaptureError(description: String) { showErrorToUser(description) } private fun onAuthorizationRequired() { // Navigate to authorization flow } private fun showErrorToUser(message: String) { // Display error in UI } } ``` -------------------------------- ### Start Capture with Metadata and Callback Source: https://developer.entrupy.com/docs/mobile-sdks/android/integration-guide/core-authentication-workflow/performing-an-authentication Start the capture flow with detailed item metadata and a CaptureCallback to handle events like success or errors. Ensure authorization is valid before starting. ```kotlin import com.entrupy.sdk.app.EntrupyApp import com.entrupy.sdk.listeners.CaptureCallback import com.entrupy.sdk.model.ConfigMetadata import com.entrupy.sdk.model.ProductCategory val entrupyApp = EntrupyApp.sharedInstance() if (!entrupyApp.isAuthorizationValid()) { // Re-authorize first performUserAuthorization() return } val metadata = ConfigMetadata( brandId = "nike", productCategory = ProductCategory.Sneakers, customerItemId = "INTERNAL_SKU_12345" ) entrupyApp.startCapture( configMetadata = metadata, callback = object : CaptureCallback { override fun onCaptureStarted() { Log.d("Entrupy", "Capture UI launched successfully") } override fun onCaptureError(errorCode: Int, description: String) { Log.e("Entrupy", "Capture failed to start: $description (Code: $errorCode)") // Handle error appropriately showError(description) } } ) ``` -------------------------------- ### Start Simple Capture Source: https://developer.entrupy.com/docs/mobile-sdks/android/integration-guide/core-authentication-workflow/performing-an-authentication Initiate the capture flow without specific metadata. This uses the first available configuration and bypasses customerItemId tracking. ```kotlin import com.entrupy.sdk.app.EntrupyApp val entrupyApp = EntrupyApp.sharedInstance() if (entrupyApp.isAuthorizationValid()) { entrupyApp.startCapture() } else { // Re-authorize first performUserAuthorization() } ``` -------------------------------- ### Entrupy SDK Integration Test Example Source: https://developer.entrupy.com/docs/mobile-sdks/android/backend-and-advanced-considerations/development-testing-and-sample-app Example integration test for the complete Entrupy SDK authentication flow, including initialization, authorization, and login. ```kotlin import com.entrupy.sdk.app.EntrupyApp import com.entrupy.sdk.listeners.SdkLoginCallback // Example integration test @RunWith(AndroidJUnit4::class) class EntrupyIntegrationTest { @Test fun testCompleteAuthenticationFlow() { // 1. Initialize SDK EntrupyApp.init(ApplicationProvider.getApplicationContext()) // 2. Authorize user val entrupyApp = EntrupyApp.sharedInstance() val authRequest = entrupyApp.generateSDKAuthorizationRequest() val signedRequest = callBackendForAuthorization(authRequest) // 3. Login to SDK var loginSuccess = false entrupyApp.loginUser(signedRequest, object : SdkLoginCallback { override fun onLoginStarted() { Log.d("Test", "Login started") } override fun onLoginSuccess(expirationTime: Long) { loginSuccess = true } override fun onLoginError( errorCode: Int, description: String, localizedDescription: String ) { fail("Login failed: $description") } }) // 4. Verify authorization assertTrue(entrupyApp.isAuthorizationValid()) // 5. Test capture flow (if needed) // Note: This would require a real device or emulator with camera } } ``` -------------------------------- ### Fetching Configuration Source: https://developer.entrupy.com/docs/mobile-sdks/ios/sdk-reference/view-model-guides/capture-flow-ui Optionally pre-fetch SDK configuration to potentially reduce latency when starting a capture or search. This is not mandatory. ```APIDOC ## Fetching Configuration (Optional Optimization) To potentially reduce latency when starting a capture or search, you can optionally pre-fetch SDK configuration. This is not mandatory, as the SDK will fetch it implicitly if needed, but doing so earlier (e.g., in `viewDidAppear`) can provide a slight performance benefit. ```swift // Swift // In your ViewController, e.g., in viewDidAppear if EntrupyApp.sharedInstance().isAuthorizationValid() { EntrupyApp.sharedInstance().configDelegate = self // Conform to EntrupyConfigDelegate // Use .ConfigTypeProduction for release builds. // .ConfigTypeDebug provides a shorter workflow for development (results will be Invalid). EntrupyApp.sharedInstance().fetchConfigurationType(EntrupyConfigType.ConfigTypeProduction) } ``` ``` -------------------------------- ### Applying Filters Example Source: https://developer.entrupy.com/docs/mobile-sdks/ios/sdk-reference/direct-access-api-guides/programmatic-search-items Demonstrates how to combine multiple filters and values within filters to construct a precise search query. ```APIDOC ## Applying Filters Filters are combined using **AND** logic. Multiple values within a single filter type use **OR** logic. ### Example To find items that are either authentic or under review, AND belong to the luxury category: ```swift let query = EntrupySearchQuery( filters: [ .status([.authentic, .underReview]), // OR logic within status filter .category([.luxury]) // AND logic between status and category filters ] ) // Ensure the category filter is always included as it's required. ``` ### Status Filter Options | Status | Description | |---------------|--------------------------| | `.authentic` | Item is authentic | | `.underReview`| Item is under review | | `.invalid` | Invalid submission | | `.notSupported`| Item type not supported | | `.unidentified`| Cannot be identified | | `.other(String)`| Custom status value | ### Category Filter Options | Category | Description | |---------------|--------------------------| | `.luxury` | Luxury goods | | `.apparel` | Apparel items | | `.sneakers` | Sneakers | | `.other(String)`| Custom category | ### Brands Filter Example To filter for items from specific brands: ```swift query.filters.append(.brands(["louis_vuitton", "chanel"])) ``` ``` -------------------------------- ### Luxury Item Metadata Example Source: https://developer.entrupy.com/docs/mobile-sdks/ios/sdk-reference/view-model-guides/capture-flow-ui Provides an example of how to structure metadata for a luxury item, including required fields like 'product_category' and 'brand', and optional fields like 'material' and 'customer_item_id'. ```swift func luxuryItemMetadata() -> [String: Any] { [ "product_category": "luxury", "brand": "Louis Vuitton", "material": "Monogram Canvas", "customer_item_id": "LV-NEVERFULL-MM-001" // "capture_workflow": "authentication" // Optional, defaults to "authentication" ] } ``` -------------------------------- ### Usage Example: Setting Delegate and Calling API Source: https://developer.entrupy.com/docs/mobile-sdks/ios/sdk-reference/direct-access-api-guides/fetch-market-edge-for-item Before calling `fetchMarketEdgeForItem`, ensure the `marketEdgeDelegate` is set to `self`. This example shows how to set the delegate and then call the API with an `entrupyId`. ```swift // 1. Set delegate entrupyApp.marketEdgeDelegate = self // 2. Call API (e.g. after user provides entrupyId) entrupyApp.fetchMarketEdgeForItem(withEntrupyID: entrupyId) ``` -------------------------------- ### Start Capture with Metadata Only Source: https://developer.entrupy.com/docs/mobile-sdks/android/integration-guide/core-authentication-workflow/performing-an-authentication Initiate the capture flow by providing only ConfigMetadata, without a specific callback for handling events. ```kotlin val metadata = ConfigMetadata( brandId = "gucci", productCategory = ProductCategory.Luxury ) entrupyApp.startCapture(configMetadata = metadata) ``` -------------------------------- ### Webhook Implementation Example (Node.js) Source: https://developer.entrupy.com/docs/mobile-sdks/android/backend-and-advanced-considerations/essential-backend-integration-tasks This example demonstrates how to set up a webhook endpoint in Node.js to receive and process events from Entrupy, including signature verification and event type handling. ```APIDOC ## POST /api/entrupy/webhooks ### Description Receives webhook events from Entrupy. It verifies the signature and processes different event types like 'authentication.completed', 'authentication.failed', and 'authentication.requires_action'. ### Method POST ### Endpoint /api/entrupy/webhooks ### Request Body - **event_type** (string) - Required - The type of event that occurred. - **...other event-specific fields** ### Request Example ```json { "event_type": "authentication.completed", "item_id": "evt_12345", "customer_item_id": "cust_abcde", "result": "authentic", "certificate_url": "https://entrupy.com/certificate/12345" } ``` ### Response #### Success Response (200) - **received** (boolean) - Indicates if the webhook was successfully received and processed. #### Response Example ```json { "received": true } ``` #### Error Response (401) - **error** (string) - "Invalid signature" #### Error Response (500) - **error** (string) - "Webhook processing failed" ``` -------------------------------- ### Conceptual Swift Examples for Support Messaging Source: https://developer.entrupy.com/docs/mobile-sdks/ios/sdk-reference/direct-access-api-guides/programmatic-customer-support These are fictional examples demonstrating how Entrupy SDK *might* provide programmatic access to support message functionalities. Verify actual SDK methods and adapt accordingly. Ensure UI updates are performed on the main thread. ```swift // Swift - Conceptual Examples (Verify Actual SDK Methods) let entrupyIdForSupport = "abc123xyz" // 1. Fetching Support Message History (Conceptual) /* EntrupySDK.shared.fetchSupportMessages(entrupyId: entrupyIdForSupport) { result in // Fictional method DispatchQueue.main.async { switch result { case .success(let messages): // 'messages' would likely be an array of message objects // Each message might have properties like: text, sender, timestamp, type (user/support) // Update your custom chat UI with these messages messages.forEach { message in // print("Message from \(message.sender): \(message.text)") } print("Support messages fetched for \(entrupyIdForSupport).") case .failure(let error): print("Failed to load support messages for \(entrupyIdForSupport): \(error.localizedDescription)") } } } */ // 2. Listing Available Structured Responses (Conceptual) // The Detail View often allows users to pick from predefined questions or responses. // A programmatic equivalent might fetch these available choices. /* EntrupySDK.shared.getAvailableSupportResponses(entrupyId: entrupyIdForSupport) { result in // Fictional method DispatchQueue.main.async { switch result { case .success(let responseOptions): // 'responseOptions' would be an array of structs/objects, each with an ID and display text // Populate your UI (e.g., a picker or list) with these options responseOptions.forEach { option in // print("Available response: \(option.displayText) (ID: \(option.id))") } case .failure(let error): print("Failed to get available support responses for \(entrupyIdForSupport): \(error.localizedDescription)") } } } */ // 3. Sending a Structured Support Response (Conceptual) /* let chosenResponseId = "user_needs_help_with_retake" // Example ID selected by user from available options EntrupySDK.shared.sendSupportResponse(entrupyId: entrupyIdForSupport, responseId: chosenResponseId) { result in // Fictional method DispatchQueue.main.async { switch result { case .success: print("Successfully sent support response '\(chosenResponseId)' for \(entrupyIdForSupport).") // Optionally, refresh the message history case .failure(let error): print("Failed to send support response for \(entrupyIdForSupport): \(error.localizedDescription)") } } } */ ``` -------------------------------- ### Entrupy SDK Unit Test Example Source: https://developer.entrupy.com/docs/mobile-sdks/android/backend-and-advanced-considerations/development-testing-and-sample-app Example unit test for Entrupy SDK integration, demonstrating mocking and validation of authorization requests and configuration metadata. ```kotlin import com.entrupy.sdk.app.EntrupyApp import com.entrupy.sdk.model.ConfigMetadata import com.entrupy.sdk.model.ProductCategory // Example unit test class EntrupyAppTest { @Test fun testUserAuthorization() { // Mock SDK responses val mockApp = mock() whenever(mockApp.generateSDKAuthorizationRequest()).thenReturn("test_request") // Test authorization flow val authRequest = mockApp.generateSDKAuthorizationRequest() assertEquals("test_request", authRequest) } @Test fun testConfigMetadataValidation() { val validMetadata = ConfigMetadata( brandId = "nike", productCategory = ProductCategory.Sneakers, customerItemId = "test_123" ) assertTrue(isValidMetadata(validMetadata)) // Test with minimal required fields val minimalMetadata = ConfigMetadata( brandId = "gucci", productCategory = ProductCategory.Luxury ) assertTrue(isValidMetadata(minimalMetadata)) } } ``` -------------------------------- ### Luxury Item Metadata Example Source: https://developer.entrupy.com/docs/mobile-sdks/ios/integration-guide/core-authentication-workflow/performing-an-authentication Prepare metadata for a luxury item authentication. Required fields include 'product_category' and 'brand'. Optional fields like 'customer_item_id' are highly recommended for tracking. ```swift func luxuryItemMetadata() -> [String: Any] { return [ "product_category": "luxury", "brand": "Louis Vuitton", "material": "Monogram Canvas", "customer_item_id": "LV-NEVERFULL-MM-001" // "capture_workflow": "authentication" // Optional, defaults to "authentication" ] } ``` -------------------------------- ### Fetch Entrupy SDK Configuration Source: https://developer.entrupy.com/docs/mobile-sdks/ios/sdk-reference/view-model-guides/capture-flow-ui Optionally pre-fetch SDK configuration to potentially reduce latency when starting a capture or search. This is not mandatory as the SDK fetches it implicitly if needed. ```swift // In your ViewController, e.g., in viewDidAppear if EntrupyApp.sharedInstance().isAuthorizationValid() { EntrupyApp.sharedInstance().configDelegate = self // Conform to EntrupyConfigDelegate // Use .ConfigTypeProduction for release builds. // .ConfigTypeDebug provides a shorter workflow for development (results will be Invalid). EntrupyApp.sharedInstance().fetchConfigurationType(EntrupyConfigType.ConfigTypeProduction) } ``` -------------------------------- ### Android UI Test with Espresso Source: https://developer.entrupy.com/docs/mobile-sdks/android/backend-and-advanced-considerations/development-testing-and-sample-app Demonstrates basic UI testing for an Android application using Espresso. Includes setup for ActivityScenarioRule and placeholder tests for capture flow and permission handling. ```kotlin @RunWith(AndroidJUnit4::class) class EntrupyUITest { @get:Rule val activityRule = ActivityScenarioRule(MainActivity::class.java) @Test fun testCaptureFlowLaunch() { // Navigate to capture button onView(withId(R.id.btn_start_capture)) .perform(click()) // Verify capture flow is launched // Note: This would require custom assertions based on your UI } @Test fun testPermissionHandling() { // Test permission denial flow // This requires special setup to simulate permission denial } } ``` -------------------------------- ### Sneakers Item Metadata Example Source: https://developer.entrupy.com/docs/mobile-sdks/ios/integration-guide/core-authentication-workflow/performing-an-authentication Prepare metadata for a sneakers authentication. Required fields include 'product_category', 'brand', and 'style_name'. Optional fields like 'us_size' and 'customer_item_id' can also be included. ```swift func sneakersItemMetadata() -> [String: Any] { return [ "product_category": "sneakers", "brand": "Nike", "style_name": "Air Jordan 1 Retro High OG SP", "us_size": "9.5", "style_code": "DO7097-100", "customer_item_id": "AJ1-DO7097-100-9_5" // "capture_workflow": "authentication" // Optional, defaults to "authentication" ] } ``` -------------------------------- ### Conceptual Direct Fetch for Session Details Source: https://developer.entrupy.com/docs/mobile-sdks/ios/sdk-reference/direct-access-api-guides/programmatic-session-data This is a conceptual example of how a direct fetch method might work if supported by the SDK. It demonstrates fetching session details for a given Entrupy ID and handling success or failure responses. Verify actual SDK capabilities for this functionality. ```swift func fetchAndDisplayItemDetails(entrupyId: String) { EntrupySDK.shared.fetchSessionDetails(entrupyId: entrupyId) { result in // Fictional method DispatchQueue.main.async { switch result { case .success(let details): // Assuming 'details' is a struct containing all necessary info: // let statusText = details.status.result.display.header // let etaMinutes = (details.status.result.eta ?? 0) / 60 // let certificateURL = details.certificate?.url // let brandName = details.properties.brand.name // ... and so on for catalog data, flags, etc. // Update your custom UI elements // self.statusLabel.text = "Status: \(statusText) - ETA: \(etaMinutes)m" // self.brandLabel.text = "Brand: \(brandName)" print("Successfully fetched details for \(entrupyId)") case .failure(let error): // Handle the error (e.g., item not found, network issue) // self.statusLabel.text = "Unable to load status for \(entrupyId)" print("Error fetching details for \(entrupyId): \(error.localizedDescription)") } } } } ``` -------------------------------- ### Initiate Capture Flow with Item Metadata Source: https://developer.entrupy.com/docs/mobile-sdks/ios/sdk-reference/view-model-guides/capture-flow-ui Prepare item metadata, check authorization, assign a capture delegate, and start the capture flow. Ensure 'self' conforms to EntrupyCaptureDelegate. Handles invalid tokens by printing a message. ```swift // Swift // 1. Prepare Item Metadata (include product_category and category-specific fields) // Sneakers example (required: brand, style_name) let itemMetadata: [String: Any] = [ "product_category": "sneakers", "brand": "Nike", "style_name": "Air Jordan 1 Retro High OG SP", // Optional "us_size": "9.5", "upc": "00195244532483", "style_code": "DO7097-100", // Recommended "customer_item_id": "SKU-INTERNAL-12345" // max 256 chars ] // 2. Check Authorization and Present if EntrupyApp.sharedInstance().isAuthorizationValid() { // 3. Assign the Capture Delegate EntrupyApp.sharedInstance().captureDelegate = self // 'self' must conform to EntrupyCaptureDelegate // 4. Start the Capture Flow EntrupyApp.sharedInstance().startCapture(forItem: itemMetadata, viewController: self) } else { // Handle invalid or expired token: initiate re-authorization print("Authorization token is invalid. Please log in again.") } ``` -------------------------------- ### Conceptual Direct Session Details Fetch Source: https://developer.entrupy.com/docs/mobile-sdks/android/sdk-reference/direct-access-api-guides/programmatic-session-data A conceptual example of a direct fetch method for session details, assuming the SDK provides `fetchSessionDetails`. It includes success and error handling for updating UI elements. ```kotlin import com.entrupy.sdk.app.EntrupyApp /* fun fetchAndDisplayItemDetails(entrupyId: String) { EntrupyApp.sharedInstance().fetchSessionDetails(entrupyId = entrupyId) { result -> runOnUiThread { when (result) { is Result.Success -> { // Assuming 'details' is a data class containing all necessary info: // val statusText = details.status.result.display.header // val etaMinutes = (details.status.result.eta ?: 0) / 60 // val certificateURL = details.certificate?.url // val brandName = details.properties.brand.name // ... and so on for catalog data, flags, etc. // Update your custom UI elements // statusLabel.text = "Status: $statusText - ETA: ${etaMinutes}m" // brandLabel.text = "Brand: $brandName" println("Successfully fetched details for $entrupyId") } is Result.Error -> { // Handle the error (e.g., item not found, network issue) // statusLabel.text = "Unable to load status for $entrupyId" println("Error fetching details for $entrupyId: ${result.exception.message}") } } } } } */ ``` -------------------------------- ### Present MarketEdge View with Configuration Source: https://developer.entrupy.com/docs/mobile-sdks/ios/sdk-reference/view-model-guides/market-edge-view-ui Implement this method to present the MarketEdge view. Ensure user authorization and provide an Entrupy ID and configuration. The SDK manages the view's lifecycle. ```swift import EntrupySDK final class YourViewController: UIViewController, EntrupyMarketEdgeViewDelegate { func presentMarketEdge(for entrupyID: String) { guard EntrupyApp.sharedInstance().isAuthorizationValid() else { print("User not authorized. Cannot display MarketEdge view.") return } let configuration = EntrupyMarketEdgeViewConfiguration( displayMarketGrade: true, displayMarketValue: true, displayMarketMatch: true, displayRegionSelection: true ) EntrupyApp.sharedInstance().marketEdgeViewDelegate = self EntrupyApp.sharedInstance().displayMarketEdgeViewForItem(withEntrupyID: entrupyID, withConfiguration: configuration) } // MARK: - EntrupyMarketEdgeViewDelegate func didDisplayMarketEdgeViewForItem(withEntrupyID entrupyID: String) { // SDK presented the view } func didDismissMarketEdgeViewForItem(withEntrupyID entrupyID: String) { // User closed the view } func didDisplayMarketEdgeViewFailWithError( _ errorCode: EntrupyErrorCode, description: String, localizedDescription: String, forEntrupyID entrupyID: String ) { // Failed to present (e.g. auth, network, invalid ID) } } ``` -------------------------------- ### Configure Automatic Transition to Detail View Source: https://developer.entrupy.com/docs/mobile-sdks/android/sdk-reference/view-model-guides/result-screen-ui Set up the Result Screen to automatically transition to the Detail View when authentication results are ready. Configure the transition delay in milliseconds. ```kotlin import com.entrupy.sdk.app.EntrupyApp // Configure automatic transition to Detail View when results are ready val resultScreenConfig = EntrupyResultScreenConfig.Builder() .setAutoTransitionToDetailView(true) // Automatically show Detail View when results are ready .setTransitionDelay(2000L) // Wait 2 seconds before transitioning .build() EntrupyApp.sharedInstance().setResultScreenConfig(resultScreenConfig) ``` -------------------------------- ### Preview Themes in Activity Source: https://developer.entrupy.com/docs/mobile-sdks/android/sdk-reference/ui-theme-customization Implement a theme preview activity to test different theme configurations. Use `EntrupyApp.sharedInstance().updateTheme()` and `recreate()` to apply and display theme changes. ```kotlin import com.entrupy.sdk.app.EntrupyApp class ThemePreviewActivity : AppCompatActivity() { private val entrupyApp = EntrupyApp.sharedInstance() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_theme_preview) // Preview different themes findViewById