Skip to main content

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

PropertyTypeDefaultDescription
dateRangeDateRange?.last(days: 30)Date range filter (last 30 days by default)
filters[EntrupySearchFilter][]Array of filters to apply
resultModeResultMode.resultsControls response content
limitInt20Maximum items per page
cursor[String]?nilCursor 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])
}
Category Filter Required

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])
StatusDescription
.authenticItem is authentic
.underReviewUnder review
.invalidInvalid submission
.notSupportedItem type not supported
.unidentifiedCannot be identified
.other(String)Custom status value

Category Filter

Filter by product category:

.category([Category])
CategoryDescription
.luxuryLuxury goods
.apparelApparel items
.sneakersSneakers
.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])
FlagStatusDescription
.noneNo flag applied
.flaggedCurrently flagged
.resolvedFlag 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:

FieldTypeDescription
authentication_idStringUnique ID assigned by Entrupy
propertiesEntrupyCaptureResultPropertiesBrand, model, function details
statusEntrupyCaptureResultStatusResult and flag status
more_detailsEntrupyCaptureResultMoreDetails?Certificate info, catalog insights
text_fields[EntrupyCaptureResultTextField]?User-submitted text inputs
imagesEntrupyCaptureResultImages?Submitted images
event_timesEntrupyCaptureResultEventTimes?Timestamps for events
timestampEntrupyCaptureResultTimestampAuthentication 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