This is an automated email from the ASF dual-hosted git repository. shuber pushed a commit to branch unomi-3-dev in repository https://gitbox.apache.org/repos/asf/unomi.git
commit af154df77c927b33c1138e60df09014d64d49922 Author: Serge Huber <[email protected]> AuthorDate: Wed Jan 21 15:09:06 2026 +0100 [UNOMI-882] docs: update shell commands and REST API documentation - Fix shell command option ordering in manual (options must come before arguments) - Update shell-commands.adoc with correct --csv option syntax and usage notes - Fix PlantUML diagram syntax in property-types.adoc (remove invalid note syntax) - Enhance REST API README with comprehensive documentation - Add Postman collection (unomi-postman-collection.json) for REST API testing - Add postman-readme.md with setup instructions and usage examples - Document Swagger UI access and OpenAPI specification endpoints - Include technical details about OpenAPI feature and Swagger UI version --- manual/src/main/asciidoc/property-types.adoc | 64 +- manual/src/main/asciidoc/shell-commands.adoc | 11 +- rest/README.md | 55 +- rest/postman-readme.md | 277 +++ rest/unomi-postman-collection.json | 2638 ++++++++++++++++++++++++++ 5 files changed, 2999 insertions(+), 46 deletions(-) diff --git a/manual/src/main/asciidoc/property-types.adoc b/manual/src/main/asciidoc/property-types.adoc index 1c7d0c7d9..cccc33b0a 100644 --- a/manual/src/main/asciidoc/property-types.adoc +++ b/manual/src/main/asciidoc/property-types.adoc @@ -19,7 +19,7 @@ Property types define the structure and metadata for properties that can be used IMPORTANT: Property types are primarily designed for **UI purposes** - they inform user interfaces about what properties should be editable, how they should be displayed, and what constraints apply. Property types are **dynamically created and updated** at runtime and do not enforce strict validation on the server side. For actual data validation, Apache Unomi uses <<_json_schemas,JSON Schemas>>, which are used exclusively for validating events sent through public endpoints. -==== Quick Reference: Property Types vs JSON Schemas +=== Quick Reference: Property Types vs JSON Schemas |=== | Aspect | Property Types | JSON Schemas @@ -1103,41 +1103,33 @@ skinparam rectangle { BorderColor #4A90A4 } -skinparam note { - BackgroundColor #FFF9E6 - BorderColor #D4A574 -} - -rectangle "Property Types" as PT { - note right - • UI metadata (names, descriptions, types) - • Display hints (ranks, tags, protected flags) - • Dynamic and editable at runtime - • Used by GraphQL to generate schema - end note -} - -rectangle "User Interface" as UI { - note right - • Dynamic forms based on property types - • Property editors with type hints - • Grouped displays using tags - end note -} - -rectangle "JSON Schemas" as JSON { - note right - • Server-side validation for EVENTS ONLY - • Event type checking and constraints - • Event structure validation - • Event data integrity enforcement - • Used when events sent via /context.json - or /eventcollector endpoints - end note -} - -PT -->|"UI Generation"| UI -UI -->|"Data Submission"| JSON +rectangle "Property Types" as PT +note right of PT + • UI metadata (names, descriptions, types) + • Display hints (ranks, tags, protected flags) + • Dynamic and editable at runtime + • Used by GraphQL to generate schema +end note + +rectangle "User Interface" as UI +note right of UI + • Dynamic forms based on property types + • Property editors with type hints + • Grouped displays using tags +end note + +rectangle "JSON Schemas" as JSON +note right of JSON + • Server-side validation for EVENTS ONLY + • Event type checking and constraints + • Event structure validation + • Event data integrity enforcement + • Used when events sent via /context.json + or /eventcollector endpoints +end note + +PT --> UI : UI Generation +UI --> JSON : Data Submission @enduml ---- diff --git a/manual/src/main/asciidoc/shell-commands.adoc b/manual/src/main/asciidoc/shell-commands.adoc index 515d63cf9..94dd773b8 100644 --- a/manual/src/main/asciidoc/shell-commands.adoc +++ b/manual/src/main/asciidoc/shell-commands.adoc @@ -96,10 +96,11 @@ These commands are available once the application is running. If an argument is |Command|Arguments|Description |rule-list -|[maxEntries] [--csv] +|[--csv] [maxEntries] |Lists all the rules registered in the Apache Unomi server. The maxEntries (defaults to 100) will allow you to specify how many entries need to be retrieved. If the value is inferior to the total value, a message will display the total -value of rules registered in the server. If you add the "--csv" option the list will be output as a CSV formatted table +value of rules registered in the server. If you add the "--csv" option the list will be output as a CSV formatted table. +Note: Options must come before arguments, so use `rule-list --csv 100` not `rule-list 100 --csv`. |rule-view |rule-id |Dumps a single rule in JSON. The rule-id argument can be retrieved from the `rule-list` command output. @@ -131,9 +132,11 @@ created, EXECUTE means the rule's actions are being executed. |event-id |Dumps a single event in JSON. The `event-id` can be retrieved from the event-tail command output. |event-list -|[max-entries] [event-type] [--csv] +|[--csv] [max-entries] [event-type] |List the last events processed by Apache Unomi. The `max-entries` parameter can be used to control how many events are displayed (default is 100). The `event-type` makes it possible to filter the list by event type. The `--csv` argument is used to output the list as a CSV list instead of an ASCII table. +Note: Options must come before arguments, so use `event-list --csv 100 view` not `event-list 100 view --csv`. +Note: Options must come before arguments, so use `event-list --csv 100 view` not `event-list 100 view --csv`. |event-search |profile-id [event-type] [max-entries] |This command makes it possible to search for the last events by `profile-id` and by `event-type`. A `max-entries` @@ -148,7 +151,7 @@ check that everything is properly registered. If you add the "--csv" option the |Dumps a single action in JSON. The action-id argument can be retrieved from the `action-list` command output. |condition-list -|[csv] +|[--csv] |List all the conditions registered in the server. If you add the "--csv" option the list will be output as a CSV formatted table |condition-view |condition-id diff --git a/rest/README.md b/rest/README.md index b44c62130..69b64b8cd 100644 --- a/rest/README.md +++ b/rest/README.md @@ -15,10 +15,53 @@ ~ limitations under the License. --> -# How to generate the REST API documentation +# REST API Documentation -- Switch to the `rest-documentation` branch, a different branch is need so that we can add the proper `@Path` annotations on the endpoint and add the Maven plugin configuration -for documentation generation. -- Make sure that the changes from master are incorporated to the branch by performing a rebase: `git rebase master`. -- Run `mvn test`. -- The documentation should now be available via `target/miredot/index.html` \ No newline at end of file +Apache Unomi provides REST API documentation through OpenAPI/Swagger UI. + +## Accessing the API Documentation + +When the Unomi server is running, you can access the REST API documentation in the following ways: + +### Swagger UI (Interactive Documentation) + +The Swagger UI provides an interactive interface to explore and test the REST API: + +- **URL**: `http://localhost:8181/cxs/api-docs?url=openapi.json` +- **Alternative**: Access via the main Unomi web interface at `/cxs/api-docs?url=openapi.json` + +The Swagger UI allows you to: +- Browse all available REST API endpoints +- View request/response schemas +- Test API calls directly from the browser +- Download the OpenAPI specification + +### OpenAPI Specification + +The OpenAPI 3.0 specification is available as JSON: + +- **URL**: `http://localhost:8181/openapi.json` + +This specification can be used with: +- API client generators +- Documentation tools +- API testing tools + +## Postman Collection + +A comprehensive Postman collection with example requests is available in this directory: + +- **Collection file**: `unomi-postman-collection.json` +- **Documentation**: `postman-readme.md` + +See `postman-readme.md` for detailed setup instructions and usage examples. + +## Technical Details + +The REST API documentation is automatically generated using: + +- **OpenAPI Feature**: Apache CXF's OpenApiFeature +- **Swagger UI**: Embedded Swagger UI (version 5.27.1) +- **Configuration**: Configured in `RestServer.java` + +The OpenAPI specification is generated dynamically from the JAX-RS annotations on the REST endpoints. \ No newline at end of file diff --git a/rest/postman-readme.md b/rest/postman-readme.md new file mode 100644 index 000000000..35391d932 --- /dev/null +++ b/rest/postman-readme.md @@ -0,0 +1,277 @@ +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +# Apache Unomi Postman Collection + +This Postman collection provides comprehensive examples for getting started with Apache Unomi REST API. + +## Setup Instructions + +### 1. Import the Collection + +1. Open Postman +2. Click **Import** button +3. Select the `unomi-postman-collection.json` file +4. The collection will appear in your Postman workspace + +### 2. Configure Environment Variables + +The collection uses several variables that you need to configure: + +#### Required Variables + +1. **baseUrl**: Your Unomi server URL + - Default: `http://localhost:8181` + - Update if your server is running on a different host/port + +2. **scope**: The scope identifier for your tenant + - Default: `example` + - This should match your tenant's scope + +3. **publicApiKey**: Your tenant's public API key + - Get this from your tenant after creating it + - Used for public API endpoints (`/context.json`, `/eventcollector`) + - Sent via `X-Unomi-Api-Key` header + +4. **privateApiKey**: Your tenant's private API key + - Get this from your tenant after creating it + - Used for private API endpoints (segments, rules, profiles, scopes, etc.) + - Used with `tenantId` for Basic Auth (tenantId:privateApiKey) + +5. **tenantId**: Your tenant ID + - Default: `mytenant` + - Used with `privateApiKey` for Basic Auth on private endpoints + - Update this to match your actual tenant ID + +6. **adminUsername**: Admin username for administrative endpoints + - Default: `karaf` + - Used only for tenant management endpoints (`/cxs/tenants`) + +7. **adminPassword**: Admin password for administrative endpoints + - Default: `karaf` + - Used only for tenant management endpoints (`/cxs/tenants`) + +8. **healthUsername**: Health check username + - Default: `health` + - Used for health check endpoint + +9. **healthPassword**: Health check password + - Default: `health` + - Used for health check endpoint + +#### Optional Variables (with defaults) + +- **sessionId**: `session-123` (used for context requests) +- **profileId**: `profile-123` (used for profile operations) +- **segmentId**: `premium-users` (used for segment operations) +- **ruleId**: `set-premium-on-purchase` (used for rule operations) +- **scopeId**: `example` (used for scope management operations) + +### 3. Setting Up Variables in Postman + +#### Option 1: Collection Variables (Recommended) +1. Right-click the collection → **Edit** +2. Go to **Variables** tab +3. Update the values for your environment +4. **No base64 encoding needed!** Postman automatically handles Basic Auth encoding + +#### Option 2: Environment Variables +1. Create a new Environment in Postman +2. Add all the variables listed above +3. Select the environment before making requests + +## Collection Structure + +The collection is organized in a logical demo flow order with 12 main folders: + +### 1. Health Check +- Basic health check endpoint to verify server status +- **Authentication**: `healthUsername:healthPassword` (Basic Auth) + +### 2. Tenant Management +- Create, list, update, delete tenants +- Generate API keys (PUBLIC and PRIVATE) +- **Authentication**: `adminUsername:adminPassword` (Basic Auth) +- **Important**: Save both PUBLIC and PRIVATE API keys from the create tenant response! + +### 3. Scope Management +- **List All Scopes**: Retrieve all scopes in the system +- **Get Scope by ID**: Retrieve a specific scope by its identifier +- **Create Scope**: Create a new scope with basic metadata +- **Create Scope with Tags**: Create a scope with tags and additional metadata +- **Update Scope**: Update an existing scope (use POST with same itemId) +- **Delete Scope**: Delete a scope by ID +- **Authentication**: `tenantId:privateApiKey` (Basic Auth) + +### 4. Event Schema Creation +- Create JSON schemas for custom events +- Validate events against schemas +- List and manage schemas +- **Authentication**: `tenantId:privateApiKey` (Basic Auth) + +### 5. Basic Context Requests +- Minimal context requests +- Context with source information +- Context with all properties +- Context with specific properties +- **Authentication**: `X-Unomi-Api-Key` header with `publicApiKey` + +### 6. Segment Creation +- Simple segments (single condition) +- Complex segments (multiple conditions) +- Segments based on past events +- Nested segment conditions +- Segment management operations +- **Authentication**: `tenantId:privateApiKey` (Basic Auth) + +### 7. Context Requests with Events +- Context requests with view events +- Context requests with custom events +- Event collector for multiple events +- **Authentication**: `X-Unomi-Api-Key` header with `publicApiKey` + +### 8. Personalization +- Simple personalization (matching-first strategy) +- Score-based personalization (score-sorted strategy) +- **Authentication**: `X-Unomi-Api-Key` header with `publicApiKey` + +### 9. Rule Management +- Create rules with conditions and actions +- List and get rules +- View rule statistics +- Delete rules +- **Authentication**: `tenantId:privateApiKey` (Basic Auth) + +### 11. Profile Management +- Get, create, update, delete profiles +- Search profiles +- Get profile segments and sessions +- **Authentication**: `tenantId:privateApiKey` (Basic Auth) + +### 10. Explain Context Request +- Context requests with explain mode enabled +- Returns detailed tracing information +- **Authentication**: `X-Unomi-Api-Key` header with `publicApiKey` + +### 12. Additional Useful Requests +- Event type management +- Event search +- Condition and action definitions +- Property types +- **Authentication**: `tenantId:privateApiKey` (Basic Auth) + +## Quick Start Guide + +### Step 1: Check Server Health +1. Go to **1. Health Check** → **Health Check** +2. Update `healthAuth` variable if needed +3. Send the request +4. Verify all components are LIVE + +### Step 2: Create a Tenant +1. Go to **2. Tenant Management** → **Create Tenant** +2. Update the request body with your tenant details (or use the default `{{tenantId}}`) +3. Send the request +4. **IMPORTANT**: Save both API keys from the response: + - Find the API key with `"type": "PUBLIC"` → Update `publicApiKey` variable + - Find the API key with `"type": "PRIVATE"` → Update `privateApiKey` variable +5. Update `tenantId` variable to match your actual tenant ID + +### Step 3: Create a Scope (if needed) +1. Go to **3. Scope Management** → **Create Scope** +2. Update the request body with your scope ID and metadata +3. Send the request + +### Step 4: Create a Simple Segment +1. Go to **6. Segment Creation** → **Simple Segment - Profile Property** +2. Update the `scope` variable if needed +3. Send the request (uses `tenantId:privateApiKey` authentication) + +### Step 5: Make a Basic Context Request +1. Go to **5. Basic Context Requests** → **Get Context (Minimal)** +2. Update `sessionId` if needed +3. Send the request (uses `X-Unomi-Api-Key` header with `publicApiKey`) +4. Note the `profileId` and `sessionId` in the response + +### Step 6: Send an Event +1. Go to **7. Context Requests with Events** → **Context with View Event** +2. Update `sessionId` and `scope` variables +3. Send the request (uses `X-Unomi-Api-Key` header with `publicApiKey`) + +## Common Use Cases + +### Creating a Custom Event Type + +1. **Create Event Schema** (4. Event Schema Creation → Create Event Schema) +2. **Validate Event** (4. Event Schema Creation → Validate Event) +3. **Send Custom Event** (7. Context Requests with Events → Context with Custom Event) + +### Setting Up Personalization + +1. **Create Segments** (6. Segment Creation) +2. **Create Rules** (9. Rule Management) - Optional, to automatically add users to segments +3. **Request Personalization** (8. Personalization) + +### Debugging with Explain Mode + +1. **Enable Explain** (10. Explain Context Request → Context Request with Explain) +2. Review the `requestTracing` object in the response +3. Check rule execution, segment evaluation, and personalization decisions + +## Tips + +1. **Start Simple**: Begin with basic context requests before moving to complex segments and rules +2. **Use Explain Mode**: When debugging, use explain mode to understand why rules/segments match or don't match +3. **Save Responses**: Save important responses (like tenant creation) to retrieve API keys +4. **Update Variables**: Keep your variables up to date, especially `sessionId` and `profileId` as you work +5. **Check Health**: Regularly check the health endpoint to ensure all components are running + +## Troubleshooting + +### 401 Unauthorized +- **Public endpoints** (`/context.json`, `/eventcollector`): Check that `publicApiKey` is set correctly +- **Private endpoints** (segments, rules, profiles, scopes): Check that both `tenantId` and `privateApiKey` are set correctly +- **Admin endpoints** (`/cxs/tenants`): Verify `adminUsername` and `adminPassword` are correct +- **Health endpoint**: Verify `healthUsername` and `healthPassword` are correct + +### 404 Not Found +- Verify the endpoint URL is correct +- Check that the resource (tenant, segment, rule) exists +- Ensure you're using the correct scope + +### 400 Bad Request +- Validate your JSON payload structure +- Check that required fields are present +- For custom events, ensure the schema exists and matches the event type + +### Schema Validation Errors +- Ensure event schema name matches the `eventType` in your events +- Check that all required properties are present +- Verify property types match the schema definition + +## Additional Resources + +- [Apache Unomi Documentation](https://unomi.apache.org/) +- [Unomi API Reference](https://unomi.apache.org/unomi-api/) +- [Unomi Manual](https://unomi.apache.org/manual/) + +## Notes + +- All timestamps in Unomi are in ISO 8601 format +- Session IDs and Profile IDs are case-sensitive +- Scopes are used to isolate data between different tenants/applications +- Rules are executed automatically when matching events occur +- Segments are evaluated dynamically based on current profile state diff --git a/rest/unomi-postman-collection.json b/rest/unomi-postman-collection.json new file mode 100644 index 000000000..979e6bdcd --- /dev/null +++ b/rest/unomi-postman-collection.json @@ -0,0 +1,2638 @@ +{ + "info": { + "_postman_id": "unomi-api-collection", + "name": "Apache Unomi API Examples", + "description": "Comprehensive collection of Apache Unomi REST API examples for getting started", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "1. Health Check", + "item": [ + { + "name": "Health Check", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/health/check", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "health", + "check" + ] + }, + "description": "Check the health status of Unomi server and its components (Karaf, ElasticSearch/OpenSearch, Unomi bundles, Persistence, Cluster)", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{healthUsername}}", + "type": "string" + }, + { + "key": "password", + "value": "{{healthPassword}}", + "type": "string" + } + ] + } + }, + "response": [] + } + ], + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{healthUsername}}", + "type": "string" + }, + { + "key": "password", + "value": "{{healthPassword}}", + "type": "string" + } + ] + } + }, + { + "name": "2. Tenant Management", + "item": [ + { + "name": "List All Tenants", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/cxs/tenants", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "tenants" + ] + }, + "description": "Retrieve all tenants in the system. Requires administrator authentication.", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{adminUsername}}", + "type": "string" + }, + { + "key": "password", + "value": "{{adminPassword}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Get Tenant by ID", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/cxs/tenants/{{tenantId}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "tenants", + "{{tenantId}}" + ] + }, + "description": "Retrieve a specific tenant by ID", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{adminUsername}}", + "type": "string" + }, + { + "key": "password", + "value": "{{adminPassword}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Create Tenant", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestedId\": \"{{tenantId}}\",\n \"properties\": {\n \"name\": \"My Company\",\n \"description\": \"My Company tenant\",\n \"address\": \"123 Main St\",\n \"country\": \"USA\"\n }\n}" + }, + "url": { + "raw": "{{baseUrl}}/cxs/tenants", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "tenants" + ] + }, + "description": "Create a new tenant. API keys (PUBLIC and PRIVATE) are automatically generated.", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{adminUsername}}", + "type": "string" + }, + { + "key": "password", + "value": "{{adminPassword}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Update Tenant", + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"itemId\": \"{{tenantId}}\",\n \"name\": \"My Company Updated\",\n \"description\": \"Updated description\",\n \"properties\": {\n \"address\": \"456 New St\",\n \"country\": \"USA\"\n }\n}" + }, + "url": { + "raw": "{{baseUrl}}/cxs/tenants/{{tenantId}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "tenants", + "{{tenantId}}" + ] + }, + "description": "Update an existing tenant", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{adminUsername}}", + "type": "string" + }, + { + "key": "password", + "value": "{{adminPassword}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Generate API Key", + "request": { + "method": "POST", + "header": [], + "url": { + "raw": "{{baseUrl}}/cxs/tenants/{{tenantId}}/apikeys?type=PUBLIC&validityDays=365", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "tenants", + "{{tenantId}}", + "apikeys" + ], + "query": [ + { + "key": "type", + "value": "PUBLIC", + "description": "PUBLIC or PRIVATE" + }, + { + "key": "validityDays", + "value": "365", + "description": "Validity period in days (0 or null for no expiration)" + } + ] + }, + "description": "Generate a new API key for a tenant. Type can be PUBLIC or PRIVATE.", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{adminUsername}}", + "type": "string" + }, + { + "key": "password", + "value": "{{adminPassword}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Validate API Key", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/cxs/tenants/{{tenantId}}/apikeys/validate?key={{apiKey}}&type=PUBLIC", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "tenants", + "{{tenantId}}", + "apikeys", + "validate" + ], + "query": [ + { + "key": "key", + "value": "{{apiKey}}", + "description": "The API key to validate" + }, + { + "key": "type", + "value": "PUBLIC", + "description": "PUBLIC or PRIVATE" + } + ] + }, + "description": "Validate an API key for a tenant. Returns 200 OK if valid, 401 Unauthorized if invalid.", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{adminUsername}}", + "type": "string" + }, + { + "key": "password", + "value": "{{adminPassword}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Delete Tenant", + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{baseUrl}}/cxs/tenants/{{tenantId}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "tenants", + "{{tenantId}}" + ] + }, + "description": "Delete a tenant", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{adminUsername}}", + "type": "string" + }, + { + "key": "password", + "value": "{{adminPassword}}", + "type": "string" + } + ] + } + }, + "response": [] + } + ], + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{adminUsername}}", + "type": "string" + }, + { + "key": "password", + "value": "{{adminPassword}}", + "type": "string" + } + ] + } + }, + { + "name": "3. Scope Management", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + }, + "item": [ + { + "name": "List All Scopes", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/cxs/scopes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "scopes" + ] + }, + "description": "Retrieve all scopes in the system", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Get Scope by ID", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/cxs/scopes/{{scopeId}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "scopes", + "{{scopeId}}" + ] + }, + "description": "Retrieve a specific scope by ID", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Create Scope", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"itemId\": \"example\",\n \"itemType\": \"scope\",\n \"metadata\": {\n \"id\": \"example\",\n \"name\": \"Example Scope\",\n \"description\": \"An example scope for testing\",\n \"scope\": \"systemscope\"\n }\n}" + }, + "url": { + "raw": "{{baseUrl}}/cxs/scopes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "scopes" + ] + }, + "description": "Create a new scope. The itemId and metadata.id should match.", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Create Scope with Tags", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"itemId\": \"example-tagged\",\n \"itemType\": \"scope\",\n \"metadata\": {\n \"id\": \"example-tagged\",\n \"name\": \"Tagged Example Scope\",\n \"description\": \"A scope with tags for organization\",\n \"scope\": \"systemscope\",\n \"tags\": [\"production\", \"ecommerce\"],\n \"enabled\": true\n }\n}" + }, + "url": { + "raw": "{{baseUrl}}/cxs/scopes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "scopes" + ] + }, + "description": "Create a scope with tags and additional metadata", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Update Scope", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"itemId\": \"{{scopeId}}\",\n \"itemType\": \"scope\",\n \"metadata\": {\n \"id\": \"{{scopeId}}\",\n \"name\": \"Updated Scope Name\",\n \"description\": \"Updated description for the scope\",\n \"scope\": \"systemscope\",\n \"enabled\": true\n }\n}" + }, + "url": { + "raw": "{{baseUrl}}/cxs/scopes", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "scopes" + ] + }, + "description": "Update an existing scope. Use POST with the same itemId to update.", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Delete Scope", + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{baseUrl}}/cxs/scopes/{{scopeId}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "scopes", + "{{scopeId}}" + ] + }, + "description": "Delete a scope by ID", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + } + ] + }, + { + "name": "4. Event Schema Creation", + "item": [ + { + "name": "Create Event Schema", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"$id\": \"https://unomi.apache.org/schemas/json/events/contactInfoSubmitted/1-0-0\",\n \"$schema\": \"https://json-schema.org/draft/2019-09/schema\",\n \"self\": {\n \"vendor\": \"org.apache.unomi\",\n \"name\": \"contactInfoSubmitted\",\n \"format\": \"jsonschema\",\n \"target\": \"events\",\n \"version\": \"1-0-0\"\n },\n \"title\": \"contactInfoSubmittedEvent\",\n \"type\": \"object\",\n \"allOf\": [{ \"$ref\" [...] + }, + "url": { + "raw": "{{baseUrl}}/cxs/jsonSchema", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "jsonSchema" + ] + }, + "description": "Create a JSON schema for validating custom events. The schema name must match the eventType in events.", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "List Installed Schemas", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/cxs/jsonSchema", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "jsonSchema" + ] + }, + "description": "Get list of all installed JSON schema IDs", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Get Schema by ID", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "\"https://unomi.apache.org/schemas/json/events/contactInfoSubmitted/1-0-0\"" + }, + "url": { + "raw": "{{baseUrl}}/cxs/jsonSchema/query", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "jsonSchema", + "query" + ] + }, + "description": "Retrieve a specific schema by its ID", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Validate Event", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"eventType\": \"contactInfoSubmitted\",\n \"scope\": \"{{scope}}\",\n \"source\": {\n \"itemId\": \"form\",\n \"itemType\": \"form\",\n \"scope\": \"{{scope}}\"\n },\n \"properties\": {\n \"firstName\": \"John\",\n \"lastName\": \"Doe\",\n \"email\": \"[email protected]\"\n }\n}" + }, + "url": { + "raw": "{{baseUrl}}/cxs/jsonSchema/validateEvent", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "jsonSchema", + "validateEvent" + ] + }, + "description": "Validate an event against its schema. Returns validation errors if any.", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Delete Schema", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "\"https://unomi.apache.org/schemas/json/events/contactInfoSubmitted/1-0-0\"" + }, + "url": { + "raw": "{{baseUrl}}/cxs/jsonSchema/delete", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "jsonSchema", + "delete" + ] + }, + "description": "Delete a JSON schema by ID", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + } + ], + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{adminUsername}}", + "type": "string" + }, + { + "key": "password", + "value": "{{adminPassword}}", + "type": "string" + } + ] + } + }, + { + "name": "5. Basic Context Requests", + "item": [ + { + "name": "Get Context (Minimal)", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Unomi-Api-Key", + "value": "{{publicApiKey}}", + "type": "text" + } + ], + "url": { + "raw": "{{baseUrl}}/cxs/context.json?sessionId={{sessionId}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "context.json" + ], + "query": [ + { + "key": "sessionId", + "value": "{{sessionId}}" + } + ] + }, + "description": "Get basic context with minimal information. Creates profile and session if they don't exist." + }, + "response": [] + }, + { + "name": "Get Context with Source", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "X-Unomi-Api-Key", + "value": "{{publicApiKey}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"source\": {\n \"itemId\": \"homepage\",\n \"itemType\": \"page\",\n \"scope\": \"{{scope}}\"\n },\n \"sessionId\": \"{{sessionId}}\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/cxs/context.json", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "context.json" + ] + }, + "description": "Get context with source information about the page/site" + }, + "response": [] + }, + { + "name": "Get Context with All Properties", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "X-Unomi-Api-Key", + "value": "{{publicApiKey}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"source\": {\n \"itemId\": \"homepage\",\n \"itemType\": \"page\",\n \"scope\": \"{{scope}}\"\n },\n \"sessionId\": \"{{sessionId}}\",\n \"requiredProfileProperties\": [\"*\"],\n \"requiredSessionProperties\": [\"*\"],\n \"requireSegments\": true,\n \"requireScores\": true\n}" + }, + "url": { + "raw": "{{baseUrl}}/cxs/context.json", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "context.json" + ] + }, + "description": "Get context with all profile properties, session properties, segments, and scores" + }, + "response": [] + }, + { + "name": "Get Context with Specific Properties", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "X-Unomi-Api-Key", + "value": "{{publicApiKey}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"source\": {\n \"itemId\": \"homepage\",\n \"itemType\": \"page\",\n \"scope\": \"{{scope}}\"\n },\n \"sessionId\": \"{{sessionId}}\",\n \"requiredProfileProperties\": [\"properties.firstName\", \"properties.lastName\", \"properties.email\"],\n \"requiredSessionProperties\": [\"properties.pageViews\", \"properties.lastVisit\"],\n \"requireSegments\": true\n}" + }, + "url": { + "raw": "{{baseUrl}}/cxs/context.json", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "context.json" + ] + }, + "description": "Get context with only specific profile and session properties" + }, + "response": [] + } + ] + }, + { + "name": "6. Segment Creation", + "item": [ + { + "name": "Simple Segment - Profile Property", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"metadata\": {\n \"id\": \"premium-users\",\n \"name\": \"Premium Users\",\n \"scope\": \"{{scope}}\",\n \"description\": \"Users with premium subscription\"\n },\n \"condition\": {\n \"type\": \"profilePropertyCondition\",\n \"parameterValues\": {\n \"propertyName\": \"properties.subscriptionType\",\n \"comparisonOperator\": \"equals\",\n \"propertyValue\": \"premium\"\n }\n }\n}" + }, + "url": { + "raw": "{{baseUrl}}/cxs/segments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "segments" + ] + }, + "description": "Create a simple segment based on a single profile property condition", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Segment - Multiple Conditions (AND)", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"metadata\": {\n \"id\": \"active-premium-users\",\n \"name\": \"Active Premium Users\",\n \"scope\": \"{{scope}}\",\n \"description\": \"Premium users who are active\"\n },\n \"condition\": {\n \"type\": \"booleanCondition\",\n \"parameterValues\": {\n \"operator\": \"and\",\n \"subConditions\": [\n {\n \"type\": \"profilePropertyCondition\",\n [...] + }, + "url": { + "raw": "{{baseUrl}}/cxs/segments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "segments" + ] + }, + "description": "Create a segment with multiple conditions using AND operator", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Segment - Age Range", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"metadata\": {\n \"id\": \"age-20-30\",\n \"name\": \"Age 20-30\",\n \"scope\": \"{{scope}}\",\n \"description\": \"Users between 20 and 30 years old\"\n },\n \"condition\": {\n \"type\": \"booleanCondition\",\n \"parameterValues\": {\n \"operator\": \"and\",\n \"subConditions\": [\n {\n \"type\": \"profilePropertyCondition\",\n \"parameterValu [...] + }, + "url": { + "raw": "{{baseUrl}}/cxs/segments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "segments" + ] + }, + "description": "Create a segment for users in a specific age range", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Segment - Past Events", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"metadata\": {\n \"id\": \"active-users\",\n \"name\": \"Active Users\",\n \"scope\": \"{{scope}}\",\n \"description\": \"Users who viewed pages in the last 30 days\"\n },\n \"condition\": {\n \"type\": \"pastEventCondition\",\n \"parameterValues\": {\n \"eventType\": \"view\",\n \"numberOfDays\": 30,\n \"minimumEventCount\": 1\n }\n }\n}" + }, + "url": { + "raw": "{{baseUrl}}/cxs/segments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "segments" + ] + }, + "description": "Create a segment based on past events (users who performed an action in the last N days)", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Segment - Complex (Multiple Past Events)", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"metadata\": {\n \"id\": \"engaged-customers\",\n \"name\": \"Engaged Customers\",\n \"scope\": \"{{scope}}\",\n \"description\": \"Users who viewed pages recently and made purchases\"\n },\n \"condition\": {\n \"type\": \"booleanCondition\",\n \"parameterValues\": {\n \"operator\": \"and\",\n \"subConditions\": [\n {\n \"type\": \"pastEventCondition\",\n [...] + }, + "url": { + "raw": "{{baseUrl}}/cxs/segments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "segments" + ] + }, + "description": "Create a complex segment combining multiple past event conditions", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Segment - Nested Segment Condition", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"metadata\": {\n \"id\": \"vip-premium-users\",\n \"name\": \"VIP Premium Users\",\n \"scope\": \"{{scope}}\",\n \"description\": \"Users who are in premium segment and have VIP status\"\n },\n \"condition\": {\n \"type\": \"booleanCondition\",\n \"parameterValues\": {\n \"operator\": \"and\",\n \"subConditions\": [\n {\n \"type\": \"profileSegmentCondition\",\n [...] + }, + "url": { + "raw": "{{baseUrl}}/cxs/segments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "segments" + ] + }, + "description": "Create a segment that references another segment (nested segment condition)", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "List Segments", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/cxs/segments?offset=0&size=50", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "segments" + ], + "query": [ + { + "key": "offset", + "value": "0" + }, + { + "key": "size", + "value": "50" + } + ] + }, + "description": "List all segments with pagination", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Get Segment", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/cxs/segments/{{segmentId}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "segments", + "{{segmentId}}" + ] + }, + "description": "Get a specific segment by ID", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Get Segment Match Count", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/cxs/segments/{{segmentId}}/count", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "segments", + "{{segmentId}}", + "count" + ] + }, + "description": "Get the count of profiles matching a segment", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Get Matching Profiles", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/cxs/segments/{{segmentId}}/match?offset=0&size=10", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "segments", + "{{segmentId}}", + "match" + ], + "query": [ + { + "key": "offset", + "value": "0" + }, + { + "key": "size", + "value": "10" + } + ] + }, + "description": "Get profiles matching a segment", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Delete Segment", + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{baseUrl}}/cxs/segments/{{segmentId}}?validate=true", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "segments", + "{{segmentId}}" + ], + "query": [ + { + "key": "validate", + "value": "true", + "description": "Check for dependencies before deleting" + } + ] + }, + "description": "Delete a segment. Set validate=true to check for dependencies.", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + } + ], + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{adminUsername}}", + "type": "string" + }, + { + "key": "password", + "value": "{{adminPassword}}", + "type": "string" + } + ] + } + }, + { + "name": "7. Context Requests with Events", + "item": [ + { + "name": "Context with View Event", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "X-Unomi-Api-Key", + "value": "{{publicApiKey}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"source\": {\n \"itemId\": \"homepage\",\n \"itemType\": \"page\",\n \"scope\": \"{{scope}}\"\n },\n \"sessionId\": \"{{sessionId}}\",\n \"events\": [\n {\n \"eventType\": \"view\",\n \"scope\": \"{{scope}}\",\n \"source\": {\n \"itemType\": \"site\",\n \"scope\": \"{{scope}}\",\n \"itemId\": \"mysite\"\n },\n \"target\": {\n [...] + }, + "url": { + "raw": "{{baseUrl}}/cxs/context.json", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "context.json" + ] + }, + "description": "Send a context request with a view event to track page views" + }, + "response": [] + }, + { + "name": "Context with Custom Event", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "X-Unomi-Api-Key", + "value": "{{publicApiKey}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"source\": {\n \"itemId\": \"contact-form\",\n \"itemType\": \"form\",\n \"scope\": \"{{scope}}\"\n },\n \"sessionId\": \"{{sessionId}}\",\n \"events\": [\n {\n \"eventType\": \"contactInfoSubmitted\",\n \"scope\": \"{{scope}}\",\n \"source\": {\n \"itemType\": \"form\",\n \"scope\": \"{{scope}}\",\n \"itemId\": \"contact-form\"\n },\n [...] + }, + "url": { + "raw": "{{baseUrl}}/cxs/context.json", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "context.json" + ] + }, + "description": "Send a context request with a custom event (requires schema to be created first)" + }, + "response": [] + }, + { + "name": "Event Collector - Multiple Events", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "X-Unomi-Api-Key", + "value": "{{publicApiKey}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"sessionId\": \"{{sessionId}}\",\n \"events\": [\n {\n \"eventType\": \"view\",\n \"scope\": \"{{scope}}\",\n \"source\": {\n \"itemType\": \"site\",\n \"scope\": \"{{scope}}\",\n \"itemId\": \"mysite\"\n },\n \"target\": {\n \"itemType\": \"page\",\n \"scope\": \"{{scope}}\",\n \"itemId\": \"product-page\",\n [...] + }, + "url": { + "raw": "{{baseUrl}}/cxs/eventcollector", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "eventcollector" + ] + }, + "description": "Send multiple events using the event collector endpoint. This executes rules but doesn't return context." + }, + "response": [] + } + ] + }, + { + "name": "8. Personalization", + "item": [ + { + "name": "Context with Simple Personalization", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "X-Unomi-Api-Key", + "value": "{{publicApiKey}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"source\": {\n \"itemId\": \"homepage\",\n \"itemType\": \"page\",\n \"scope\": \"{{scope}}\"\n },\n \"sessionId\": \"{{sessionId}}\",\n \"personalizations\": [\n {\n \"id\": \"homepage-hero\",\n \"strategy\": \"matching-first\",\n \"strategyOptions\": {\n \"fallback\": \"default-content\"\n },\n \"contents\": [\n {\n \"id\": [...] + }, + "url": { + "raw": "{{baseUrl}}/cxs/context.json", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "context.json" + ] + }, + "description": "Request personalization with matching-first strategy. Returns the first matching content or fallback." + }, + "response": [] + }, + { + "name": "Context with Score-Based Personalization", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "X-Unomi-Api-Key", + "value": "{{publicApiKey}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"source\": {\n \"itemId\": \"recommendations\",\n \"itemType\": \"page\",\n \"scope\": \"{{scope}}\"\n },\n \"sessionId\": \"{{sessionId}}\",\n \"personalizations\": [\n {\n \"id\": \"recommendations-by-interest\",\n \"strategy\": \"score-sorted\",\n \"strategyOptions\": {\n \"threshold\": -1\n },\n \"contents\": [\n {\n \"id\ [...] + }, + "url": { + "raw": "{{baseUrl}}/cxs/context.json", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "context.json" + ] + }, + "description": "Request personalization with score-sorted strategy. Contents are sorted by their filter scores." + }, + "response": [] + } + ] + }, + { + "name": "9. Rule Management", + "item": [ + { + "name": "List All Rules", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/cxs/rules", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "rules" + ] + }, + "description": "Get metadata for all rules", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Get Rule", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/cxs/rules/{{ruleId}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "rules", + "{{ruleId}}" + ] + }, + "description": "Get a specific rule by ID", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Create Rule - Add Profile Property", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"metadata\": {\n \"id\": \"set-premium-on-purchase\",\n \"name\": \"Set Premium on Purchase\",\n \"description\": \"Set premium flag when user makes a purchase\",\n \"scope\": \"{{scope}}\",\n \"enabled\": true\n },\n \"condition\": {\n \"type\": \"eventTypeCondition\",\n \"parameterValues\": {\n \"eventTypeId\": \"purchase\"\n }\n },\n \"actions\": [\n {\n \"type\": \" [...] + }, + "url": { + "raw": "{{baseUrl}}/cxs/rules", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "rules" + ] + }, + "description": "Create a rule that sets a profile property when an event occurs", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Create Rule - Add to Segment", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"metadata\": {\n \"id\": \"add-to-premium-segment\",\n \"name\": \"Add to Premium Segment\",\n \"description\": \"Add profile to premium segment on purchase\",\n \"scope\": \"{{scope}}\",\n \"enabled\": true\n },\n \"condition\": {\n \"type\": \"booleanCondition\",\n \"parameterValues\": {\n \"operator\": \"and\",\n \"subConditions\": [\n {\n \"type\": \"e [...] + }, + "url": { + "raw": "{{baseUrl}}/cxs/rules", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "rules" + ] + }, + "description": "Create a rule that adds a profile to a segment based on event conditions", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Get Rule Statistics", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/cxs/rules/statistics", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "rules", + "statistics" + ] + }, + "description": "Get statistics for all rules", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Get Rule Statistics by ID", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/cxs/rules/{{ruleId}}/statistics", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "rules", + "{{ruleId}}", + "statistics" + ] + }, + "description": "Get statistics for a specific rule", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Delete Rule", + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{baseUrl}}/cxs/rules/{{ruleId}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "rules", + "{{ruleId}}" + ] + }, + "description": "Delete a rule", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + } + ], + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{adminUsername}}", + "type": "string" + }, + { + "key": "password", + "value": "{{adminPassword}}", + "type": "string" + } + ] + } + }, + { + "name": "11. Profile Management", + "item": [ + { + "name": "Get Profile", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/cxs/profiles/{{profileId}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "profiles", + "{{profileId}}" + ] + }, + "description": "Get a profile by ID", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Create/Update Profile", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"itemId\": \"{{profileId}}\",\n \"itemType\": \"profile\",\n \"properties\": {\n \"firstName\": \"John\",\n \"lastName\": \"Doe\",\n \"email\": \"[email protected]\",\n \"age\": 28,\n \"subscriptionType\": \"premium\",\n \"isActive\": true\n }\n}" + }, + "url": { + "raw": "{{baseUrl}}/cxs/profiles", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "profiles" + ] + }, + "description": "Create or update a profile. Sends a profileUpdated event.", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Search Profiles", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"condition\": {\n \"type\": \"profilePropertyCondition\",\n \"parameterValues\": {\n \"propertyName\": \"properties.subscriptionType\",\n \"comparisonOperator\": \"equals\",\n \"propertyValue\": \"premium\"\n }\n },\n \"offset\": 0,\n \"limit\": 50,\n \"sortBy\": \"properties.lastName:asc\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/cxs/profiles/search", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "profiles", + "search" + ] + }, + "description": "Search profiles using a condition query", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Get Profile Count", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/cxs/profiles/count", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "profiles", + "count" + ] + }, + "description": "Get total count of profiles", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Get Profile Segments", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/cxs/profiles/{{profileId}}/segments", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "profiles", + "{{profileId}}", + "segments" + ] + }, + "description": "Get all segments that a profile belongs to", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Get Profile Sessions", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/cxs/profiles/{{profileId}}/sessions?offset=0&size=10", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "profiles", + "{{profileId}}", + "sessions" + ], + "query": [ + { + "key": "offset", + "value": "0" + }, + { + "key": "size", + "value": "10" + } + ] + }, + "description": "Get all sessions for a profile", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Delete Profile", + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{baseUrl}}/cxs/profiles/{{profileId}}", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "profiles", + "{{profileId}}" + ] + }, + "description": "Delete a profile", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + } + ], + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{adminUsername}}", + "type": "string" + }, + { + "key": "password", + "value": "{{adminPassword}}", + "type": "string" + } + ] + } + }, + { + "name": "10. Explain Context Request", + "item": [ + { + "name": "Context Request with Explain", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "X-Unomi-Api-Key", + "value": "{{publicApiKey}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"source\": {\n \"itemId\": \"homepage\",\n \"itemType\": \"page\",\n \"scope\": \"{{scope}}\"\n },\n \"sessionId\": \"{{sessionId}}\",\n \"events\": [\n {\n \"eventType\": \"view\",\n \"scope\": \"{{scope}}\",\n \"source\": {\n \"itemType\": \"site\",\n \"scope\": \"{{scope}}\",\n \"itemId\": \"mysite\"\n },\n \"target\": {\n [...] + }, + "url": { + "raw": "{{baseUrl}}/cxs/context.json?explain=true", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "context.json" + ], + "query": [ + { + "key": "explain", + "value": "true", + "description": "Enable detailed tracing of request processing" + } + ] + }, + "description": "Get context with explain mode enabled. Returns detailed tracing information about rule execution, segment evaluation, and personalization. Requires administrator authentication." + }, + "response": [] + } + ] + }, + { + "name": "12. Additional Useful Requests", + "item": [ + { + "name": "List Event Types", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/cxs/events/types", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "events", + "types" + ] + }, + "description": "Get list of all event type identifiers that the server has processed", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Search Events", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"condition\": {\n \"type\": \"eventTypeCondition\",\n \"parameterValues\": {\n \"eventTypeId\": \"view\"\n }\n },\n \"offset\": 0,\n \"limit\": 50,\n \"sortBy\": \"timeStamp:desc\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/cxs/events/search", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "events", + "search" + ] + }, + "description": "Search for events using a query condition", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Get Session Events", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/cxs/profiles/sessions/{{sessionId}}/events?eventTypes=view&eventTypes=click&offset=0&size=50", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "profiles", + "sessions", + "{{sessionId}}", + "events" + ], + "query": [ + { + "key": "eventTypes", + "value": "view" + }, + { + "key": "eventTypes", + "value": "click" + }, + { + "key": "offset", + "value": "0" + }, + { + "key": "size", + "value": "50" + } + ] + }, + "description": "Get events for a specific session, optionally filtered by event types", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Get Condition Definitions", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/cxs/definitions/conditions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "definitions", + "conditions" + ] + }, + "description": "Get all available condition type definitions", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Get Action Definitions", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/cxs/definitions/actions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "definitions", + "actions" + ] + }, + "description": "Get all available action type definitions", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + }, + { + "name": "Get Property Types", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/cxs/profiles/properties", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "cxs", + "profiles", + "properties" + ] + }, + "description": "Get all known property types organized by target", + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{tenantId}}", + "type": "string" + }, + { + "key": "password", + "value": "{{privateApiKey}}", + "type": "string" + } + ] + } + }, + "response": [] + } + ], + "auth": { + "type": "basic", + "basic": [ + { + "key": "username", + "value": "{{adminUsername}}", + "type": "string" + }, + { + "key": "password", + "value": "{{adminPassword}}", + "type": "string" + } + ] + } + } + ], + "variable": [ + { + "key": "baseUrl", + "value": "http://localhost:8181", + "type": "string" + }, + { + "key": "scope", + "value": "example", + "type": "string" + }, + { + "key": "scopeId", + "value": "example", + "type": "string", + "description": "Scope ID for scope management operations" + }, + { + "key": "sessionId", + "value": "session-123", + "type": "string" + }, + { + "key": "profileId", + "value": "profile-123", + "type": "string" + }, + { + "key": "tenantId", + "value": "mytenant", + "type": "string" + }, + { + "key": "segmentId", + "value": "premium-users", + "type": "string" + }, + { + "key": "ruleId", + "value": "set-premium-on-purchase", + "type": "string" + }, + { + "key": "apiKey", + "value": "YOUR_API_KEY", + "type": "string", + "description": "API key to validate (used in Validate API Key request)" + }, + { + "key": "publicApiKey", + "value": "YOUR_PUBLIC_API_KEY", + "type": "string", + "description": "Public API key from tenant" + }, + { + "key": "privateApiKey", + "value": "YOUR_PRIVATE_API_KEY", + "type": "string", + "description": "Private API key from tenant (used with tenantId for Basic Auth)" + }, + { + "key": "adminUsername", + "value": "karaf", + "type": "string", + "description": "Admin username for administrative endpoints" + }, + { + "key": "adminPassword", + "value": "karaf", + "type": "string", + "description": "Admin password for administrative endpoints" + }, + { + "key": "healthUsername", + "value": "health", + "type": "string", + "description": "Health check username" + }, + { + "key": "healthPassword", + "value": "health", + "type": "string", + "description": "Health check password" + } + ] +} \ No newline at end of file
