Programmatic Search for Authentication Items
The Entrupy iOS SDK provides a powerful searchAuthenticationItems API that enables programmatic searching of authentication records. This guide covers how to build search queries, apply filters, handle pagination, and process results.
Overview
The searchAuthenticationItems API supports:
- Date range filtering - Search within specific time periods
- Multiple filter types - Filter by status, category, brand, and flag
- Pagination - Cursor-based navigation for large result sets
- Result mode selection - Choose between full results or count-only mode
Method Signature
func searchAuthenticationItems(query: EntrupySearchQuery, completion: @escaping (NSDictionary?, NSError?) -> Void)
The completion handler returns an NSDictionary which can be decoded into the typed EntrupySearchItemsResult model provided by the SDK:
EntrupyApp.sharedInstance().searchAuthenticationItems(query: query) { result, error in
guard let result = result else { return }
do {
let jsonData = try JSONSerialization.data(withJSONObject: result, options: [])
let searchResult = try JSONDecoder().decode(EntrupySearchItemsResult.self, from: jsonData)
// Use the typed searchResult
} catch {
print("Decoding error: \(error)")
}
}
Building a Search Query
The EntrupySearchQuery class contains all search parameters.
The SDK provides predefined enum values for common filter options (status, category, flag) to ensure type safety and reduce errors. However, each enum also includes an .other(String) case that allows you to pass custom values if new options become available:
// Using predefined values
.status([.authentic, .underReview])
.category([.apparel, .luxury , .sneakers])
// Using .other for custom or new values not yet in the SDK
.status([.other("new_status_value")])
.category([.other("new_category_value")])
Query Properties
| Property | Type | Default | Description |
|---|---|---|---|
dateRange | DateRange? | .last(days: 30) | Date range filter (last 30 days by default) |
filters | [EntrupySearchFilter] | [] | Array of filters to apply |
resultMode | ResultMode | .results | Controls response content |
limit | Int | 20 | Maximum items per page |
cursor | [String]? | nil | Cursor for pagination (from previous response) |
EntrupySearchFilter
The filters property accepts an array of EntrupySearchFilter enum values:
public enum EntrupySearchFilter {
case status([AuthenticationStatus])
case category([Category])
case brands([String])
case flag([FlagStatus])
}
The category filter is required for search results to be returned. Always include at least one category in your query:
query.filters = [
.category([.luxury, .apparel, .sneakers]) // Required
// ... other optional filters
]
Date Range Options
The DateRange enum provides two ways to specify time boundaries:
public enum DateRange {
case last(days: Int) // Last N days from now
case custom(start: String, end: String) // ISO8601 date strings
}
Result Mode Options
Control what data is returned in the response:
public enum ResultMode {
case countOnly // Returns only counts, no items
case results // Returns full item data
case other(String) // Custom value
}
Applying Filters
Filters are combined with AND logic. Multiple values within a single filter use OR logic.
Example: To find items that are (authentic OR under review) AND in the luxury category:
query.filters = [
.status([.authentic, .underReview]), // OR logic within this filter
.category([.luxury]) // AND logic between filters
]
Status Filter
Filter by authentication result status:
.status([AuthenticationStatus])
| Status | Description |
|---|---|
.authentic | Item is authentic |
.underReview | Under review |
.invalid | Invalid submission |
.notSupported | Item type not supported |
.unidentified | Cannot be identified |
.other(String) | Custom status value |
Category Filter
Filter by product category:
.category([Category])
| Category | Description |
|---|---|
.luxury | Luxury goods |
.apparel | Apparel items |
.sneakers | Sneakers |
.other(String) | Custom category |
Brands Filter
Filter by brand identifiers:
.brands([String])
Pass brand ID strings directly to filter by specific brands.
// Filter for Louis Vuitton and Chanel items
query.filters = [
.brands(["louis_vuitton", "chanel"])
]
Flag Filter
Filter by flag status:
.flag([FlagStatus])
| FlagStatus | Description |
|---|---|
.none | No flag applied |
.flagged | Currently flagged |
.resolved | Flag has been resolved |
Usage Examples
Basic Search (Last 30 Days)
let query = EntrupySearchQuery()
query.dateRange = .last(days: 30)
query.filters = [.category([.sneakers, .luxury])]
query.resultMode = .results
query.limit = 20
EntrupyApp.sharedInstance().searchAuthenticationItems(query: query) { result, error in
if let error = error {
print("Error: \(error.localizedDescription)")
return
}
guard let result = result else { return }
// Decode to typed result
do {
let jsonData = try JSONSerialization.data(withJSONObject: result, options: [])
let searchResult = try JSONDecoder().decode(EntrupySearchItemsResult.self, from: jsonData)
print("Total matching items: \(searchResult.total_count)")
print("Items in this response: \(searchResult.item_count)")
} catch {
print("Decoding error: \(error)")
}
}
Filtered Search with Multiple Criteria
let query = EntrupySearchQuery()
query.dateRange = .last(days: 90)
query.filters = [
.status([.authentic, .underReview]),
.category([.luxury]),
.flag([.none])
]
query.resultMode = .results
query.limit = 10
EntrupyApp.sharedInstance().searchAuthenticationItems(query: query) { result, error in
// Handle response...
}
Count Only Mode
When you only need to know how many items match your criteria without retrieving the actual item data:
let query = EntrupySearchQuery()
query.dateRange = .last(days: 7)
query.filters = [
.status([.authentic]),
.category([.sneakers, .luxury, .apparel])
]
query.resultMode = .countOnly // Only returns counts, no items array
EntrupyApp.sharedInstance().searchAuthenticationItems(query: query) { result, error in
// result will have total_count but items will be nil
}
Custom Date Range
let query = EntrupySearchQuery()
query.dateRange = .custom(
start: "2025-01-01T00:00:00Z", // ISO8601 format
end: "2025-01-31T23:59:59Z"
)
query.filters = [.category([.sneakers, .luxury])]
query.resultMode = .results
EntrupyApp.sharedInstance().searchAuthenticationItems(query: query) { result, error in
// Handle response...
}
Pagination
Use cursor-based pagination to navigate through large result sets:
// First page
let query = EntrupySearchQuery()
query.dateRange = .last(days: 30)
query.filters = [.category([.sneakers, .luxury])]
query.limit = 20
query.cursor = nil // First page
EntrupyApp.sharedInstance().searchAuthenticationItems(query: query) { result, error in
guard let result = result else { return }
do {
let jsonData = try JSONSerialization.data(withJSONObject: result, options: [])
let searchResult = try JSONDecoder().decode(EntrupySearchItemsResult.self, from: jsonData)
// Process current page items
if let items = searchResult.items {
for item in items {
print("Item ID: \(item.authentication_id)")
}
}
// Check for more pages
if let nextCursor = searchResult.next_cursor {
// Load next page
query.cursor = nextCursor
EntrupyApp.sharedInstance().searchAuthenticationItems(query: query) { nextResult, nextError in
// Handle next page...
}
} else {
print("All results fetched")
}
} catch {
print("Decoding error: \(error)")
}
}
Response Structure
EntrupySearchItemsResult
The search response contains:
public struct EntrupySearchItemsResult: Codable {
public let metadata: EntrupySearchItemsResultMetadata
public let total_count: Int // Total matching items in database
public let item_count: Int // Items returned in this response
public let items: [EntrupyCaptureResult]? // Item data (nil if countOnly mode)
public let next_cursor: [String]? // Cursor for next page (nil if last page)
}
public struct EntrupySearchItemsResultMetadata: Codable {
public let result_mode: String? // "count_only" or "results"
}
Item Data: EntrupyCaptureResult
Each item in the items array contains:
| Field | Type | Description |
|---|---|---|
authentication_id | String | Unique ID assigned by Entrupy |
properties | EntrupyCaptureResultProperties | Brand, model, function details |
status | EntrupyCaptureResultStatus | Result and flag status |
more_details | EntrupyCaptureResultMoreDetails? | Certificate info, catalog insights |
text_fields | [EntrupyCaptureResultTextField]? | User-submitted text inputs |
images | EntrupyCaptureResultImages? | Submitted images |
event_times | EntrupyCaptureResultEventTimes? | Timestamps for events |
timestamp | EntrupyCaptureResultTimestamp | Authentication start time |
Error Handling
Use the localizedDescription property to display user friendly error messages:
EntrupyApp.sharedInstance().searchAuthenticationItems(query: query) { result, error in
if let error = error {
print("Search failed: \(error.localizedDescription)")
// Display error.localizedDescription to the user
return
}
// Handle successful result...
}
For detailed information about specific error codes and handling strategies, see the Error Code Reference.
Next Steps
- Learn about Programmatic Access to Session Data for fetching individual item details.
- Review Programmatic Customer Support for flag management and support interactions.
- Explore Searching SDK Authentications in the Integration Guide for UI-based search approaches.