API Documentation
Complete reference for the Appizer REST API
Contents
Base URL
https://api.appizer.com/v1
AI-Powered Events & Push Notifications Quickstart
A step-by-step guide to integrate WonderPush with Appizer for automated, AI-generated push notifications.
Quick Steps:
- Integrate WonderPush with your app or website
- Configure Appizer with your WonderPush credentials
- Send user events to Appizer
- Configure AI-generated push notifications
Appizer uses OpenAI's gpt-3.5-turbo model to generate engaging push notifications under 150 characters, optimized for user engagement.
Authentication
All API requests require authentication using your API key in the Authorization header.
Authorization: Bearer YOUR_API_KEY
Keep your API keys secure and never expose them in client-side code. Use environment variables or secure configuration management.
Website Integration (Client JS)
Integrate Appizer with any existing website form (e.g., newsletter signup) using your App ID. The Web SDK posts a user create/update to Appizer in the background and does not block your form's normal submit flow.
Set your website URL in App settings so Appizer can validate origin. Example: https://your-site.example. No API key is required in the browser.
Include the Web SDK
<script src="https://cdn.appizer.com/js/appizer-web.js"></script>
<script>
AppizerWeb.init({
appId: "YOUR_APP_ID",
autoEvents: true, // Automatic page view tracking (including SPAs)
autoHook: true, // Automatic form submission tracking
// Optional: override apiBase for custom environments
// apiBase: "https://api.appizer.com",
// Optional: customize localStorage key for user ID
// userIdStorageKey: "appizer_user_id",
// Optional: enable debug logging
// debug: false,
});
</script>
Auto-hook Forms
Forms with an email field are auto-registered. You can explicitly flag forms with data-appizer="true" or set the App ID per form.
<form id="newsletter" data-appizer="true" data-appizer-app-id="YOUR_APP_ID" action="/subscribe" method="post">
<input type="email" name="email" placeholder="you@example.com" required />
<input type="text" name="firstName" placeholder="First name" />
<input type="text" name="lastName" placeholder="Last name" />
<button type="submit">Subscribe</button>
</form>
<script>
// Your existing submit handler continues to work; SDK posts to Appizer in parallel.
document.getElementById('newsletter').addEventListener('submit', function (e) {
// ... your existing logic (e.g., analytics, server post)
});
</script>
Advanced: Explicit Send via AppizerWeb.sendUser
Use this when your site uses custom AJAX or SPA flows that don’t trigger a native form submit. It sends a user create/update directly to Appizer.
<!-- Ensure the SDK is loaded -->
<script src="https://cdn.appizer.com/js/appizer-web.js"></script>
<script>
// Optional: init to keep defaults in sync
AppizerWeb.init({ appId: "YOUR_APP_ID" });
// In your AJAX flow or button handler
const appId = "YOUR_APP_ID";
const websiteUrl = window.location.origin;
const email = document.querySelector("#email").value;
const firstName = document.querySelector("#firstName")?.value;
const lastName = document.querySelector("#lastName")?.value;
AppizerWeb.sendUser(
{ appId, websiteUrl },
{ appId, websiteUrl, email, firstName, lastName }
).then((resp) => {
console.log("AppizerWeb: user send result", resp);
});
</script>
The AppizerWeb.sendUser(options, payload) method is provided by the SDK and posts in the background.
Custom Email Variable Name
If your form uses a custom email input name (like user[email] or contactEmail), configure the SDK for reliable email discovery.
<script>
AppizerWeb.init({
appId: "YOUR_APP_ID",
// Tell the SDK exactly which input name holds the email
emailField: "user[email]" // or "contactEmail"
});
</script>
<script>
AppizerWeb.init({
appId: "YOUR_APP_ID",
emailSelectors: [
'input[name="email"]',
'input[name="user[email]"]',
'input[name="contactEmail"]',
'input[type="email"]'
]
});
</script>
<script>
const form = document.querySelector('#newsletter');
AppizerWeb.registerForm(form, {
appId: "YOUR_APP_ID",
emailField: "contactEmail" // overrides discovery for this specific form
});
</script>
Manual Hook (Advanced)
Prefer explicit control? Register a form manually:
<script>
const form = document.querySelector('#newsletter');
AppizerWeb.registerForm(form, {
appId: "YOUR_APP_ID",
// Optional: apiBase and endpoint overrides
// apiBase: "https://api.appizer.com",
// endpoint: "/v1/website/users",
// Optional: websiteUrl override (defaults to window.location.origin)
// websiteUrl: "https://your-site.example",
});
</script>
What Gets Sent
The SDK sends a background request to POST /v1/website/users with fields it detects:
{
"appId": "YOUR_APP_ID",
"websiteUrl": "https://your-site.example",
"email": "you@example.com",
// optional fields if present
"firstName": "Ada",
"lastName": "Lovelace",
// or a single name field when first/last not provided
"name": "Ada Lovelace",
// optional externalId if your form provides it
"externalId": "user-123"
}
Security
- No API keys in the browser. Origin is validated against your configured website URL.
- SDK does not block form submission; network issues do not affect your UX.
- Use server-side APIs for privileged operations; the website endpoint is limited to user create/update.
Events
Track Event
Record a custom event for analytics and audience segmentation.
Request
POST /events
Content-Type: application/json
Authorization: Bearer YOUR_API_KEY
{
"event_name": "purchase_completed",
"user_id": "user_123",
"properties": {
"amount": 29.99,
"currency": "USD",
"product_id": "premium_plan"
},
"ip": "192.168.1.1",
"ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
Parameters
- event_name (string, required): Name of the event to track
- user_id (string, required): Your unique identifier for the user
- properties (object, optional): Additional event attributes as key-value pairs
- ip (string, optional): User's IP address for analytics tracking
- ua (string, optional): User agent string for device/browser tracking
Parameters
- events (array, required): Array of event objects to track
- event_name (string, required): Name of the event to track
- user_id (string, required): Your unique identifier for the user
- properties (object, optional): Additional event attributes as key-value pairs
- ip (string, optional): User's IP address for analytics tracking
- ua (string, optional): User agent string for device/browser tracking
Response
{
"success": true,
"event_id": "evt_789",
"message": "Event tracked successfully"
}
Batch Track Events
Track multiple events in a single request for better performance.
Request
POST /events/batch
Content-Type: application/json
Authorization: Bearer YOUR_API_KEY
{
"events": [
{
"event_name": "page_view",
"user_id": "user_123",
"properties": {
"page": "/dashboard"
},
"ip": "192.168.1.1",
"ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
},
{
"event_name": "button_click",
"user_id": "user_123",
"properties": {
"button_id": "cta_button"
}
}
]
}
Response
{
"success": true,
"processed_count": 2,
"message": "Batch events tracked successfully"
}
User Management
Create or Update User
Create or update user profile information. If a user with the same user_id exists, their information will be updated.
Request
POST /users
Content-Type: application/json
Authorization: Bearer YOUR_API_KEY
{
"user_id": "user_123",
"email": "user@example.com",
"phone": "+1234567890",
"properties": {
"name": "John Doe",
"plan": "premium",
"signup_date": "2023-06-15"
},
"origin": {
"channel": "ios-app",
"campaign": "spring-launch",
"label": "Onboarding Flow"
}
}
Parameters
- user_id (string, required): Your unique identifier for the user
- email (string, optional): User's email address
- phone (string, optional): User's phone number with country code (e.g., +1234567890)
- properties (object, optional): Additional user attributes as key-value pairs
- origin (object, optional): Free-form metadata describing where this user originated (e.g., acquisition channel, campaign, internal system). Stored verbatim and visible in the dashboard.
Response
{
"success": true,
"user_id": "usr_789",
"external_id": "user_123",
"message": "User created/updated successfully"
}
Create User Alias
Add an alternative identifier that references an existing user. After creating an alias, you can pass either ID in future API calls.
Request
POST /users/aliases
Content-Type: application/json
Authorization: Bearer YOUR_API_KEY
{
"user_id": "user_123",
"alias_id": "legacy_999"
}
Parameters
- user_id (string, required): ID of the existing user (you may instead supply
primary_user_idUUID). - alias_id (string, required): New alias to associate.
Response
{
"success": true,
"alias_id": "legacy_999",
"user_id": "user_123",
"message": "Alias created"
}
Replace User ID
Update an existing user_id to a new identifier.
Request
POST /users/replace-id
Content-Type: application/json
Authorization: Bearer YOUR_API_KEY
{
"user_id": "user_123",
"new_user_id": "user_456"
}
Parameters
- user_id (string, required): Current user identifier.
- new_user_id (string, required): Desired new identifier.
Response
{
"success": true,
"user_id": "user_456",
"message": "User ID updated"
}
Analytics
Query Analytics
Run analytics queries using natural language or SQL.
Get Metrics
Retrieve pre-calculated metrics and KPIs.
Audiences
Create Audience
Create a smart audience segment using natural language.
List Audiences
Get all audiences for an app.
Push Notifications
Send Push Notification
Send a push notification to a specific user using their user_id (external_id). Supports both static messages and AI-generated content.
Prerequisites: An Engagement Platform (such as WonderPush) must be configured for your app, and the user must have an external_id set (typically the user ID from your engagement platform).
Static Message Request
POST /v1/sendpush
Content-Type: application/json
Authorization: Bearer YOUR_API_KEY
{
"user_id": "user_123",
"title": "Welcome Back!",
"message": "We miss you! Come see what is new.",
"action_url": "https://example.com/welcome"
}
AI-Generated Message Request
Instead of a static message, provide a prompt for AI generation:
POST /v1/sendpush
Content-Type: application/json
Authorization: Bearer YOUR_API_KEY
{
"user_id": "user_123",
"title": "Special Offer",
"prompt": "Create an engaging message about a 50% off sale for returning users",
"max_characters": 150,
"action_url": "https://example.com/sale"
}
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| user_id | string | Yes | The external_id of the target user from the app_users table |
| title | string | Yes | Push notification title (max 255 characters) |
| message | string | Conditional | Static message content. Required if prompt not provided. |
| prompt | string | Conditional | AI prompt for generating message. Required if message not provided. |
| max_characters | integer | No | Max characters for AI generation (default: 150, max: 500) |
| action_url | string | No | URL to open when user taps the notification |
Response
{
"success": true,
"message": "Push notification sent successfully",
"deliveryId": "wp_del_abc123",
"recipientCount": 1
}
// When using AI generation, response includes:
{
"success": true,
"message": "Push notification sent successfully",
"deliveryId": "wp_del_abc123",
"recipientCount": 1,
"generatedMessage": "Ready to crush your goals? Check out our new tracking feature!"
}
Note: The generatedMessage field is only included when using AI generation (prompt parameter).
Error Codes
- 400 - Validation Error or WonderPush not configured
- 401 - Invalid or missing API key
- 404 - User not found with the provided user_id
- 500 - Internal Server Error
Model Context Protocol (MCP) Server v2.0
The Model Context Protocol (MCP) v2.0 is a standardized protocol that connects AI systems like Windsurf and Claude Desktop with Appizer's data and functionality using JSON-RPC 2.0 over Streamable HTTP transport (session-based).
Protocol Version: 2025-11-25
Compatible with Windsurf, Claude Desktop, and other MCP clients
Overview
MCP v2.0 provides:
- 6 Tools for querying events, users, apps, and audiences
- URI-based Resources for read-only data access
- JSON-RPC 2.0 Protocol for standardized communication
- Organization-scoped Access with secure API key authentication
Quick Start with Windsurf
- Go to Settings → MCP Server
- Generate an API key and enable MCP
- Copy the Windsurf configuration
- Add to
~/.codeium/mcp_config.json - Restart Windsurf and start using Appizer tools!
Authentication
MCP uses a dedicated API key for authentication. This key is separate from your regular Appizer API keys and can be managed in your organization settings.
X-MCP-API-Key: YOUR_MCP_API_KEY
MCP API keys have broad access to your organization's data. Keep them secure and rotate them regularly.
Server Endpoint
POST https://app.appizer.com/mcp
All MCP requests use JSON-RPC 2.0 format sent via POST to this endpoint.
Session-based transport: Clients must call initialize first and include the returned sessionId in subsequent requests (header MCP-Session-Id).
Editor Config
Windsurf (uses serverUrl)
Config: ~/.codeium/mcp_config.json
{
"mcpServers": {
"appizer": {
"serverUrl": "https://app.appizer.com/mcp",
"headers": { "X-MCP-API-Key": "YOUR_MCP_API_KEY" }
}
}
}
Cursor IDE (uses url)
Config: ~/.cursor/mcp_config.json
{
"mcpServers": {
"appizer": {
"url": "https://app.appizer.com/mcp",
"headers": { "X-MCP-API-Key": "YOUR_MCP_API_KEY" }
}
}
}
Claude Desktop (uses url)
Config: ~/Library/Application Support/Claude/claude_desktop_config.json
{
"mcpServers": {
"appizer": {
"url": "https://app.appizer.com/mcp",
"headers": { "X-MCP-API-Key": "YOUR_MCP_API_KEY" }
}
}
}
Claude Code (requires transport: "http")
Config: ~/.claude.json or .mcp.json
{
"mcpServers": {
"appizer": {
"transport": "http",
"url": "https://app.appizer.com/mcp",
"headers": { "X-MCP-API-Key": "YOUR_MCP_API_KEY" }
}
}
}
Google Antigravity (uses serverUrl)
Config: Extensions → Model Context Protocol
{
"mcpServers": {
"appizer": {
"serverUrl": "https://app.appizer.com/mcp",
"headers": { "X-MCP-API-Key": "YOUR_MCP_API_KEY" }
}
}
}
Claude Code CLI: You can also configure via CLI: claude mcp add --transport http appizer https://app.appizer.com/mcp --header "X-MCP-API-Key: YOUR_KEY"
Available Endpoints
/mcp
Server Information
Returns basic information about the MCP server.
Response
{
"name": "Appizer MCP Server",
"version": "2.0.0",
"protocol_version": "2025-11-25",
"status": "active",
"transport": "Streamable HTTP (JSON-RPC 2.0)",
"timestamp": "2026-01-22T15:30:00.000Z",
"documentation": "/mcp/docs"
}
/mcp/docs
API Documentation
Returns detailed information about available methods, tools, and Windsurf configuration.
Response
{
"name": "Appizer MCP Server",
"version": "2.0.0",
"protocol_version": "2025-11-25",
"methods": ["initialize", "tools/list", "tools/call", ...],
"tools": [{"name": "query_events", ...}, ...],
"windsurf_config": {...}
}
/mcp/resources
List Available Resources
Returns a list of resources available through the MCP server.
Response
{
"resources": {
"apps": [
{
"id": "app_123",
"name": "Mobile App",
"description": "iOS and Android app",
"type": "app",
"uri": "/mcp/resources/apps/app_123"
}
],
"audiences": [
{
"id": "aud_456",
"name": "Active Users",
"description": "Users active in the last 30 days",
"type": "audience",
"app_id": "app_123",
"uri": "/mcp/resources/audiences/aud_456"
}
]
}
}
/mcp/resources/apps/:appId
Get App Details
Returns detailed information about a specific app.
Response
{
"id": "app_123",
"name": "Mobile App",
"description": "iOS and Android app",
"created_at": "2025-01-15T10:30:00Z",
"updated_at": "2025-07-01T14:22:10Z",
"stats": {
"users": 15420,
"events": 982345,
"last_activity": "2025-07-19T21:15:33Z"
},
"top_events": [
{ "name": "app_open", "count": 45678 },
{ "name": "purchase", "count": 2341 }
]
}
/mcp/events
Query Events
Allows querying events with various filters.
Parameters
app_id- Filter by app IDevent_name- Filter by event nameuser_id- Filter by user IDlimit- Maximum number of results (default: 100, max: 1000)offset- Pagination offset (default: 0)
Response
{
"events": [
{
"id": "evt_789",
"app_id": "app_123",
"user_id": "user_456",
"event_name": "purchase",
"properties": { "amount": 49.99, "item": "Premium Plan" },
"created_at": "2025-07-19T20:15:33Z"
}
],
"pagination": {
"total": 982345,
"limit": 100,
"offset": 0,
"has_more": true
}
}
/mcp/resources/apps/:appId/versions
Get App Versions
Returns version release history for an app. Use this to analyze how new releases impact performance and engagement.
Response
{
"app_id": "app_123",
"app_name": "Mobile App",
"current_version": "2.1.0",
"versions": [
{
"id": "ver_789",
"version": "2.1.0",
"release_notes": "New onboarding flow",
"released_at": "2026-01-15T10:00:00Z",
"created_by": "user@example.com"
},
{
"id": "ver_456",
"version": "2.0.0",
"release_notes": "Major redesign",
"released_at": "2025-12-01T09:00:00Z",
"created_by": "user@example.com"
}
],
"total": 2
}
Use Case: Query events before and after a version release to measure the impact of new features on user engagement, retention, and conversion rates.
get_app_versions
Get App Versions Tool
MCP tool for AI assistants to fetch version history with optional date filtering.
Parameters
app_id(required) - App ID to retrieve versions forstart_date(optional) - Filter versions released after this date (ISO 8601)end_date(optional) - Filter versions released before this date (ISO 8601)
Example Prompt
"Show me how user engagement changed after we released version 2.0 on December 1st"
The AI assistant will use get_app_versions to find the release date, then query events before and after to compare metrics.
create_audience
Create Audience Tool
Create an audience from a natural language description with AI-powered SQL generation. The tool uses pattern matching, vector similarity, and LLM generation to convert descriptions into SQL queries.
Parameters
app_id(optional) - Target app (auto-selected if org has 1 app)name(required) - Audience namedescription(required) - Natural language description used as AI prompt
Example Prompt
"Create an audience of users who haven't been active in the last 7 days"
Response
{
"audience_id": "uuid",
"name": "Inactive Users - 7 Days",
"user_count": 1245,
"query_method": "pattern_last_seen",
"confidence": 0.95
}
Security: Generated SQL is validated against a blocklist (no DROP/DELETE/UPDATE) and executed in read-only transactions with 30-second timeouts.
create_push_campaign
Create Push Campaign Tool
Create a push notification campaign with optional AI-generated message, audience, and trigger event detection. Supports scheduled, recurring, slipping_away, and trigger-based campaigns.
Parameters
app_id(optional) - Target app (auto-selected if org has 1 app)name(required) - Campaign identifiertitle(required) - Push notification titlemessage(conditional) - Static message (if no prompt)prompt(conditional) - AI prompt for message generationaudience_id(optional) - Existing audience to targetaudience_prompt(optional) - Create audience from this promptschedule_type(required) - scheduled, recurring, slipping_away, or triggerscheduled_at(conditional) - ISO 8601 datetime for scheduledtrigger_event_name(conditional) - Exact event name for trigger campaignstrigger_event_prompt(conditional) - Natural language description - AI matches to tracked eventsaction_url(optional) - URL to open on tap
Trigger Campaigns: Use trigger_event_prompt with natural language like "when user finishes a level" and the AI will match it to your tracked events (e.g., "level_complete"). Or use trigger_event_name for exact event names.
Note: schedule_type: "now" is not supported via MCP to prevent accidental mass sends. Use the dashboard for immediate campaigns.
Example Prompt - Scheduled
"Create a re-engagement campaign for users inactive for 7 days. Schedule it for tomorrow at 10am with a message about our new features."
Example Prompt - Trigger
"Create a campaign that sends a congratulations message when a user finishes a level"
Response
{
"campaign_id": "uuid",
"name": "Re-engagement Campaign",
"status": "scheduled",
"audience": {
"id": "audience-uuid",
"user_count": 1245,
"auto_created": true
},
"trigger": {
"event_name": "level_complete",
"match_method": "llm_semantic",
"available_events_count": 47
},
"scheduled_at": "2026-02-04T10:00:00Z"
}
list_push_campaigns
List Push Campaigns Tool
List push notification campaigns for an app with optional status filtering and delivery stats.
Parameters
app_id(optional) - Target app (auto-selected if org has 1 app)status(optional) - Filter by: scheduled, live, paused, sentlimit(optional) - Max results (default: 50)
Example Prompt
"Show me all my live push campaigns"
list_event_dictionary
List Event Dictionary Tool
List event dictionary entries for an app with optional filtering by archived status, undefined events, or search terms.
Parameters
app_id(required) - Target app IDinclude_archived(optional) - Include archived events (default: false)only_undefined(optional) - Show only events without definitions (default: false)search(optional) - Search event names (case-insensitive partial match)limit(optional) - Max results (default: 100, max: 500)
Example Prompts
"List all events that don't have definitions yet"
"Show me archived events"
"Find events with 'purchase' in the name"
update_event_definition
Update Event Definition Tool
Update the definition for a single event by ID or name. Can also be used to clear definitions or archive events.
Parameters
app_id(required) - Target app IDevent_id(optional) - Event dictionary ID (use this OR event_name)event_name(optional) - Event name to update (use this OR event_id)definition(required) - New definition text (empty string to clear)
Security: Clearing all definitions (empty definition + no event_id/event_name) is only allowed from the dashboard, not via MCP.
Example Prompts
"Update the definition for 'purchase_completed' to 'User successfully completed a purchase'"
"Archive the 'old_event' event"
auto_define_events
Auto-Define Events Tool
AI-powered batch definition generation for events. Analyzes event names, usage patterns, and sample data to generate meaningful definitions.
Parameters
app_id(required) - Target app IDmode(required) - "empty_only" or "overwrite_all"dry_run(optional) - Preview changes without saving (default: false)event_names(optional) - Array of specific event names to process
AI-Powered: Uses OpenAI to analyze event context including name patterns, usage frequency, sample properties, and related events to generate accurate definitions.
Security: The "overwrite_all" mode is only allowed from the dashboard to prevent accidental overwrites of existing definitions via MCP.
Example Prompts
"Auto-generate definitions for all undefined events"
"Preview AI-generated definitions without saving them"
"Generate definitions for 'purchase_completed' and 'signup_started' events"
Response
{
"app_id": "app-123",
"app_name": "My App",
"mode": "empty_only",
"dry_run": false,
"definitions_generated": 12,
"definitions_updated": 12,
"llm_used": true,
"definitions": [
{
"event_name": "purchase_completed",
"definition": "User successfully completed a purchase transaction",
"updated": true
}
],
"note": "Definitions have been saved to the event dictionary."
}
MCP Use Cases & Implementation Guides
The Model Context Protocol can be utilized in various scenarios. Here are detailed guides for common use cases:
Agentic Coding Assistant
Implement an AI coding assistant that can access your app's event data to suggest code improvements or debug issues.
Setup Steps:
- Enable MCP in your organization settings
- Generate a dedicated MCP API key for your coding assistant
- Implement the following integration code in your development environment
Example Implementation:
# Python example for VSCode extension or Jupyter notebook
import os
from openai import OpenAI
import requests
class AppizerDevAgent:
def __init__(self, mcp_api_key, openai_api_key):
self.mcp_api_key = mcp_api_key
self.mcp_base_url = "https://api.appizer.com/mcp"
self.mcp_headers = {"X-MCP-API-Key": mcp_api_key}
self.client = OpenAI(api_key=openai_api_key)
def get_event_data(self, app_id, event_name=None, limit=10):
"""Fetch recent events from the app"""
params = {"app_id": app_id, "limit": limit}
if event_name:
params["event_name"] = event_name
response = requests.get(
f"{self.mcp_base_url}/events",
headers=self.mcp_headers,
params=params
)
return response.json()
def analyze_code_with_context(self, code_snippet, issue_description):
"""Analyze code with context from app events"""
# Get event data for context
events_data = self.get_event_data(app_id="YOUR_APP_ID")
# Create prompt with code and event context
prompt = f"""
Analyze this code snippet:
```
{code_snippet}
```
Issue description: {issue_description}
Recent app events for context:
{events_data}
Please provide suggestions to fix the issue based on the code and event data.
"""
# Get AI analysis
response = self.client.chat.completions.create(
model="gpt-4",
messages=[
{"role": "system", "content": "You are a coding assistant with access to app event data."},
{"role": "user", "content": prompt}
]
)
return {
"visualizations": [],
"insights": response.choices[0].message.content
}
# Usage
agent = AppizerDevAgent(
mcp_api_key="YOUR_MCP_API_KEY",
openai_api_key="YOUR_OPENAI_API_KEY"
)
# Example analysis
code = """
function processUserPurchase(userId, itemId) {
// Implementation with potential issues
const user = getUser(userId);
const item = getItem(itemId);
if (user.credits >= item.price) {
user.credits -= item.price;
user.items.push(item);
trackEvent('purchase', { userId, itemId });
}
}
"""
analysis = agent.analyze_code_with_context(
code,
"Users report purchases sometimes fail even with sufficient credits"
)
print(analysis["insights"])
Key Benefits:
- AI coding assistance with real-time app data context
- Debug issues with actual event data from your application
- Generate code suggestions based on user behavior patterns
- Automate repetitive development tasks with app-aware AI
Customer Support AI
Build a support chatbot that can access user data and event history to provide personalized assistance.
Example Implementation:
// Node.js example for a customer support chatbot
const axios = require('axios');
const { OpenAI } = require('openai');
class AppizerSupportBot {
constructor(mcpApiKey, openaiApiKey) {
this.mcpApiKey = mcpApiKey;
this.mcpBaseUrl = 'https://api.appizer.com/mcp';
this.openai = new OpenAI({ apiKey: openaiApiKey });
}
async getUserData(userId) {
try {
const response = await axios.get(`${this.mcpBaseUrl}/users/${userId}`, {
headers: { 'X-MCP-API-Key': this.mcpApiKey }
});
return response.data;
} catch (error) {
console.error('Error fetching user data:', error);
return null;
}
}
async getUserEvents(userId, limit = 10) {
try {
const response = await axios.get(`${this.mcpBaseUrl}/events`, {
headers: { 'X-MCP-API-Key': this.mcpApiKey },
params: { user_id: userId, limit }
});
return response.data.events;
} catch (error) {
console.error('Error fetching user events:', error);
return [];
}
}
async handleSupportQuery(userId, query) {
// Get user context
const userData = await this.getUserData(userId);
const userEvents = await this.getUserEvents(userId);
// Create context-aware prompt
const systemPrompt = `You are a helpful customer support assistant for our app.
You have access to the following user data: ${JSON.stringify(userData)}
Recent user activity: ${JSON.stringify(userEvents)}
Based on this context, provide a helpful, personalized response.`;
// Generate AI response
const completion = await this.openai.chat.completions.create({
model: "gpt-4",
messages: [
{ role: "system", content: systemPrompt },
{ role: "user", content: query }
]
});
return completion.choices[0].message.content;
}
}
// Usage example
const supportBot = new AppizerSupportBot(
'YOUR_MCP_API_KEY',
'YOUR_OPENAI_API_KEY'
);
async function handleCustomerQuery(userId, query) {
const response = await supportBot.handleSupportQuery(userId, query);
console.log(`Response for user ${userId}: ${response}`);
return response;
}
// Example usage
handleCustomerQuery('user_123', 'Why was I charged twice for my subscription?');
AI-Powered Analytics
Generate insights and visualizations from your app data using AI.
Example Implementation:
# Python example for data analysis with pandas and matplotlib
import os
import requests
import pandas as pd
import matplotlib.pyplot as plt
from openai import OpenAI
class AppizerAnalytics:
def __init__(self, mcp_api_key, openai_api_key):
self.mcp_api_key = mcp_api_key
self.mcp_base_url = "https://api.appizer.com/mcp"
self.mcp_headers = {"X-MCP-API-Key": mcp_api_key}
self.client = OpenAI(api_key=openai_api_key)
def get_event_data(self, app_id, event_name=None, days=30, limit=1000):
"""Fetch event data for analysis"""
params = {"app_id": app_id, "limit": limit}
if event_name:
params["event_name"] = event_name
response = requests.get(
f"{self.mcp_base_url}/events",
headers=self.mcp_headers,
params=params
)
return response.json()["events"]
def analyze_events(self, app_id, event_name):
"""Analyze specific event patterns"""
# Get event data
events = self.get_event_data(app_id, event_name)
# Convert to DataFrame for analysis
df = pd.DataFrame(events)
# Extract timestamps and convert to datetime
df['created_at'] = pd.to_datetime(df['created_at'])
df['date'] = df['created_at'].dt.date
# Group by date and count events
daily_counts = df.groupby('date').size().reset_index(name='count')
# Create visualization
plt.figure(figsize=(10, 6))
plt.plot(daily_counts['date'], daily_counts['count'])
plt.title(f'{event_name} Events Over Time')
plt.xlabel('Date')
plt.ylabel('Event Count')
plt.xticks(rotation=45)
plt.tight_layout()
# Save visualization
viz_path = f"{event_name}_trend.png"
plt.savefig(viz_path)
# Generate AI insights
prompt = f"""
Analyze this event data for {event_name} events:
{daily_counts.to_string()}
Provide 3-5 key insights about user behavior patterns, anomalies,
and recommendations based on this data.
"""
response = self.client.chat.completions.create(
model="gpt-4",
messages=[
{"role": "system", "content": "You are a data analyst providing insights on app usage patterns."},
{"role": "user", "content": prompt}
]
)
return {
"visualization_path": viz_path,
"insights": response.choices[0].message.content,
"raw_data": daily_counts.to_dict()
}
# Usage
analytics = AppizerAnalytics(
mcp_api_key="YOUR_MCP_API_KEY",
openai_api_key="YOUR_OPENAI_API_KEY"
)
# Example analysis
results = analytics.analyze_events("app_123", "purchase")
print(results["insights"])
Environment Setup Best Practices
Follow these best practices when setting up MCP in your environment:
Environment Configuration
API Key Management:
- Create dedicated API keys for each integration
- Store keys in environment variables, never hardcode them
- Implement a key rotation schedule (e.g., quarterly)
- Set up access logging for all MCP API calls
Example .env File:
# Development environment
APPIZER_MCP_API_KEY=your_dev_mcp_key_here
APPIZER_MCP_BASE_URL=https://api.appizer.com/mcp
APPIZER_ORG_ID=your_org_id_here
# For production, use a different key with appropriate permissions
# APPIZER_MCP_API_KEY_PROD=your_prod_mcp_key_here
# For AI integrations
OPENAI_API_KEY=your_openai_key_here
Monitoring MCP Usage:
// Node.js example for logging MCP API access
const winston = require('winston');
const axios = require('axios');
// Configure logger
const logger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
defaultMeta: { service: 'mcp-client' },
transports: [
new winston.transports.File({ filename: 'mcp-access.log' })
]
});
// Create axios instance with interceptors
const mcpClient = axios.create({
baseURL: process.env.APPIZER_MCP_BASE_URL,
headers: { 'X-MCP-API-Key': process.env.APPIZER_MCP_API_KEY }
});
// Log all requests
mcpClient.interceptors.request.use(request => {
logger.info('MCP API Request', {
method: request.method,
url: request.url,
params: request.params
});
return request;
});
// Log all responses
mcpClient.interceptors.response.use(
response => {
logger.info('MCP API Response', {
status: response.status,
data: response.data ? 'Data received' : 'No data'
});
return response;
},
error => {
logger.error('MCP API Error', {
status: error.response?.status,
message: error.message
});
return Promise.reject(error);
}
);
// Example usage
async function fetchApps() {
try {
const response = await mcpClient.get('/resources');
return response.data;
} catch (error) {
console.error('Error fetching resources:', error);
return null;
}
}
Integration with AI Systems
MCP is designed to work with various AI systems and frameworks. Here are some common integration patterns:
LangChain Integration
Example of integrating MCP with LangChain:
# Python example with LangChain
from langchain.tools import BaseTool
from langchain.agents import initialize_agent
from langchain.chat_models import ChatOpenAI
import requests
class AppizerMCPTool(BaseTool):
name = "appizer_mcp"
description = "Access Appizer data through MCP"
def __init__(self, api_key):
self.api_key = api_key
self.base_url = "https://api.appizer.com/mcp"
self.headers = {"X-MCP-API-Key": api_key}
def _run(self, query):
# Example: Get app resources
response = requests.get(
f"{self.base_url}/resources",
headers=self.headers
)
return response.json()
# Initialize the tool and language model
mcp_tool = AppizerMCPTool(api_key="YOUR_MCP_API_KEY")
llm = ChatOpenAI(model="gpt-4")
# Use with an agent
agent = initialize_agent([mcp_tool], llm, agent="zero-shot-react-description")
result = agent.run("What apps are available in my Appizer account?")
Code Editor Integration
Enable Appizer MCP in AI-powered code editors to enhance your development workflow. Different editors use different configuration formats:
Windsurf
Windsurf expects serverUrl in the configuration:
{
"mcpServers": {
"appizer": {
"serverUrl": "https://app.appizer.com/mcp",
"headers": {
"X-MCP-API-Key": "YOUR_MCP_API_KEY"
}
}
}
}
Cursor IDE
Cursor uses url and stores config in ~/.cursor/mcp_config.json:
{
"mcpServers": {
"appizer": {
"url": "https://app.appizer.com/mcp",
"headers": {
"X-MCP-API-Key": "YOUR_MCP_API_KEY"
}
}
}
}
Setup: Open Cursor Settings (Cmd/Ctrl + ,) → Search for "MCP" → Click "Edit Config" → Add the configuration above → Restart Cursor
Claude Desktop
Claude Desktop uses url and stores config in ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"appizer": {
"url": "https://app.appizer.com/mcp",
"headers": {
"X-MCP-API-Key": "YOUR_MCP_API_KEY"
}
}
}
}
Claude Code
Claude Code requires explicit transport specification for HTTP servers. You can configure it via CLI or JSON:
CLI Configuration (Recommended):
claude mcp add --transport http appizer https://app.appizer.com/mcp \
--header "X-MCP-API-Key: YOUR_MCP_API_KEY"
JSON Configuration: Add to ~/.claude.json (user scope) or .mcp.json (project scope):
{
"mcpServers": {
"appizer": {
"transport": "http",
"url": "https://app.appizer.com/mcp",
"headers": {
"X-MCP-API-Key": "YOUR_MCP_API_KEY"
}
}
}
}
Verify Connection: Run claude mcp list and claude mcp get appizer
Google Antigravity
Google Antigravity uses serverUrl and is configured via Extensions → Model Context Protocol:
{
"mcpServers": {
"appizer": {
"serverUrl": "https://app.appizer.com/mcp",
"headers": {
"X-MCP-API-Key": "YOUR_MCP_API_KEY"
}
}
}
}
Setup: Open Antigravity settings → Navigate to Extensions → Model Context Protocol → Add the configuration above → Restart Antigravity
SSE-based Editors
Some editors expect url instead of serverUrl:
{
"mcpServers": {
"appizer": {
"url": "https://app.appizer.com/mcp",
"headers": {
"X-MCP-API-Key": "YOUR_MCP_API_KEY"
}
}
}
}
Editor Features
- Access your Appizer resources directly from your editor
- Query events, users, and analytics data in real-time
- Generate code based on your Appizer data models
- Debug MCP integrations with inline suggestions
- Receive contextual documentation while coding
Security Best Practices
- Rotate your MCP API keys regularly
- Monitor MCP usage for unusual patterns
- Limit MCP access to trusted AI systems
- Review the data accessible through MCP
- Disable MCP when not in use
MCP provides AI systems with access to your organization's data. Always review what data is being shared and with which systems.
Error Codes
| Code | Description |
|---|---|
| 400 | Bad Request - The request was invalid or cannot be served |
| 401 | Unauthorized - Authentication failed or user doesn't have permissions |
| 404 | Not Found - The specified resource could not be found |
| 429 | Too Many Requests - Rate limit exceeded |
| 500 | Internal Server Error - Something went wrong on our end |
Rate Limits
Rate Limits
API requests are rate limited to prevent abuse and ensure service quality:
- Events API: 1,000 requests per minute
- Analytics API: 100 requests per minute
- Other APIs: 500 requests per minute
- Batch Events: 100 requests per minute (up to 100 events per batch)