From 289efd6cce105add0470ed27ad84469e6393fbe9 Mon Sep 17 00:00:00 2001 From: yubi_shi Date: Thu, 8 Oct 2026 21:32:15 +0800 Subject: [PATCH] docs: document attendance scope for reverse event lookups --- api-reference-backup/exhibitors/events.mdx | 9 +- .../exhibitors/search-events.mdx | 9 +- api-reference-backup/openapi.json | 317 ++++++++++++++++-- .../personnel/events-by-linkedin.mdx | 5 +- .../personnel/events-by-name.mdx | 9 +- api-reference-backup/personnel/events.mdx | 5 +- api-reference/openapi.json | 317 ++++++++++++++++-- llms-full.txt | 35 +- openapi.json | 317 ++++++++++++++++-- scripts/test_sync_public_assets.py | 64 +++- 10 files changed, 984 insertions(+), 103 deletions(-) diff --git a/api-reference-backup/exhibitors/events.mdx b/api-reference-backup/exhibitors/events.mdx index 3d911b9..9964669 100644 --- a/api-reference-backup/exhibitors/events.mdx +++ b/api-reference-backup/exhibitors/events.mdx @@ -27,12 +27,13 @@ See [Authentication](/authentication) | Name | Required | Type | Notes | | --- | --- | --- | --- | | `exhibitor_id` | Yes | string | Numeric-string exhibitor identifier. | +| `attendance_scope` | No | string | `all` (default), `exhibitor`, or `visitor`. `exhibitor` includes events with exhibitor evidence, including dual-identity events. `visitor` returns visitor-only events and excludes exhibitor evidence. Other values, including `null`, return `400`. | | `page` | No | integer | Defaults to `1`. | | `pageSize` | No | integer | Defaults to `20`; maximum `100`. | ## Request example ```bash -curl "https://platform.lensmor.com/external/exhibitors/events?exhibitor_id=456&page=1&pageSize=20" \ +curl "https://platform.lensmor.com/external/exhibitors/events?exhibitor_id=456&attendance_scope=visitor&page=1&pageSize=20" \ -H "Authorization: Bearer $LENSMOR_API_KEY" ``` @@ -55,11 +56,12 @@ curl "https://platform.lensmor.com/external/exhibitors/events?exhibitor_id=456&p "country": "United States", "exhibitorCount": 950, "sponsorMatchStarred": 0, + "attendance_identity": ["visitor"], "image": null, "dataSource": "Lensmor" } ], - "total": 12, + "total": 1, "page": 1, "pageSize": 20, "totalPages": 1, @@ -78,6 +80,7 @@ curl "https://platform.lensmor.com/external/exhibitors/events?exhibitor_id=456&p | `venue`, `city`, `region`, `country` | Location metadata. | | `exhibitorCount` | Known exhibitor count when available. | | `sponsorMatchStarred` | Sponsor Match starred state (`0` or `1`). | +| `attendance_identity` | Complete array of this company's identities at this event: `exhibitor` and/or `visitor`. | | `image` | Event image URL when available. | | `dataSource` | Always `Lensmor` for public event records. | | `total`, `page`, `pageSize`, `totalPages`, `hasMore` | Pagination metadata. | @@ -89,6 +92,6 @@ curl "https://platform.lensmor.com/external/exhibitors/events?exhibitor_id=456&p - `429 Too Many Requests` ## Notes -- Event items reuse the standard event-item response shape. +- Event items include the standard event fields and the event-scoped `attendance_identity` array. With `attendance_scope=all`, a dual-identity event can return `["exhibitor", "visitor"]`. - Pagination behavior follows the shared [Pagination conventions](/concepts/pagination). - This endpoint requires `exhibitor_id`; if you only have `company_name`, use `POST /external/exhibitors/search-events`. diff --git a/api-reference-backup/exhibitors/search-events.mdx b/api-reference-backup/exhibitors/search-events.mdx index b08d519..820ecd6 100644 --- a/api-reference-backup/exhibitors/search-events.mdx +++ b/api-reference-backup/exhibitors/search-events.mdx @@ -36,6 +36,7 @@ See [Authentication](/authentication) | Name | Required | Type | Notes | | --- | --- | --- | --- | | `company_name` | Yes | string | Company name input. Incomplete names are allowed, but matching stays precision-first. | +| `attendance_scope` | No | string | `all` (default), `exhibitor`, or `visitor`. `exhibitor` includes dual-identity events; `visitor` returns visitor-only events and excludes exhibitor evidence. Other values, including `null`, return `400`. | | `sponsor_match_starred` | No | integer | `1` returns starred Sponsor Match events, `0` returns non-starred events; omit to include both. | | `page` | No | integer | Defaults to `1`. | | `pageSize` | No | integer | Defaults to `20`; maximum `100`. | @@ -51,7 +52,7 @@ curl -X POST "https://platform.lensmor.com/external/exhibitors/search-events" \ -H "Authorization: Bearer $LENSMOR_API_KEY" \ -H "Content-Type: application/json" \ -H "x-call-source: api" \ - -d '{"company_name":"Acme","sponsor_match_starred":1,"page":1,"pageSize":20}' + -d '{"company_name":"Acme","attendance_scope":"exhibitor","sponsor_match_starred":1,"page":1,"pageSize":20}' ``` ## Response example @@ -73,6 +74,7 @@ curl -X POST "https://platform.lensmor.com/external/exhibitors/search-events" \ "country": "United States", "exhibitorCount": 100, "sponsorMatchStarred": 1, + "attendance_identity": ["exhibitor", "visitor"], "image": null, "dataSource": "Lensmor", "matchedExhibitors": [ @@ -103,14 +105,15 @@ curl -X POST "https://platform.lensmor.com/external/exhibitors/search-events" \ | `exhibitorCount` | Exhibitor coverage count when available. | | `sponsorMatchStarred` | Sponsor Match starred state (`0` or `1`). | | `dataSource` | Always `Lensmor` for public event records. | -| `matchedExhibitors` | Matched company records that connect the input to the returned event. Treat this as the primary evidence that the company-name input matched the returned event. | +| `attendance_identity` | Complete array of this company's identities at this event: `exhibitor` and/or `visitor`. | +| `matchedExhibitors` | Matched exhibitor relationships. Visitor-only events can have an empty array. | | `total`, `page`, `pageSize`, `totalPages`, `hasMore` | Pagination metadata. | ## Credit behavior This endpoint consumes `50` credits after the company-name matcher finds at least one event. A successful empty response consumes `0` credits. If a non-empty search cannot spend the required credits, the API returns `402 Payment Required` instead of returning the matched records. -Refresh [Credits balance](/api-reference/credits/get-credits-balance) after successful searches when your UI or audit log needs final credit reconciliation. Use the returned event count, page count, and `matchedExhibitors` as the main value evidence for the search result. +Refresh [Credits balance](/api-reference/credits/get-credits-balance) after successful searches when your UI or audit log needs final credit reconciliation. Use the returned event count, pagination, and `attendance_identity` to interpret the search result. `matchedExhibitors` can be empty for visitor-only events. ## Concurrency limit diff --git a/api-reference-backup/openapi.json b/api-reference-backup/openapi.json index 9e11e78..192abd0 100644 --- a/api-reference-backup/openapi.json +++ b/api-reference-backup/openapi.json @@ -1172,7 +1172,7 @@ "Exhibitors" ], "summary": "Search events by exhibitor company name", - "description": "Find deduplicated events associated with exhibitor companies that match a required company name.\n\nUse this endpoint for account planning, CRM enrichment, or the question “which events is this company associated with?” without first resolving an exhibitor ID. Optional `sponsor_match_starred` filtering can select starred or non-starred Sponsor Match events; omit it to include both states.\n\nThe endpoint returns events, not exhibitor records. A non-empty result consumes `50` credits and an empty result consumes `0` credits, so check the balance before bulk or user-confirmed searches. Matching is precision-first and incomplete names can legitimately return no results.", + "description": "Find deduplicated events associated with exhibitor companies matching a required company name. Use this for account planning or CRM enrichment without first resolving `exhibitor_id`. The precision-first matcher can return no result for incomplete names. A non-empty result consumes `50` credits; an empty result consumes `0`. `sponsor_match_starred` optionally selects starred or non-starred events.\n\n`attendance_scope` accepts `all` (default), `exhibitor`, or `visitor`. `exhibitor` includes events with exhibitor evidence, even when visitor evidence is present. `visitor` returns visitor-only events and excludes exhibitor evidence. Each event includes `attendance_identity`; visitor-only results can have an empty `matchedExhibitors` array.", "operationId": "searchEventsByExhibitorCompanyName", "parameters": [ { @@ -1225,6 +1225,10 @@ "id": "456", "companyName": "Acme Retail Systems" } + ], + "attendance_identity": [ + "exhibitor", + "visitor" ] } ], @@ -1317,12 +1321,15 @@ "Exhibitors" ], "summary": "List exhibitor related events", - "description": "Return a paginated list of Lensmor events associated with one known exhibitor identifier.\n\nUse this endpoint when an exhibitor profile has already been resolved and the integration needs the company's event history or current event associations. Event items use the shared public event shape and can be passed to event detail, fit scoring, ranking, or access workflows. Follow `hasMore` and increment `page` to retrieve additional results.\n\nIf the starting input is only a company name, use exhibitor event search instead. An exhibitor with no associated events returns a successful empty page; an unknown exhibitor identifier returns an error.", + "description": "Return a paginated list of Lensmor events for a known `exhibitor_id`. Use it after resolving an exhibitor profile to browse company event associations. Follow `hasMore` and increment `page` for more results; an exhibitor with no associated events returns an empty page, while an unknown ID returns an error.\n\n`attendance_scope` accepts `all` (default), `exhibitor`, or `visitor`. `all` returns events with known attendance evidence. `exhibitor` includes events with exhibitor evidence, even when visitor evidence is also present. `visitor` returns visitor-only events and excludes events with exhibitor evidence. Each item includes an event-scoped `attendance_identity` array. If you only have a company name, use exhibitor event search.", "operationId": "listExhibitorEvents", "parameters": [ { "$ref": "#/components/parameters/ExhibitorIdQuery" }, + { + "$ref": "#/components/parameters/CompanyAttendanceScopeQuery" + }, { "$ref": "#/components/parameters/Page" }, @@ -1336,7 +1343,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/EventPage" + "$ref": "#/components/schemas/ExhibitorRelatedEventPage" }, "example": { "items": [ @@ -1347,10 +1354,13 @@ "dateStart": "2026-01-12", "dateEnd": "2026-01-15", "city": "New York", - "country": "United States" + "country": "United States", + "attendance_identity": [ + "visitor" + ] } ], - "total": 12, + "total": 1, "page": 1, "pageSize": 20, "totalPages": 1, @@ -1371,7 +1381,14 @@ "429": { "$ref": "#/components/responses/RateLimited" } - } + }, + "x-codeSamples": [ + { + "lang": "curl", + "label": "cURL", + "source": "curl --request GET \\\n --url 'https://platform.lensmor.com/external/exhibitors/events?exhibitor_id=456&attendance_scope=visitor&page=1&pageSize=20' \\\n --header 'Authorization: Bearer '" + } + ] } }, "/external/personnel/list": { @@ -1572,12 +1589,15 @@ "Personnel" ], "summary": "List personnel related events", - "description": "Return a paginated list of Lensmor events associated with one known personnel identifier.\n\nUse this endpoint when the integration already has `personnel_id` and needs the person's event history or current event associations. Returned event items use the shared public event shape and can be passed directly to event detail, scoring, ranking, or event-access workflows. Follow `hasMore` and increment `page` when additional results are available.\n\nThis lookup does not expose or unlock contact data. If the starting identifier is a LinkedIn URL, use the LinkedIn-based lookup; if only a full name is available, use the exact-name event search and account for its credit and concurrency rules.", + "description": "Return paginated events associated with a known `personnel_id`. Use it after resolving the person to browse event history or current associations. Follow `hasMore` and increment `page` for additional results. This lookup does not expose or unlock contact data. Use the LinkedIn URL or exact-name lookup when a Lensmor personnel ID is unavailable.\n\n`attendance_scope` accepts `all` (default), `exhibitor_employee`, or `visitor`. `all` returns events with known attendance evidence. `exhibitor_employee` includes events with employee evidence, even when visitor evidence is also present. `visitor` returns visitor-only events and excludes events with exhibitor-employee evidence. Each item includes an event-scoped `attendance_identity` array.", "operationId": "listPersonnelEvents", "parameters": [ { "$ref": "#/components/parameters/PersonnelIdQuery" }, + { + "$ref": "#/components/parameters/PersonnelAttendanceScopeQuery" + }, { "$ref": "#/components/parameters/Page" }, @@ -1591,14 +1611,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/EventPage" + "$ref": "#/components/schemas/PersonnelRelatedEventPage" }, "example": { "items": [ { "id": "501", "eventId": "139574", - "name": "Retail Technology Expo 2026" + "name": "Retail Technology Expo 2026", + "attendance_identity": [ + "visitor" + ] } ], "total": 1, @@ -1622,7 +1645,14 @@ "429": { "$ref": "#/components/responses/RateLimited" } - } + }, + "x-codeSamples": [ + { + "lang": "curl", + "label": "cURL", + "source": "curl --request GET \\\n --url 'https://platform.lensmor.com/external/personnel/events?personnel_id=789&attendance_scope=visitor&page=1&pageSize=20' \\\n --header 'Authorization: Bearer '" + } + ] } }, "/external/personnel/events/by-linkedin": { @@ -1631,7 +1661,7 @@ "Personnel" ], "summary": "List personnel related events by LinkedIn URL", - "description": "Normalize a public LinkedIn profile URL, resolve the matching Lensmor personnel record, and return that person's related events.\n\nUse this endpoint for browser-extension, CRM-enrichment, or research workflows where LinkedIn URL is the stable starting identifier. The response includes personnel context plus a paginated event list, allowing the client to recover a Lensmor personnel ID for later profile or contact workflows. Continue through pages only while `hasMore` is true.\n\nURL normalization handles common LinkedIn profile variations, but a URL that cannot be resolved returns a not-found response. This call is read-only and does not unlock contact data.", + "description": "Normalize a public LinkedIn profile URL, resolve its matching Lensmor personnel record, and return the person plus paginated related events. Use this lookup when a LinkedIn URL is the stable starting identifier; a URL that cannot be resolved returns not found. The call does not unlock contact data. Follow `hasMore` for additional event pages.\n\n`attendance_scope` accepts `all` (default), `exhibitor_employee`, or `visitor`. `all` returns events with known attendance evidence. `exhibitor_employee` includes dual-identity events. `visitor` returns visitor-only events and excludes events with exhibitor-employee evidence. Each event includes an event-scoped `attendance_identity` array.", "operationId": "listPersonnelEventsByLinkedin", "parameters": [ { @@ -1645,6 +1675,9 @@ "description": "Public LinkedIn profile URL used for normalized personnel matching.", "example": "https://www.linkedin.com/in/jane-doe" }, + { + "$ref": "#/components/parameters/PersonnelAttendanceScopeQuery" + }, { "$ref": "#/components/parameters/Page" }, @@ -1668,7 +1701,7 @@ "$ref": "#/components/schemas/ContactItem" }, "events": { - "$ref": "#/components/schemas/EventPage" + "$ref": "#/components/schemas/PersonnelRelatedEventPage" } } }, @@ -1688,7 +1721,10 @@ { "id": "501", "eventId": "139574", - "name": "Retail Technology Expo 2026" + "name": "Retail Technology Expo 2026", + "attendance_identity": [ + "visitor" + ] } ], "total": 1, @@ -1713,7 +1749,14 @@ "429": { "$ref": "#/components/responses/RateLimited" } - } + }, + "x-codeSamples": [ + { + "lang": "curl", + "label": "cURL", + "source": "curl --request GET \\\n --url 'https://platform.lensmor.com/external/personnel/events/by-linkedin?linkedin_url=https%3A%2F%2Fwww.linkedin.com%2Fin%2Fjane-smith&attendance_scope=visitor&page=1&pageSize=20' \\\n --header 'Authorization: Bearer '" + } + ] } }, "/external/personnel/events/by-name": { @@ -1722,7 +1765,7 @@ "Personnel" ], "summary": "Search personnel related events by name", - "description": "Find a paginated, deduplicated event list for up to 50 personnel records whose full name exactly matches the supplied name.\n\nUse this endpoint only when neither a Lensmor personnel ID nor a LinkedIn URL is available. Matching is case-insensitive after trimming but is not partial or fuzzy. Date filters apply to event start dates; without `date_start_from`, the search defaults to upcoming events.\n\nThis endpoint requires an active paid user. A non-empty result consumes `50` credits, an empty result consumes `0` credits, and at most `10 requests` can run concurrently for one user. The response contains events rather than a separate personnel object.", + "description": "Find paginated, deduplicated events for up to 50 personnel records with the exact full name. Matching ignores case and surrounding whitespace. Date filters use event start dates; `date_start_from` defaults to `2026-01-01`. A non-empty result consumes `50` credits; an empty result consumes `0`. Up to `10 requests` can run concurrently per user.\n\n`attendance_scope` accepts `all` (default), `exhibitor_employee`, or `visitor`. `all` includes known attendance evidence. `exhibitor_employee` includes dual-identity events. `visitor` returns visitor-only events and excludes exhibitor-employee evidence. Evidence is combined per event across matched people before filtering. Each event returns the complete `attendance_identity` array.", "operationId": "searchPersonnelEventsByName", "parameters": [ { @@ -1737,16 +1780,20 @@ }, "example": "Jane Doe" }, + { + "$ref": "#/components/parameters/PersonnelAttendanceScopeQuery" + }, { "name": "date_start_from", "in": "query", "required": false, - "description": "Inclusive event start-date lower bound. Defaults to the current date when omitted.", + "description": "Inclusive event start-date lower bound. Defaults to `2026-01-01` when omitted.", "schema": { "type": "string", - "format": "date" + "format": "date", + "default": "2026-01-01" }, - "example": "2025-01-01" + "example": "2026-01-01" }, { "name": "date_start_to", @@ -1757,7 +1804,7 @@ "type": "string", "format": "date" }, - "example": "2025-12-31" + "example": "2026-12-31" }, { "$ref": "#/components/parameters/Page" @@ -1777,7 +1824,7 @@ "schema": { "oneOf": [ { - "$ref": "#/components/schemas/EventPage" + "$ref": "#/components/schemas/PersonnelRelatedEventPage" }, { "$ref": "#/components/schemas/FeatureUnavailableBusinessError" @@ -1808,7 +1855,10 @@ "hasVisitors": true, "sponsorMatchStarred": 0, "image": null, - "dataSource": "Lensmor" + "dataSource": "Lensmor", + "attendance_identity": [ + "visitor" + ] } ], "total": 1, @@ -1862,7 +1912,14 @@ "429": { "$ref": "#/components/responses/RateLimited" } - } + }, + "x-codeSamples": [ + { + "lang": "curl", + "label": "cURL", + "source": "curl --request GET \\\n --url 'https://platform.lensmor.com/external/personnel/events/by-name?person_name=Jane%20Smith&attendance_scope=visitor&page=1&pageSize=20' \\\n --header 'Authorization: Bearer '" + } + ] } }, "/external/personnel/unlock-linkedin-activity": { @@ -2787,6 +2844,38 @@ }, "description": "Identify the caller as `api` or `agent` for usage attribution. Defaults to `api` when omitted.", "example": "api" + }, + "CompanyAttendanceScopeQuery": { + "name": "attendance_scope", + "in": "query", + "required": false, + "description": "Filter events by this company's attendance identity. Defaults to `all`. `exhibitor` includes events with exhibitor evidence, including events that also have visitor evidence. `visitor` returns visitor-only events and excludes events with exhibitor evidence. Only `all`, `exhibitor`, and `visitor` are valid; other values, including `null`, return 400.", + "schema": { + "type": "string", + "enum": [ + "all", + "exhibitor", + "visitor" + ], + "default": "all" + }, + "example": "visitor" + }, + "PersonnelAttendanceScopeQuery": { + "name": "attendance_scope", + "in": "query", + "required": false, + "description": "Filter events by attendance identities for the matched person or people. Defaults to `all`. `exhibitor_employee` includes events with exhibitor-employee evidence, including events that also have visitor evidence. `visitor` returns visitor-only events and excludes events with exhibitor-employee evidence. Exact-name lookups combine evidence per event across matched personnel before applying this filter. Only `all`, `exhibitor_employee`, and `visitor` are valid; other values, including `null`, return 400.", + "schema": { + "type": "string", + "enum": [ + "all", + "exhibitor_employee", + "visitor" + ], + "default": "all" + }, + "example": "visitor" } }, "requestBodies": { @@ -2955,6 +3044,17 @@ "default": 20, "description": "Maximum records requested per page; defaults to `20` and cannot exceed `100`.", "example": 20 + }, + "attendance_scope": { + "type": "string", + "enum": [ + "all", + "exhibitor", + "visitor" + ], + "default": "all", + "description": "Filter events by this company's attendance identity. Defaults to `all`. `exhibitor` includes events with exhibitor evidence, including events that also have visitor evidence. `visitor` returns visitor-only events and excludes events with exhibitor evidence. Only `all`, `exhibitor`, and `visitor` are valid; other values, including `null`, return 400.", + "example": "exhibitor" } } }, @@ -2962,11 +3062,12 @@ "company_name": "Acme", "sponsor_match_starred": 1, "page": 1, - "pageSize": 20 + "pageSize": 20, + "attendance_scope": "exhibitor" } } }, - "description": "Provide the company name, optional Sponsor Match filter, and pagination for event reverse search." + "description": "Provide the company name, optional Sponsor Match filter, and pagination for event reverse search. Optional `attendance_scope` filters by company attendance identity and defaults to `all`." }, "ProfileMatchingBody": { "required": true, @@ -3724,7 +3825,8 @@ { "type": "object", "required": [ - "matchedExhibitors" + "matchedExhibitors", + "attendance_identity" ], "properties": { "matchedExhibitors": { @@ -3732,12 +3834,27 @@ "items": { "$ref": "#/components/schemas/MatchedExhibitorSummary" }, - "description": "Matched Exhibitors returned as part of this event reverse search item object." + "description": "Admitted company matches with exhibitor relationships at this event. This array can be empty for visitor-only results." + }, + "attendance_identity": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "exhibitor", + "visitor" + ] + }, + "description": "Complete attendance identities for this company at this event. An event matched by a scope still returns its complete identity array.", + "example": [ + "exhibitor", + "visitor" + ] } } } ], - "description": "Event result enriched with the exhibitor company that produced the reverse-search match." + "description": "Event result with the company's attendance identities and any matched exhibitor relationships. Visitor-only results can have an empty matchedExhibitors array." }, "EventReverseSearchPage": { "type": "object", @@ -5960,6 +6077,152 @@ } ], "description": "Full Lensmor event metadata plus profile-recommendation evidence and rank." + }, + "ExhibitorRelatedEventItem": { + "allOf": [ + { + "$ref": "#/components/schemas/EventItem" + }, + { + "type": "object", + "required": [ + "attendance_identity" + ], + "properties": { + "attendance_identity": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "exhibitor", + "visitor" + ] + }, + "description": "Complete attendance identities for this company at this event. An event matched by a scope still returns its complete identity array.", + "example": [ + "exhibitor", + "visitor" + ] + } + } + } + ], + "description": "Event returned by a company reverse lookup with event-scoped attendance identities." + }, + "PersonnelRelatedEventItem": { + "allOf": [ + { + "$ref": "#/components/schemas/EventItem" + }, + { + "type": "object", + "required": [ + "attendance_identity" + ], + "properties": { + "attendance_identity": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "exhibitor_employee", + "visitor" + ] + }, + "description": "Complete attendance identities for the matched personnel at this event. Exact-name lookups combine evidence across matched personnel records before filtering. Scope filtering does not trim the returned identity array.", + "example": [ + "exhibitor_employee", + "visitor" + ] + } + } + } + ], + "description": "Event returned by a person reverse lookup with event-scoped attendance identities." + }, + "ExhibitorRelatedEventPage": { + "type": "object", + "required": [ + "items", + "total", + "page", + "pageSize", + "totalPages", + "hasMore" + ], + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ExhibitorRelatedEventItem" + }, + "description": "Records returned on the current page or in the current batch." + }, + "total": { + "type": "integer", + "description": "Total matching records across all pages." + }, + "page": { + "type": "integer", + "description": "One-based page number returned." + }, + "pageSize": { + "type": "integer", + "description": "Maximum records requested for this page." + }, + "totalPages": { + "type": "integer", + "description": "Total pages available for the current query." + }, + "hasMore": { + "type": "boolean", + "description": "Whether another result page is available." + } + }, + "additionalProperties": true, + "description": "Paginated company-related events with attendance identities." + }, + "PersonnelRelatedEventPage": { + "type": "object", + "required": [ + "items", + "total", + "page", + "pageSize", + "totalPages", + "hasMore" + ], + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PersonnelRelatedEventItem" + }, + "description": "Records returned on the current page or in the current batch." + }, + "total": { + "type": "integer", + "description": "Total matching records across all pages." + }, + "page": { + "type": "integer", + "description": "One-based page number returned." + }, + "pageSize": { + "type": "integer", + "description": "Maximum records requested for this page." + }, + "totalPages": { + "type": "integer", + "description": "Total pages available for the current query." + }, + "hasMore": { + "type": "boolean", + "description": "Whether another result page is available." + } + }, + "additionalProperties": true, + "description": "Paginated person-related events with attendance identities." } } } diff --git a/api-reference-backup/personnel/events-by-linkedin.mdx b/api-reference-backup/personnel/events-by-linkedin.mdx index 9decb6c..cd10a26 100644 --- a/api-reference-backup/personnel/events-by-linkedin.mdx +++ b/api-reference-backup/personnel/events-by-linkedin.mdx @@ -32,12 +32,13 @@ See [Authentication](/authentication) | Name | Required | Type | Notes | | --- | --- | --- | --- | | `linkedin_url` | Yes | string | LinkedIn profile URL used for normalized matching. | +| `attendance_scope` | No | string | `all` (default), `exhibitor_employee`, or `visitor`. `exhibitor_employee` includes dual-identity events; `visitor` returns visitor-only events and excludes exhibitor-employee evidence. Other values, including `null`, return `400`. | | `page` | No | integer | Defaults to `1`. | | `pageSize` | No | integer | Defaults to `20`; maximum `100`. | ## Request example ```bash -curl "https://platform.lensmor.com/external/personnel/events/by-linkedin?linkedin_url=https%3A%2F%2Fwww.linkedin.com%2Fin%2Fjane-smith%2F" \ +curl "https://platform.lensmor.com/external/personnel/events/by-linkedin?linkedin_url=https%3A%2F%2Fwww.linkedin.com%2Fin%2Fjane-smith%2F&attendance_scope=visitor&page=1&pageSize=20" \ -H "Authorization: Bearer $LENSMOR_API_KEY" ``` @@ -76,6 +77,7 @@ curl "https://platform.lensmor.com/external/personnel/events/by-linkedin?linkedi "country": "United States", "exhibitorCount": 950, "sponsorMatchStarred": 0, + "attendance_identity": ["visitor"], "image": null, "dataSource": "Lensmor" } @@ -103,6 +105,7 @@ curl "https://platform.lensmor.com/external/personnel/events/by-linkedin?linkedi | `events` | Paginated event results connected to the matched person. | | `events.items[].eventId` | Public event identifier for event-scoped follow-up calls. | | `events.items[].sponsorMatchStarred` | Sponsor Match starred state (`0` or `1`). | +| `events.items[].attendance_identity` | Complete array of this person's identities at this event: `exhibitor_employee` and/or `visitor`. | | `events.items[].dataSource` | Always `Lensmor` for public event records. | | `events.total`, `events.page`, `events.pageSize`, `events.totalPages`, `events.hasMore` | Pagination metadata. | diff --git a/api-reference-backup/personnel/events-by-name.mdx b/api-reference-backup/personnel/events-by-name.mdx index b5d0444..983b8c5 100644 --- a/api-reference-backup/personnel/events-by-name.mdx +++ b/api-reference-backup/personnel/events-by-name.mdx @@ -1,6 +1,6 @@ --- title: "Personnel events by name" -description: "Find upcoming or date-filtered Lensmor events associated with personnel records by exact full-name matching." +description: "Find Lensmor events from 2026 onward, or set a date range, by exact personnel full-name matching." openapi: "openapi.json GET /external/personnel/events/by-name" --- @@ -25,7 +25,8 @@ See [Authentication](/authentication). The API-key owner must have an active pai | Name | Required | Type | Notes | | --- | --- | --- | --- | | `person_name` | Yes | string | Exact full name, length `1` to `200`. Matching is case-insensitive and leading/trailing whitespace is ignored. Partial and fuzzy matching are not used. | -| `date_start_from` | No | date | Inclusive lower bound on event start date. Defaults to the current date, so the default result contains upcoming events. | +| `attendance_scope` | No | string | `all` (default), `exhibitor_employee`, or `visitor`. `exhibitor_employee` includes dual-identity events; `visitor` returns visitor-only events and excludes exhibitor-employee evidence. Other values, including `null`, return `400`. | +| `date_start_from` | No | date | Inclusive lower bound on event start date. Defaults to `2026-01-01` when omitted. | | `date_start_to` | No | date | Inclusive upper bound on event start date. Omit for no upper bound. | | `page` | No | integer | Defaults to `1`. | | `pageSize` | No | integer | Defaults to `20`; maximum `100`. This paginates events, not personnel candidates. | @@ -34,7 +35,7 @@ See [Authentication](/authentication). The API-key owner must have an active pai ## Request example ```bash -curl "https://platform.lensmor.com/external/personnel/events/by-name?person_name=Jane%20Smith&date_start_from=2026-08-10&date_start_to=2026-12-31&page=1&pageSize=20" \ +curl "https://platform.lensmor.com/external/personnel/events/by-name?person_name=Jane%20Smith&attendance_scope=visitor&date_start_from=2026-08-10&date_start_to=2026-12-31&page=1&pageSize=20" \ -H "Authorization: Bearer $LENSMOR_API_KEY" \ -H "x-call-source: api" ``` @@ -60,6 +61,7 @@ curl "https://platform.lensmor.com/external/personnel/events/by-name?person_name "exhibitorCount": 950, "hasVisitors": true, "sponsorMatchStarred": 0, + "attendance_identity": ["visitor"], "image": null, "dataSource": "Lensmor" } @@ -76,6 +78,7 @@ curl "https://platform.lensmor.com/external/personnel/events/by-name?person_name - The server considers up to `50` personnel records with the exact full name. This candidate window is fixed and independent of event `pageSize`. - Events from those exact-name records are combined and deduplicated, then ordered by `dateStart` ascending. +- Attendance evidence is combined per event across the exact-name personnel matches before scope filtering. `attendance_scope=visitor` excludes an event if any matched person has exhibitor-employee evidence there. Every event includes the complete `attendance_identity` array for the matching person or people at that event. - Both date bounds apply inclusively to `dateStart`. Set an earlier `date_start_from` to include historical events. - No personnel match or no qualifying event returns `200 OK` with `items: []`, `total: 0`, `totalPages: 0`, and `hasMore: false`. diff --git a/api-reference-backup/personnel/events.mdx b/api-reference-backup/personnel/events.mdx index 8db9733..4337881 100644 --- a/api-reference-backup/personnel/events.mdx +++ b/api-reference-backup/personnel/events.mdx @@ -27,12 +27,13 @@ See [Authentication](/authentication) | Name | Required | Type | Notes | | --- | --- | --- | --- | | `personnel_id` | Yes | string | Numeric-string personnel identifier. | +| `attendance_scope` | No | string | `all` (default), `exhibitor_employee`, or `visitor`. `exhibitor_employee` includes dual-identity events; `visitor` returns visitor-only events and excludes exhibitor-employee evidence. Other values, including `null`, return `400`. | | `page` | No | integer | Defaults to `1`. | | `pageSize` | No | integer | Defaults to `20`; maximum `100`. | ## Request example ```bash -curl "https://platform.lensmor.com/external/personnel/events?personnel_id=789&page=1&pageSize=20" \ +curl "https://platform.lensmor.com/external/personnel/events?personnel_id=789&attendance_scope=visitor&page=1&pageSize=20" \ -H "Authorization: Bearer $LENSMOR_API_KEY" ``` @@ -55,6 +56,7 @@ curl "https://platform.lensmor.com/external/personnel/events?personnel_id=789&pa "country": "United States", "exhibitorCount": 950, "sponsorMatchStarred": 0, + "attendance_identity": ["visitor"], "image": null, "dataSource": "Lensmor" } @@ -78,6 +80,7 @@ curl "https://platform.lensmor.com/external/personnel/events?personnel_id=789&pa | `venue`, `city`, `region`, `country` | Location metadata. | | `exhibitorCount` | Known exhibitor count when available. | | `sponsorMatchStarred` | Sponsor Match starred state (`0` or `1`). | +| `attendance_identity` | Complete array of this person's identities at this event: `exhibitor_employee` and/or `visitor`. | | `image` | Event image URL when available. | | `dataSource` | Always `Lensmor` for public event records. | | `total`, `page`, `pageSize`, `totalPages`, `hasMore` | Pagination metadata. | diff --git a/api-reference/openapi.json b/api-reference/openapi.json index 9e11e78..192abd0 100644 --- a/api-reference/openapi.json +++ b/api-reference/openapi.json @@ -1172,7 +1172,7 @@ "Exhibitors" ], "summary": "Search events by exhibitor company name", - "description": "Find deduplicated events associated with exhibitor companies that match a required company name.\n\nUse this endpoint for account planning, CRM enrichment, or the question “which events is this company associated with?” without first resolving an exhibitor ID. Optional `sponsor_match_starred` filtering can select starred or non-starred Sponsor Match events; omit it to include both states.\n\nThe endpoint returns events, not exhibitor records. A non-empty result consumes `50` credits and an empty result consumes `0` credits, so check the balance before bulk or user-confirmed searches. Matching is precision-first and incomplete names can legitimately return no results.", + "description": "Find deduplicated events associated with exhibitor companies matching a required company name. Use this for account planning or CRM enrichment without first resolving `exhibitor_id`. The precision-first matcher can return no result for incomplete names. A non-empty result consumes `50` credits; an empty result consumes `0`. `sponsor_match_starred` optionally selects starred or non-starred events.\n\n`attendance_scope` accepts `all` (default), `exhibitor`, or `visitor`. `exhibitor` includes events with exhibitor evidence, even when visitor evidence is present. `visitor` returns visitor-only events and excludes exhibitor evidence. Each event includes `attendance_identity`; visitor-only results can have an empty `matchedExhibitors` array.", "operationId": "searchEventsByExhibitorCompanyName", "parameters": [ { @@ -1225,6 +1225,10 @@ "id": "456", "companyName": "Acme Retail Systems" } + ], + "attendance_identity": [ + "exhibitor", + "visitor" ] } ], @@ -1317,12 +1321,15 @@ "Exhibitors" ], "summary": "List exhibitor related events", - "description": "Return a paginated list of Lensmor events associated with one known exhibitor identifier.\n\nUse this endpoint when an exhibitor profile has already been resolved and the integration needs the company's event history or current event associations. Event items use the shared public event shape and can be passed to event detail, fit scoring, ranking, or access workflows. Follow `hasMore` and increment `page` to retrieve additional results.\n\nIf the starting input is only a company name, use exhibitor event search instead. An exhibitor with no associated events returns a successful empty page; an unknown exhibitor identifier returns an error.", + "description": "Return a paginated list of Lensmor events for a known `exhibitor_id`. Use it after resolving an exhibitor profile to browse company event associations. Follow `hasMore` and increment `page` for more results; an exhibitor with no associated events returns an empty page, while an unknown ID returns an error.\n\n`attendance_scope` accepts `all` (default), `exhibitor`, or `visitor`. `all` returns events with known attendance evidence. `exhibitor` includes events with exhibitor evidence, even when visitor evidence is also present. `visitor` returns visitor-only events and excludes events with exhibitor evidence. Each item includes an event-scoped `attendance_identity` array. If you only have a company name, use exhibitor event search.", "operationId": "listExhibitorEvents", "parameters": [ { "$ref": "#/components/parameters/ExhibitorIdQuery" }, + { + "$ref": "#/components/parameters/CompanyAttendanceScopeQuery" + }, { "$ref": "#/components/parameters/Page" }, @@ -1336,7 +1343,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/EventPage" + "$ref": "#/components/schemas/ExhibitorRelatedEventPage" }, "example": { "items": [ @@ -1347,10 +1354,13 @@ "dateStart": "2026-01-12", "dateEnd": "2026-01-15", "city": "New York", - "country": "United States" + "country": "United States", + "attendance_identity": [ + "visitor" + ] } ], - "total": 12, + "total": 1, "page": 1, "pageSize": 20, "totalPages": 1, @@ -1371,7 +1381,14 @@ "429": { "$ref": "#/components/responses/RateLimited" } - } + }, + "x-codeSamples": [ + { + "lang": "curl", + "label": "cURL", + "source": "curl --request GET \\\n --url 'https://platform.lensmor.com/external/exhibitors/events?exhibitor_id=456&attendance_scope=visitor&page=1&pageSize=20' \\\n --header 'Authorization: Bearer '" + } + ] } }, "/external/personnel/list": { @@ -1572,12 +1589,15 @@ "Personnel" ], "summary": "List personnel related events", - "description": "Return a paginated list of Lensmor events associated with one known personnel identifier.\n\nUse this endpoint when the integration already has `personnel_id` and needs the person's event history or current event associations. Returned event items use the shared public event shape and can be passed directly to event detail, scoring, ranking, or event-access workflows. Follow `hasMore` and increment `page` when additional results are available.\n\nThis lookup does not expose or unlock contact data. If the starting identifier is a LinkedIn URL, use the LinkedIn-based lookup; if only a full name is available, use the exact-name event search and account for its credit and concurrency rules.", + "description": "Return paginated events associated with a known `personnel_id`. Use it after resolving the person to browse event history or current associations. Follow `hasMore` and increment `page` for additional results. This lookup does not expose or unlock contact data. Use the LinkedIn URL or exact-name lookup when a Lensmor personnel ID is unavailable.\n\n`attendance_scope` accepts `all` (default), `exhibitor_employee`, or `visitor`. `all` returns events with known attendance evidence. `exhibitor_employee` includes events with employee evidence, even when visitor evidence is also present. `visitor` returns visitor-only events and excludes events with exhibitor-employee evidence. Each item includes an event-scoped `attendance_identity` array.", "operationId": "listPersonnelEvents", "parameters": [ { "$ref": "#/components/parameters/PersonnelIdQuery" }, + { + "$ref": "#/components/parameters/PersonnelAttendanceScopeQuery" + }, { "$ref": "#/components/parameters/Page" }, @@ -1591,14 +1611,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/EventPage" + "$ref": "#/components/schemas/PersonnelRelatedEventPage" }, "example": { "items": [ { "id": "501", "eventId": "139574", - "name": "Retail Technology Expo 2026" + "name": "Retail Technology Expo 2026", + "attendance_identity": [ + "visitor" + ] } ], "total": 1, @@ -1622,7 +1645,14 @@ "429": { "$ref": "#/components/responses/RateLimited" } - } + }, + "x-codeSamples": [ + { + "lang": "curl", + "label": "cURL", + "source": "curl --request GET \\\n --url 'https://platform.lensmor.com/external/personnel/events?personnel_id=789&attendance_scope=visitor&page=1&pageSize=20' \\\n --header 'Authorization: Bearer '" + } + ] } }, "/external/personnel/events/by-linkedin": { @@ -1631,7 +1661,7 @@ "Personnel" ], "summary": "List personnel related events by LinkedIn URL", - "description": "Normalize a public LinkedIn profile URL, resolve the matching Lensmor personnel record, and return that person's related events.\n\nUse this endpoint for browser-extension, CRM-enrichment, or research workflows where LinkedIn URL is the stable starting identifier. The response includes personnel context plus a paginated event list, allowing the client to recover a Lensmor personnel ID for later profile or contact workflows. Continue through pages only while `hasMore` is true.\n\nURL normalization handles common LinkedIn profile variations, but a URL that cannot be resolved returns a not-found response. This call is read-only and does not unlock contact data.", + "description": "Normalize a public LinkedIn profile URL, resolve its matching Lensmor personnel record, and return the person plus paginated related events. Use this lookup when a LinkedIn URL is the stable starting identifier; a URL that cannot be resolved returns not found. The call does not unlock contact data. Follow `hasMore` for additional event pages.\n\n`attendance_scope` accepts `all` (default), `exhibitor_employee`, or `visitor`. `all` returns events with known attendance evidence. `exhibitor_employee` includes dual-identity events. `visitor` returns visitor-only events and excludes events with exhibitor-employee evidence. Each event includes an event-scoped `attendance_identity` array.", "operationId": "listPersonnelEventsByLinkedin", "parameters": [ { @@ -1645,6 +1675,9 @@ "description": "Public LinkedIn profile URL used for normalized personnel matching.", "example": "https://www.linkedin.com/in/jane-doe" }, + { + "$ref": "#/components/parameters/PersonnelAttendanceScopeQuery" + }, { "$ref": "#/components/parameters/Page" }, @@ -1668,7 +1701,7 @@ "$ref": "#/components/schemas/ContactItem" }, "events": { - "$ref": "#/components/schemas/EventPage" + "$ref": "#/components/schemas/PersonnelRelatedEventPage" } } }, @@ -1688,7 +1721,10 @@ { "id": "501", "eventId": "139574", - "name": "Retail Technology Expo 2026" + "name": "Retail Technology Expo 2026", + "attendance_identity": [ + "visitor" + ] } ], "total": 1, @@ -1713,7 +1749,14 @@ "429": { "$ref": "#/components/responses/RateLimited" } - } + }, + "x-codeSamples": [ + { + "lang": "curl", + "label": "cURL", + "source": "curl --request GET \\\n --url 'https://platform.lensmor.com/external/personnel/events/by-linkedin?linkedin_url=https%3A%2F%2Fwww.linkedin.com%2Fin%2Fjane-smith&attendance_scope=visitor&page=1&pageSize=20' \\\n --header 'Authorization: Bearer '" + } + ] } }, "/external/personnel/events/by-name": { @@ -1722,7 +1765,7 @@ "Personnel" ], "summary": "Search personnel related events by name", - "description": "Find a paginated, deduplicated event list for up to 50 personnel records whose full name exactly matches the supplied name.\n\nUse this endpoint only when neither a Lensmor personnel ID nor a LinkedIn URL is available. Matching is case-insensitive after trimming but is not partial or fuzzy. Date filters apply to event start dates; without `date_start_from`, the search defaults to upcoming events.\n\nThis endpoint requires an active paid user. A non-empty result consumes `50` credits, an empty result consumes `0` credits, and at most `10 requests` can run concurrently for one user. The response contains events rather than a separate personnel object.", + "description": "Find paginated, deduplicated events for up to 50 personnel records with the exact full name. Matching ignores case and surrounding whitespace. Date filters use event start dates; `date_start_from` defaults to `2026-01-01`. A non-empty result consumes `50` credits; an empty result consumes `0`. Up to `10 requests` can run concurrently per user.\n\n`attendance_scope` accepts `all` (default), `exhibitor_employee`, or `visitor`. `all` includes known attendance evidence. `exhibitor_employee` includes dual-identity events. `visitor` returns visitor-only events and excludes exhibitor-employee evidence. Evidence is combined per event across matched people before filtering. Each event returns the complete `attendance_identity` array.", "operationId": "searchPersonnelEventsByName", "parameters": [ { @@ -1737,16 +1780,20 @@ }, "example": "Jane Doe" }, + { + "$ref": "#/components/parameters/PersonnelAttendanceScopeQuery" + }, { "name": "date_start_from", "in": "query", "required": false, - "description": "Inclusive event start-date lower bound. Defaults to the current date when omitted.", + "description": "Inclusive event start-date lower bound. Defaults to `2026-01-01` when omitted.", "schema": { "type": "string", - "format": "date" + "format": "date", + "default": "2026-01-01" }, - "example": "2025-01-01" + "example": "2026-01-01" }, { "name": "date_start_to", @@ -1757,7 +1804,7 @@ "type": "string", "format": "date" }, - "example": "2025-12-31" + "example": "2026-12-31" }, { "$ref": "#/components/parameters/Page" @@ -1777,7 +1824,7 @@ "schema": { "oneOf": [ { - "$ref": "#/components/schemas/EventPage" + "$ref": "#/components/schemas/PersonnelRelatedEventPage" }, { "$ref": "#/components/schemas/FeatureUnavailableBusinessError" @@ -1808,7 +1855,10 @@ "hasVisitors": true, "sponsorMatchStarred": 0, "image": null, - "dataSource": "Lensmor" + "dataSource": "Lensmor", + "attendance_identity": [ + "visitor" + ] } ], "total": 1, @@ -1862,7 +1912,14 @@ "429": { "$ref": "#/components/responses/RateLimited" } - } + }, + "x-codeSamples": [ + { + "lang": "curl", + "label": "cURL", + "source": "curl --request GET \\\n --url 'https://platform.lensmor.com/external/personnel/events/by-name?person_name=Jane%20Smith&attendance_scope=visitor&page=1&pageSize=20' \\\n --header 'Authorization: Bearer '" + } + ] } }, "/external/personnel/unlock-linkedin-activity": { @@ -2787,6 +2844,38 @@ }, "description": "Identify the caller as `api` or `agent` for usage attribution. Defaults to `api` when omitted.", "example": "api" + }, + "CompanyAttendanceScopeQuery": { + "name": "attendance_scope", + "in": "query", + "required": false, + "description": "Filter events by this company's attendance identity. Defaults to `all`. `exhibitor` includes events with exhibitor evidence, including events that also have visitor evidence. `visitor` returns visitor-only events and excludes events with exhibitor evidence. Only `all`, `exhibitor`, and `visitor` are valid; other values, including `null`, return 400.", + "schema": { + "type": "string", + "enum": [ + "all", + "exhibitor", + "visitor" + ], + "default": "all" + }, + "example": "visitor" + }, + "PersonnelAttendanceScopeQuery": { + "name": "attendance_scope", + "in": "query", + "required": false, + "description": "Filter events by attendance identities for the matched person or people. Defaults to `all`. `exhibitor_employee` includes events with exhibitor-employee evidence, including events that also have visitor evidence. `visitor` returns visitor-only events and excludes events with exhibitor-employee evidence. Exact-name lookups combine evidence per event across matched personnel before applying this filter. Only `all`, `exhibitor_employee`, and `visitor` are valid; other values, including `null`, return 400.", + "schema": { + "type": "string", + "enum": [ + "all", + "exhibitor_employee", + "visitor" + ], + "default": "all" + }, + "example": "visitor" } }, "requestBodies": { @@ -2955,6 +3044,17 @@ "default": 20, "description": "Maximum records requested per page; defaults to `20` and cannot exceed `100`.", "example": 20 + }, + "attendance_scope": { + "type": "string", + "enum": [ + "all", + "exhibitor", + "visitor" + ], + "default": "all", + "description": "Filter events by this company's attendance identity. Defaults to `all`. `exhibitor` includes events with exhibitor evidence, including events that also have visitor evidence. `visitor` returns visitor-only events and excludes events with exhibitor evidence. Only `all`, `exhibitor`, and `visitor` are valid; other values, including `null`, return 400.", + "example": "exhibitor" } } }, @@ -2962,11 +3062,12 @@ "company_name": "Acme", "sponsor_match_starred": 1, "page": 1, - "pageSize": 20 + "pageSize": 20, + "attendance_scope": "exhibitor" } } }, - "description": "Provide the company name, optional Sponsor Match filter, and pagination for event reverse search." + "description": "Provide the company name, optional Sponsor Match filter, and pagination for event reverse search. Optional `attendance_scope` filters by company attendance identity and defaults to `all`." }, "ProfileMatchingBody": { "required": true, @@ -3724,7 +3825,8 @@ { "type": "object", "required": [ - "matchedExhibitors" + "matchedExhibitors", + "attendance_identity" ], "properties": { "matchedExhibitors": { @@ -3732,12 +3834,27 @@ "items": { "$ref": "#/components/schemas/MatchedExhibitorSummary" }, - "description": "Matched Exhibitors returned as part of this event reverse search item object." + "description": "Admitted company matches with exhibitor relationships at this event. This array can be empty for visitor-only results." + }, + "attendance_identity": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "exhibitor", + "visitor" + ] + }, + "description": "Complete attendance identities for this company at this event. An event matched by a scope still returns its complete identity array.", + "example": [ + "exhibitor", + "visitor" + ] } } } ], - "description": "Event result enriched with the exhibitor company that produced the reverse-search match." + "description": "Event result with the company's attendance identities and any matched exhibitor relationships. Visitor-only results can have an empty matchedExhibitors array." }, "EventReverseSearchPage": { "type": "object", @@ -5960,6 +6077,152 @@ } ], "description": "Full Lensmor event metadata plus profile-recommendation evidence and rank." + }, + "ExhibitorRelatedEventItem": { + "allOf": [ + { + "$ref": "#/components/schemas/EventItem" + }, + { + "type": "object", + "required": [ + "attendance_identity" + ], + "properties": { + "attendance_identity": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "exhibitor", + "visitor" + ] + }, + "description": "Complete attendance identities for this company at this event. An event matched by a scope still returns its complete identity array.", + "example": [ + "exhibitor", + "visitor" + ] + } + } + } + ], + "description": "Event returned by a company reverse lookup with event-scoped attendance identities." + }, + "PersonnelRelatedEventItem": { + "allOf": [ + { + "$ref": "#/components/schemas/EventItem" + }, + { + "type": "object", + "required": [ + "attendance_identity" + ], + "properties": { + "attendance_identity": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "exhibitor_employee", + "visitor" + ] + }, + "description": "Complete attendance identities for the matched personnel at this event. Exact-name lookups combine evidence across matched personnel records before filtering. Scope filtering does not trim the returned identity array.", + "example": [ + "exhibitor_employee", + "visitor" + ] + } + } + } + ], + "description": "Event returned by a person reverse lookup with event-scoped attendance identities." + }, + "ExhibitorRelatedEventPage": { + "type": "object", + "required": [ + "items", + "total", + "page", + "pageSize", + "totalPages", + "hasMore" + ], + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ExhibitorRelatedEventItem" + }, + "description": "Records returned on the current page or in the current batch." + }, + "total": { + "type": "integer", + "description": "Total matching records across all pages." + }, + "page": { + "type": "integer", + "description": "One-based page number returned." + }, + "pageSize": { + "type": "integer", + "description": "Maximum records requested for this page." + }, + "totalPages": { + "type": "integer", + "description": "Total pages available for the current query." + }, + "hasMore": { + "type": "boolean", + "description": "Whether another result page is available." + } + }, + "additionalProperties": true, + "description": "Paginated company-related events with attendance identities." + }, + "PersonnelRelatedEventPage": { + "type": "object", + "required": [ + "items", + "total", + "page", + "pageSize", + "totalPages", + "hasMore" + ], + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PersonnelRelatedEventItem" + }, + "description": "Records returned on the current page or in the current batch." + }, + "total": { + "type": "integer", + "description": "Total matching records across all pages." + }, + "page": { + "type": "integer", + "description": "One-based page number returned." + }, + "pageSize": { + "type": "integer", + "description": "Maximum records requested for this page." + }, + "totalPages": { + "type": "integer", + "description": "Total pages available for the current query." + }, + "hasMore": { + "type": "boolean", + "description": "Whether another result page is available." + } + }, + "additionalProperties": true, + "description": "Paginated person-related events with attendance identities." } } } diff --git a/llms-full.txt b/llms-full.txt index 617c5ac..1ed30f5 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -2836,6 +2836,7 @@ See [Authentication](/authentication) | Name | Required | Type | Notes | | --- | --- | --- | --- | | `company_name` | Yes | string | Company name input. Incomplete names are allowed, but matching stays precision-first. | +| `attendance_scope` | No | string | `all` (default), `exhibitor`, or `visitor`. `exhibitor` includes dual-identity events; `visitor` returns visitor-only events and excludes exhibitor evidence. Other values, including `null`, return `400`. | | `sponsor_match_starred` | No | integer | `1` returns starred Sponsor Match events, `0` returns non-starred events; omit to include both. | | `page` | No | integer | Defaults to `1`. | | `pageSize` | No | integer | Defaults to `20`; maximum `100`. | @@ -2851,7 +2852,7 @@ curl -X POST "https://platform.lensmor.com/external/exhibitors/search-events" \ -H "Authorization: Bearer $LENSMOR_API_KEY" \ -H "Content-Type: application/json" \ -H "x-call-source: api" \ - -d '{"company_name":"Acme","sponsor_match_starred":1,"page":1,"pageSize":20}' + -d '{"company_name":"Acme","attendance_scope":"exhibitor","sponsor_match_starred":1,"page":1,"pageSize":20}' ``` ## Response example @@ -2873,6 +2874,7 @@ curl -X POST "https://platform.lensmor.com/external/exhibitors/search-events" \ "country": "United States", "exhibitorCount": 100, "sponsorMatchStarred": 1, + "attendance_identity": ["exhibitor", "visitor"], "image": null, "dataSource": "Lensmor", "matchedExhibitors": [ @@ -2903,14 +2905,15 @@ curl -X POST "https://platform.lensmor.com/external/exhibitors/search-events" \ | `exhibitorCount` | Exhibitor coverage count when available. | | `sponsorMatchStarred` | Sponsor Match starred state (`0` or `1`). | | `dataSource` | Always `Lensmor` for public event records. | -| `matchedExhibitors` | Matched company records that connect the input to the returned event. Treat this as the primary evidence that the company-name input matched the returned event. | +| `attendance_identity` | Complete array of this company's identities at this event: `exhibitor` and/or `visitor`. | +| `matchedExhibitors` | Matched exhibitor relationships. Visitor-only events can have an empty array. | | `total`, `page`, `pageSize`, `totalPages`, `hasMore` | Pagination metadata. | ## Credit behavior This endpoint consumes `50` credits after the company-name matcher finds at least one event. A successful empty response consumes `0` credits. If a non-empty search cannot spend the required credits, the API returns `402 Payment Required` instead of returning the matched records. -Refresh [Credits balance](/api-reference/credits/get-credits-balance) after successful searches when your UI or audit log needs final credit reconciliation. Use the returned event count, page count, and `matchedExhibitors` as the main value evidence for the search result. +Refresh [Credits balance](/api-reference/credits/get-credits-balance) after successful searches when your UI or audit log needs final credit reconciliation. Use the returned event count, pagination, and `attendance_identity` to interpret the search result. `matchedExhibitors` can be empty for visitor-only events. ## Concurrency limit @@ -3044,12 +3047,13 @@ See [Authentication](/authentication) | Name | Required | Type | Notes | | --- | --- | --- | --- | | `exhibitor_id` | Yes | string | Numeric-string exhibitor identifier. | +| `attendance_scope` | No | string | `all` (default), `exhibitor`, or `visitor`. `exhibitor` includes events with exhibitor evidence, including dual-identity events. `visitor` returns visitor-only events and excludes exhibitor evidence. Other values, including `null`, return `400`. | | `page` | No | integer | Defaults to `1`. | | `pageSize` | No | integer | Defaults to `20`; maximum `100`. | ## Request example ```bash -curl "https://platform.lensmor.com/external/exhibitors/events?exhibitor_id=456&page=1&pageSize=20" \ +curl "https://platform.lensmor.com/external/exhibitors/events?exhibitor_id=456&attendance_scope=visitor&page=1&pageSize=20" \ -H "Authorization: Bearer $LENSMOR_API_KEY" ``` @@ -3072,11 +3076,12 @@ curl "https://platform.lensmor.com/external/exhibitors/events?exhibitor_id=456&p "country": "United States", "exhibitorCount": 950, "sponsorMatchStarred": 0, + "attendance_identity": ["visitor"], "image": null, "dataSource": "Lensmor" } ], - "total": 12, + "total": 1, "page": 1, "pageSize": 20, "totalPages": 1, @@ -3095,6 +3100,7 @@ curl "https://platform.lensmor.com/external/exhibitors/events?exhibitor_id=456&p | `venue`, `city`, `region`, `country` | Location metadata. | | `exhibitorCount` | Known exhibitor count when available. | | `sponsorMatchStarred` | Sponsor Match starred state (`0` or `1`). | +| `attendance_identity` | Complete array of this company's identities at this event: `exhibitor` and/or `visitor`. | | `image` | Event image URL when available. | | `dataSource` | Always `Lensmor` for public event records. | | `total`, `page`, `pageSize`, `totalPages`, `hasMore` | Pagination metadata. | @@ -3106,7 +3112,7 @@ curl "https://platform.lensmor.com/external/exhibitors/events?exhibitor_id=456&p - `429 Too Many Requests` ## Notes -- Event items reuse the standard event-item response shape. +- Event items include the standard event fields and the event-scoped `attendance_identity` array. With `attendance_scope=all`, a dual-identity event can return `["exhibitor", "visitor"]`. - Pagination behavior follows the shared [Pagination conventions](/concepts/pagination). - This endpoint requires `exhibitor_id`; if you only have `company_name`, use `POST /external/exhibitors/search-events`. @@ -3401,12 +3407,13 @@ See [Authentication](/authentication) | Name | Required | Type | Notes | | --- | --- | --- | --- | | `personnel_id` | Yes | string | Numeric-string personnel identifier. | +| `attendance_scope` | No | string | `all` (default), `exhibitor_employee`, or `visitor`. `exhibitor_employee` includes dual-identity events; `visitor` returns visitor-only events and excludes exhibitor-employee evidence. Other values, including `null`, return `400`. | | `page` | No | integer | Defaults to `1`. | | `pageSize` | No | integer | Defaults to `20`; maximum `100`. | ## Request example ```bash -curl "https://platform.lensmor.com/external/personnel/events?personnel_id=789&page=1&pageSize=20" \ +curl "https://platform.lensmor.com/external/personnel/events?personnel_id=789&attendance_scope=visitor&page=1&pageSize=20" \ -H "Authorization: Bearer $LENSMOR_API_KEY" ``` @@ -3429,6 +3436,7 @@ curl "https://platform.lensmor.com/external/personnel/events?personnel_id=789&pa "country": "United States", "exhibitorCount": 950, "sponsorMatchStarred": 0, + "attendance_identity": ["visitor"], "image": null, "dataSource": "Lensmor" } @@ -3452,6 +3460,7 @@ curl "https://platform.lensmor.com/external/personnel/events?personnel_id=789&pa | `venue`, `city`, `region`, `country` | Location metadata. | | `exhibitorCount` | Known exhibitor count when available. | | `sponsorMatchStarred` | Sponsor Match starred state (`0` or `1`). | +| `attendance_identity` | Complete array of this person's identities at this event: `exhibitor_employee` and/or `visitor`. | | `image` | Event image URL when available. | | `dataSource` | Always `Lensmor` for public event records. | | `total`, `page`, `pageSize`, `totalPages`, `hasMore` | Pagination metadata. | @@ -3500,12 +3509,13 @@ See [Authentication](/authentication) | Name | Required | Type | Notes | | --- | --- | --- | --- | | `linkedin_url` | Yes | string | LinkedIn profile URL used for normalized matching. | +| `attendance_scope` | No | string | `all` (default), `exhibitor_employee`, or `visitor`. `exhibitor_employee` includes dual-identity events; `visitor` returns visitor-only events and excludes exhibitor-employee evidence. Other values, including `null`, return `400`. | | `page` | No | integer | Defaults to `1`. | | `pageSize` | No | integer | Defaults to `20`; maximum `100`. | ## Request example ```bash -curl "https://platform.lensmor.com/external/personnel/events/by-linkedin?linkedin_url=https%3A%2F%2Fwww.linkedin.com%2Fin%2Fjane-smith%2F" \ +curl "https://platform.lensmor.com/external/personnel/events/by-linkedin?linkedin_url=https%3A%2F%2Fwww.linkedin.com%2Fin%2Fjane-smith%2F&attendance_scope=visitor&page=1&pageSize=20" \ -H "Authorization: Bearer $LENSMOR_API_KEY" ``` @@ -3544,6 +3554,7 @@ curl "https://platform.lensmor.com/external/personnel/events/by-linkedin?linkedi "country": "United States", "exhibitorCount": 950, "sponsorMatchStarred": 0, + "attendance_identity": ["visitor"], "image": null, "dataSource": "Lensmor" } @@ -3571,6 +3582,7 @@ curl "https://platform.lensmor.com/external/personnel/events/by-linkedin?linkedi | `events` | Paginated event results connected to the matched person. | | `events.items[].eventId` | Public event identifier for event-scoped follow-up calls. | | `events.items[].sponsorMatchStarred` | Sponsor Match starred state (`0` or `1`). | +| `events.items[].attendance_identity` | Complete array of this person's identities at this event: `exhibitor_employee` and/or `visitor`. | | `events.items[].dataSource` | Always `Lensmor` for public event records. | | `events.total`, `events.page`, `events.pageSize`, `events.totalPages`, `events.hasMore` | Pagination metadata. | @@ -3627,7 +3639,8 @@ See [Authentication](/authentication). The API-key owner must have an active pai | Name | Required | Type | Notes | | --- | --- | --- | --- | | `person_name` | Yes | string | Exact full name, length `1` to `200`. Matching is case-insensitive and leading/trailing whitespace is ignored. Partial and fuzzy matching are not used. | -| `date_start_from` | No | date | Inclusive lower bound on event start date. Defaults to the current date, so the default result contains upcoming events. | +| `attendance_scope` | No | string | `all` (default), `exhibitor_employee`, or `visitor`. `exhibitor_employee` includes dual-identity events; `visitor` returns visitor-only events and excludes exhibitor-employee evidence. Other values, including `null`, return `400`. | +| `date_start_from` | No | date | Inclusive lower bound on event start date. Defaults to `2026-01-01` when omitted. | | `date_start_to` | No | date | Inclusive upper bound on event start date. Omit for no upper bound. | | `page` | No | integer | Defaults to `1`. | | `pageSize` | No | integer | Defaults to `20`; maximum `100`. This paginates events, not personnel candidates. | @@ -3636,7 +3649,7 @@ See [Authentication](/authentication). The API-key owner must have an active pai ## Request example ```bash -curl "https://platform.lensmor.com/external/personnel/events/by-name?person_name=Jane%20Smith&date_start_from=2026-08-10&date_start_to=2026-12-31&page=1&pageSize=20" \ +curl "https://platform.lensmor.com/external/personnel/events/by-name?person_name=Jane%20Smith&attendance_scope=visitor&date_start_from=2026-08-10&date_start_to=2026-12-31&page=1&pageSize=20" \ -H "Authorization: Bearer $LENSMOR_API_KEY" \ -H "x-call-source: api" ``` @@ -3662,6 +3675,7 @@ curl "https://platform.lensmor.com/external/personnel/events/by-name?person_name "exhibitorCount": 950, "hasVisitors": true, "sponsorMatchStarred": 0, + "attendance_identity": ["visitor"], "image": null, "dataSource": "Lensmor" } @@ -3678,6 +3692,7 @@ curl "https://platform.lensmor.com/external/personnel/events/by-name?person_name - The server considers up to `50` personnel records with the exact full name. This candidate window is fixed and independent of event `pageSize`. - Events from those exact-name records are combined and deduplicated, then ordered by `dateStart` ascending. +- Attendance evidence is combined per event across the exact-name personnel matches before scope filtering. `attendance_scope=visitor` excludes an event if any matched person has exhibitor-employee evidence there. Every event includes the complete `attendance_identity` array for the matching person or people at that event. - Both date bounds apply inclusively to `dateStart`. Set an earlier `date_start_from` to include historical events. - No personnel match or no qualifying event returns `200 OK` with `items: []`, `total: 0`, `totalPages: 0`, and `hasMore: false`. diff --git a/openapi.json b/openapi.json index 9e11e78..192abd0 100644 --- a/openapi.json +++ b/openapi.json @@ -1172,7 +1172,7 @@ "Exhibitors" ], "summary": "Search events by exhibitor company name", - "description": "Find deduplicated events associated with exhibitor companies that match a required company name.\n\nUse this endpoint for account planning, CRM enrichment, or the question “which events is this company associated with?” without first resolving an exhibitor ID. Optional `sponsor_match_starred` filtering can select starred or non-starred Sponsor Match events; omit it to include both states.\n\nThe endpoint returns events, not exhibitor records. A non-empty result consumes `50` credits and an empty result consumes `0` credits, so check the balance before bulk or user-confirmed searches. Matching is precision-first and incomplete names can legitimately return no results.", + "description": "Find deduplicated events associated with exhibitor companies matching a required company name. Use this for account planning or CRM enrichment without first resolving `exhibitor_id`. The precision-first matcher can return no result for incomplete names. A non-empty result consumes `50` credits; an empty result consumes `0`. `sponsor_match_starred` optionally selects starred or non-starred events.\n\n`attendance_scope` accepts `all` (default), `exhibitor`, or `visitor`. `exhibitor` includes events with exhibitor evidence, even when visitor evidence is present. `visitor` returns visitor-only events and excludes exhibitor evidence. Each event includes `attendance_identity`; visitor-only results can have an empty `matchedExhibitors` array.", "operationId": "searchEventsByExhibitorCompanyName", "parameters": [ { @@ -1225,6 +1225,10 @@ "id": "456", "companyName": "Acme Retail Systems" } + ], + "attendance_identity": [ + "exhibitor", + "visitor" ] } ], @@ -1317,12 +1321,15 @@ "Exhibitors" ], "summary": "List exhibitor related events", - "description": "Return a paginated list of Lensmor events associated with one known exhibitor identifier.\n\nUse this endpoint when an exhibitor profile has already been resolved and the integration needs the company's event history or current event associations. Event items use the shared public event shape and can be passed to event detail, fit scoring, ranking, or access workflows. Follow `hasMore` and increment `page` to retrieve additional results.\n\nIf the starting input is only a company name, use exhibitor event search instead. An exhibitor with no associated events returns a successful empty page; an unknown exhibitor identifier returns an error.", + "description": "Return a paginated list of Lensmor events for a known `exhibitor_id`. Use it after resolving an exhibitor profile to browse company event associations. Follow `hasMore` and increment `page` for more results; an exhibitor with no associated events returns an empty page, while an unknown ID returns an error.\n\n`attendance_scope` accepts `all` (default), `exhibitor`, or `visitor`. `all` returns events with known attendance evidence. `exhibitor` includes events with exhibitor evidence, even when visitor evidence is also present. `visitor` returns visitor-only events and excludes events with exhibitor evidence. Each item includes an event-scoped `attendance_identity` array. If you only have a company name, use exhibitor event search.", "operationId": "listExhibitorEvents", "parameters": [ { "$ref": "#/components/parameters/ExhibitorIdQuery" }, + { + "$ref": "#/components/parameters/CompanyAttendanceScopeQuery" + }, { "$ref": "#/components/parameters/Page" }, @@ -1336,7 +1343,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/EventPage" + "$ref": "#/components/schemas/ExhibitorRelatedEventPage" }, "example": { "items": [ @@ -1347,10 +1354,13 @@ "dateStart": "2026-01-12", "dateEnd": "2026-01-15", "city": "New York", - "country": "United States" + "country": "United States", + "attendance_identity": [ + "visitor" + ] } ], - "total": 12, + "total": 1, "page": 1, "pageSize": 20, "totalPages": 1, @@ -1371,7 +1381,14 @@ "429": { "$ref": "#/components/responses/RateLimited" } - } + }, + "x-codeSamples": [ + { + "lang": "curl", + "label": "cURL", + "source": "curl --request GET \\\n --url 'https://platform.lensmor.com/external/exhibitors/events?exhibitor_id=456&attendance_scope=visitor&page=1&pageSize=20' \\\n --header 'Authorization: Bearer '" + } + ] } }, "/external/personnel/list": { @@ -1572,12 +1589,15 @@ "Personnel" ], "summary": "List personnel related events", - "description": "Return a paginated list of Lensmor events associated with one known personnel identifier.\n\nUse this endpoint when the integration already has `personnel_id` and needs the person's event history or current event associations. Returned event items use the shared public event shape and can be passed directly to event detail, scoring, ranking, or event-access workflows. Follow `hasMore` and increment `page` when additional results are available.\n\nThis lookup does not expose or unlock contact data. If the starting identifier is a LinkedIn URL, use the LinkedIn-based lookup; if only a full name is available, use the exact-name event search and account for its credit and concurrency rules.", + "description": "Return paginated events associated with a known `personnel_id`. Use it after resolving the person to browse event history or current associations. Follow `hasMore` and increment `page` for additional results. This lookup does not expose or unlock contact data. Use the LinkedIn URL or exact-name lookup when a Lensmor personnel ID is unavailable.\n\n`attendance_scope` accepts `all` (default), `exhibitor_employee`, or `visitor`. `all` returns events with known attendance evidence. `exhibitor_employee` includes events with employee evidence, even when visitor evidence is also present. `visitor` returns visitor-only events and excludes events with exhibitor-employee evidence. Each item includes an event-scoped `attendance_identity` array.", "operationId": "listPersonnelEvents", "parameters": [ { "$ref": "#/components/parameters/PersonnelIdQuery" }, + { + "$ref": "#/components/parameters/PersonnelAttendanceScopeQuery" + }, { "$ref": "#/components/parameters/Page" }, @@ -1591,14 +1611,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/EventPage" + "$ref": "#/components/schemas/PersonnelRelatedEventPage" }, "example": { "items": [ { "id": "501", "eventId": "139574", - "name": "Retail Technology Expo 2026" + "name": "Retail Technology Expo 2026", + "attendance_identity": [ + "visitor" + ] } ], "total": 1, @@ -1622,7 +1645,14 @@ "429": { "$ref": "#/components/responses/RateLimited" } - } + }, + "x-codeSamples": [ + { + "lang": "curl", + "label": "cURL", + "source": "curl --request GET \\\n --url 'https://platform.lensmor.com/external/personnel/events?personnel_id=789&attendance_scope=visitor&page=1&pageSize=20' \\\n --header 'Authorization: Bearer '" + } + ] } }, "/external/personnel/events/by-linkedin": { @@ -1631,7 +1661,7 @@ "Personnel" ], "summary": "List personnel related events by LinkedIn URL", - "description": "Normalize a public LinkedIn profile URL, resolve the matching Lensmor personnel record, and return that person's related events.\n\nUse this endpoint for browser-extension, CRM-enrichment, or research workflows where LinkedIn URL is the stable starting identifier. The response includes personnel context plus a paginated event list, allowing the client to recover a Lensmor personnel ID for later profile or contact workflows. Continue through pages only while `hasMore` is true.\n\nURL normalization handles common LinkedIn profile variations, but a URL that cannot be resolved returns a not-found response. This call is read-only and does not unlock contact data.", + "description": "Normalize a public LinkedIn profile URL, resolve its matching Lensmor personnel record, and return the person plus paginated related events. Use this lookup when a LinkedIn URL is the stable starting identifier; a URL that cannot be resolved returns not found. The call does not unlock contact data. Follow `hasMore` for additional event pages.\n\n`attendance_scope` accepts `all` (default), `exhibitor_employee`, or `visitor`. `all` returns events with known attendance evidence. `exhibitor_employee` includes dual-identity events. `visitor` returns visitor-only events and excludes events with exhibitor-employee evidence. Each event includes an event-scoped `attendance_identity` array.", "operationId": "listPersonnelEventsByLinkedin", "parameters": [ { @@ -1645,6 +1675,9 @@ "description": "Public LinkedIn profile URL used for normalized personnel matching.", "example": "https://www.linkedin.com/in/jane-doe" }, + { + "$ref": "#/components/parameters/PersonnelAttendanceScopeQuery" + }, { "$ref": "#/components/parameters/Page" }, @@ -1668,7 +1701,7 @@ "$ref": "#/components/schemas/ContactItem" }, "events": { - "$ref": "#/components/schemas/EventPage" + "$ref": "#/components/schemas/PersonnelRelatedEventPage" } } }, @@ -1688,7 +1721,10 @@ { "id": "501", "eventId": "139574", - "name": "Retail Technology Expo 2026" + "name": "Retail Technology Expo 2026", + "attendance_identity": [ + "visitor" + ] } ], "total": 1, @@ -1713,7 +1749,14 @@ "429": { "$ref": "#/components/responses/RateLimited" } - } + }, + "x-codeSamples": [ + { + "lang": "curl", + "label": "cURL", + "source": "curl --request GET \\\n --url 'https://platform.lensmor.com/external/personnel/events/by-linkedin?linkedin_url=https%3A%2F%2Fwww.linkedin.com%2Fin%2Fjane-smith&attendance_scope=visitor&page=1&pageSize=20' \\\n --header 'Authorization: Bearer '" + } + ] } }, "/external/personnel/events/by-name": { @@ -1722,7 +1765,7 @@ "Personnel" ], "summary": "Search personnel related events by name", - "description": "Find a paginated, deduplicated event list for up to 50 personnel records whose full name exactly matches the supplied name.\n\nUse this endpoint only when neither a Lensmor personnel ID nor a LinkedIn URL is available. Matching is case-insensitive after trimming but is not partial or fuzzy. Date filters apply to event start dates; without `date_start_from`, the search defaults to upcoming events.\n\nThis endpoint requires an active paid user. A non-empty result consumes `50` credits, an empty result consumes `0` credits, and at most `10 requests` can run concurrently for one user. The response contains events rather than a separate personnel object.", + "description": "Find paginated, deduplicated events for up to 50 personnel records with the exact full name. Matching ignores case and surrounding whitespace. Date filters use event start dates; `date_start_from` defaults to `2026-01-01`. A non-empty result consumes `50` credits; an empty result consumes `0`. Up to `10 requests` can run concurrently per user.\n\n`attendance_scope` accepts `all` (default), `exhibitor_employee`, or `visitor`. `all` includes known attendance evidence. `exhibitor_employee` includes dual-identity events. `visitor` returns visitor-only events and excludes exhibitor-employee evidence. Evidence is combined per event across matched people before filtering. Each event returns the complete `attendance_identity` array.", "operationId": "searchPersonnelEventsByName", "parameters": [ { @@ -1737,16 +1780,20 @@ }, "example": "Jane Doe" }, + { + "$ref": "#/components/parameters/PersonnelAttendanceScopeQuery" + }, { "name": "date_start_from", "in": "query", "required": false, - "description": "Inclusive event start-date lower bound. Defaults to the current date when omitted.", + "description": "Inclusive event start-date lower bound. Defaults to `2026-01-01` when omitted.", "schema": { "type": "string", - "format": "date" + "format": "date", + "default": "2026-01-01" }, - "example": "2025-01-01" + "example": "2026-01-01" }, { "name": "date_start_to", @@ -1757,7 +1804,7 @@ "type": "string", "format": "date" }, - "example": "2025-12-31" + "example": "2026-12-31" }, { "$ref": "#/components/parameters/Page" @@ -1777,7 +1824,7 @@ "schema": { "oneOf": [ { - "$ref": "#/components/schemas/EventPage" + "$ref": "#/components/schemas/PersonnelRelatedEventPage" }, { "$ref": "#/components/schemas/FeatureUnavailableBusinessError" @@ -1808,7 +1855,10 @@ "hasVisitors": true, "sponsorMatchStarred": 0, "image": null, - "dataSource": "Lensmor" + "dataSource": "Lensmor", + "attendance_identity": [ + "visitor" + ] } ], "total": 1, @@ -1862,7 +1912,14 @@ "429": { "$ref": "#/components/responses/RateLimited" } - } + }, + "x-codeSamples": [ + { + "lang": "curl", + "label": "cURL", + "source": "curl --request GET \\\n --url 'https://platform.lensmor.com/external/personnel/events/by-name?person_name=Jane%20Smith&attendance_scope=visitor&page=1&pageSize=20' \\\n --header 'Authorization: Bearer '" + } + ] } }, "/external/personnel/unlock-linkedin-activity": { @@ -2787,6 +2844,38 @@ }, "description": "Identify the caller as `api` or `agent` for usage attribution. Defaults to `api` when omitted.", "example": "api" + }, + "CompanyAttendanceScopeQuery": { + "name": "attendance_scope", + "in": "query", + "required": false, + "description": "Filter events by this company's attendance identity. Defaults to `all`. `exhibitor` includes events with exhibitor evidence, including events that also have visitor evidence. `visitor` returns visitor-only events and excludes events with exhibitor evidence. Only `all`, `exhibitor`, and `visitor` are valid; other values, including `null`, return 400.", + "schema": { + "type": "string", + "enum": [ + "all", + "exhibitor", + "visitor" + ], + "default": "all" + }, + "example": "visitor" + }, + "PersonnelAttendanceScopeQuery": { + "name": "attendance_scope", + "in": "query", + "required": false, + "description": "Filter events by attendance identities for the matched person or people. Defaults to `all`. `exhibitor_employee` includes events with exhibitor-employee evidence, including events that also have visitor evidence. `visitor` returns visitor-only events and excludes events with exhibitor-employee evidence. Exact-name lookups combine evidence per event across matched personnel before applying this filter. Only `all`, `exhibitor_employee`, and `visitor` are valid; other values, including `null`, return 400.", + "schema": { + "type": "string", + "enum": [ + "all", + "exhibitor_employee", + "visitor" + ], + "default": "all" + }, + "example": "visitor" } }, "requestBodies": { @@ -2955,6 +3044,17 @@ "default": 20, "description": "Maximum records requested per page; defaults to `20` and cannot exceed `100`.", "example": 20 + }, + "attendance_scope": { + "type": "string", + "enum": [ + "all", + "exhibitor", + "visitor" + ], + "default": "all", + "description": "Filter events by this company's attendance identity. Defaults to `all`. `exhibitor` includes events with exhibitor evidence, including events that also have visitor evidence. `visitor` returns visitor-only events and excludes events with exhibitor evidence. Only `all`, `exhibitor`, and `visitor` are valid; other values, including `null`, return 400.", + "example": "exhibitor" } } }, @@ -2962,11 +3062,12 @@ "company_name": "Acme", "sponsor_match_starred": 1, "page": 1, - "pageSize": 20 + "pageSize": 20, + "attendance_scope": "exhibitor" } } }, - "description": "Provide the company name, optional Sponsor Match filter, and pagination for event reverse search." + "description": "Provide the company name, optional Sponsor Match filter, and pagination for event reverse search. Optional `attendance_scope` filters by company attendance identity and defaults to `all`." }, "ProfileMatchingBody": { "required": true, @@ -3724,7 +3825,8 @@ { "type": "object", "required": [ - "matchedExhibitors" + "matchedExhibitors", + "attendance_identity" ], "properties": { "matchedExhibitors": { @@ -3732,12 +3834,27 @@ "items": { "$ref": "#/components/schemas/MatchedExhibitorSummary" }, - "description": "Matched Exhibitors returned as part of this event reverse search item object." + "description": "Admitted company matches with exhibitor relationships at this event. This array can be empty for visitor-only results." + }, + "attendance_identity": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "exhibitor", + "visitor" + ] + }, + "description": "Complete attendance identities for this company at this event. An event matched by a scope still returns its complete identity array.", + "example": [ + "exhibitor", + "visitor" + ] } } } ], - "description": "Event result enriched with the exhibitor company that produced the reverse-search match." + "description": "Event result with the company's attendance identities and any matched exhibitor relationships. Visitor-only results can have an empty matchedExhibitors array." }, "EventReverseSearchPage": { "type": "object", @@ -5960,6 +6077,152 @@ } ], "description": "Full Lensmor event metadata plus profile-recommendation evidence and rank." + }, + "ExhibitorRelatedEventItem": { + "allOf": [ + { + "$ref": "#/components/schemas/EventItem" + }, + { + "type": "object", + "required": [ + "attendance_identity" + ], + "properties": { + "attendance_identity": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "exhibitor", + "visitor" + ] + }, + "description": "Complete attendance identities for this company at this event. An event matched by a scope still returns its complete identity array.", + "example": [ + "exhibitor", + "visitor" + ] + } + } + } + ], + "description": "Event returned by a company reverse lookup with event-scoped attendance identities." + }, + "PersonnelRelatedEventItem": { + "allOf": [ + { + "$ref": "#/components/schemas/EventItem" + }, + { + "type": "object", + "required": [ + "attendance_identity" + ], + "properties": { + "attendance_identity": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "exhibitor_employee", + "visitor" + ] + }, + "description": "Complete attendance identities for the matched personnel at this event. Exact-name lookups combine evidence across matched personnel records before filtering. Scope filtering does not trim the returned identity array.", + "example": [ + "exhibitor_employee", + "visitor" + ] + } + } + } + ], + "description": "Event returned by a person reverse lookup with event-scoped attendance identities." + }, + "ExhibitorRelatedEventPage": { + "type": "object", + "required": [ + "items", + "total", + "page", + "pageSize", + "totalPages", + "hasMore" + ], + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ExhibitorRelatedEventItem" + }, + "description": "Records returned on the current page or in the current batch." + }, + "total": { + "type": "integer", + "description": "Total matching records across all pages." + }, + "page": { + "type": "integer", + "description": "One-based page number returned." + }, + "pageSize": { + "type": "integer", + "description": "Maximum records requested for this page." + }, + "totalPages": { + "type": "integer", + "description": "Total pages available for the current query." + }, + "hasMore": { + "type": "boolean", + "description": "Whether another result page is available." + } + }, + "additionalProperties": true, + "description": "Paginated company-related events with attendance identities." + }, + "PersonnelRelatedEventPage": { + "type": "object", + "required": [ + "items", + "total", + "page", + "pageSize", + "totalPages", + "hasMore" + ], + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PersonnelRelatedEventItem" + }, + "description": "Records returned on the current page or in the current batch." + }, + "total": { + "type": "integer", + "description": "Total matching records across all pages." + }, + "page": { + "type": "integer", + "description": "One-based page number returned." + }, + "pageSize": { + "type": "integer", + "description": "Maximum records requested for this page." + }, + "totalPages": { + "type": "integer", + "description": "Total pages available for the current query." + }, + "hasMore": { + "type": "boolean", + "description": "Whether another result page is available." + } + }, + "additionalProperties": true, + "description": "Paginated person-related events with attendance identities." } } } diff --git a/scripts/test_sync_public_assets.py b/scripts/test_sync_public_assets.py index 373843b..86087fb 100644 --- a/scripts/test_sync_public_assets.py +++ b/scripts/test_sync_public_assets.py @@ -215,9 +215,10 @@ def test_company_search_contract_matches_current_credit_rule(self) -> None: by_name = spec["paths"]["/external/personnel/events/by-name"]["get"] self.assertIn("up to 50 personnel records", by_name["description"]) self.assertIn("10 requests", by_name["description"]) + self.assertIn("2026-01-01", by_name["description"]) self.assertEqual( by_name["responses"]["200"]["content"]["application/json"]["schema"]["oneOf"][0]["$ref"], - "#/components/schemas/EventPage", + "#/components/schemas/PersonnelRelatedEventPage", ) by_name_200_refs = { item["$ref"] @@ -268,11 +269,20 @@ def test_event_search_and_event_item_contracts(self) -> None: "application/json" ]["schema"]["properties"] self.assertEqual(event_search_fields["sponsor_match_starred"]["enum"], [0, 1]) + self.assertEqual( + event_search_fields["attendance_scope"]["enum"], ["all", "exhibitor", "visitor"] + ) + self.assertEqual(event_search_fields["attendance_scope"]["default"], "all") + self.assertIn( + "attendance_identity", + schemas["EventReverseSearchItem"]["allOf"][1]["required"], + ) event_fields = schemas["EventItem"]["properties"] self.assertEqual(event_fields["dataSource"]["const"], "Lensmor") self.assertEqual(event_fields["sponsorMatchStarred"]["enum"], [0, 1]) self.assertEqual(event_fields["hasVisitors"]["type"], "boolean") + self.assertIn("availability signal", event_fields["hasVisitors"]["description"]) event_list = spec["paths"]["/external/events/list"]["get"] @@ -318,6 +328,58 @@ def test_event_search_and_event_item_contracts(self) -> None: self.assertIn(example["sponsorMatchStarred"], [0, 1]) self.assertEqual(example["dataSource"], "Lensmor") + def test_reverse_event_attendance_contract(self) -> None: + spec = json.loads(self.sync.OPENAPI_SOURCE.read_text(encoding="utf-8")) + schemas = spec["components"]["schemas"] + parameters = spec["components"]["parameters"] + paths = spec["paths"] + + cases = ( + ("/external/exhibitors/events", "exhibitor_id", "CompanyAttendanceScopeQuery", + "ExhibitorRelatedEventPage", ["exhibitor", "visitor"]), + ("/external/personnel/events", "personnel_id", "PersonnelAttendanceScopeQuery", + "PersonnelRelatedEventPage", ["exhibitor_employee", "visitor"]), + ("/external/personnel/events/by-linkedin", "linkedin_url", "PersonnelAttendanceScopeQuery", + "PersonnelRelatedEventPage", ["exhibitor_employee", "visitor"]), + ("/external/personnel/events/by-name", "person_name", "PersonnelAttendanceScopeQuery", + "PersonnelRelatedEventPage", ["exhibitor_employee", "visitor"]), + ) + for path, identifier, scope_parameter, page_name, identities in cases: + operation = paths[path]["get"] + refs = {item.get("$ref") for item in operation["parameters"]} + self.assertIn(f"#/components/parameters/{scope_parameter}", refs) + scope = parameters[scope_parameter] + self.assertFalse(scope["required"]) + self.assertEqual(scope["schema"]["enum"], ["all", *identities]) + self.assertEqual(scope["schema"]["default"], "all") + self.assertIn("visitor-only", scope["description"]) + sample = operation["x-codeSamples"][0]["source"] + self.assertIn(f"{identifier}=", sample) + self.assertIn("attendance_scope=visitor", sample) + self.assertIn("attendance_identity", operation["description"]) + content = operation["responses"]["200"]["content"]["application/json"] + if path.endswith("/by-name"): + page_ref = content["schema"]["oneOf"][0]["$ref"] + event_example = content["examples"]["success"]["value"]["items"][0] + elif path.endswith("/by-linkedin"): + page_ref = content["schema"]["properties"]["events"]["$ref"] + event_example = content["example"]["events"]["items"][0] + else: + page_ref = content["schema"]["$ref"] + event_example = content["example"]["items"][0] + self.assertEqual(page_ref, f"#/components/schemas/{page_name}") + self.assertEqual(event_example["attendance_identity"], ["visitor"]) + + for item_name, identities in ( + ("ExhibitorRelatedEventItem", ["exhibitor", "visitor"]), + ("PersonnelRelatedEventItem", ["exhibitor_employee", "visitor"]), + ): + extension = schemas[item_name]["allOf"][1] + self.assertIn("attendance_identity", extension["required"]) + self.assertEqual( + extension["properties"]["attendance_identity"]["items"]["enum"], identities + ) + def test_contact_unlock_and_outreach_contracts(self) -> None: spec = json.loads(self.sync.OPENAPI_SOURCE.read_text(encoding="utf-8")) schemas = spec["components"]["schemas"]