Specprom Integration
Integration for Спецпром-КР: voice assistants and YML catalog sync from specprom-kr.com.ua.
Overview
- Setup — Initialize database, secrets, KV
- Call handlers — call-originate, call-events, agent-init, agent-postcall (Happ Voice)
- XML Catalog Sync — Fetch and parse YML catalog, store categories and offers in D1
- Healthcheck — Monitor integration availability
Quick Start
# Local development
pnpm dev
# Deploy to dev
pnpm deploy:dev
# Deploy to production
pnpm deploy
# View logs
wrangler tail --env devProject Structure
src/
├── index.ts
├── types.ts
├── config/
├── handlers/
│ ├── call-originate.ts
│ ├── call-events.ts
│ ├── agent-init.ts
│ ├── agent-postcall.ts
│ └── xml-catalog-sync.ts # YML catalog sync
├── migrations/
└── utils/XML Catalog Sync
Syncs YML catalog from Specprom (categories + offers) to D1. URL is configurable via KV config xml_catalog.url (default: https://specprom-kr.com.ua/price/smart_search_ua.xml).
Runs automatically: daily at 3:00 UTC via cron.
Manual trigger:
curl -X POST https://integ.happ.tools/specprom/webhook/xml-catalog-sync \
-H "Content-Type: application/json" \
-d '{}'
# With URL override:
curl -X POST https://integ.happ.tools/specprom/webhook/xml-catalog-sync \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/catalog.xml"}'Response:
{
"success": true,
"categoriesCount": 42,
"offersCount": 1250
}API Endpoints
POST /setup
Initialize database tables, create empty secret placeholders, and set up KV storage.
Request:
{
"force": false
}Response:
{
"success": true,
"database": {
"migrated": true,
"tables": ["specprom_calls"]
},
"secrets": {
"created": ["API_KEY", "API_SECRET"],
"existing": []
},
"errors": []
}POST /init-webhook
Called by the voice/text assistant BEFORE starting a conversation. Use this to search for the contact in CRM by phone number and prepare context.
Request:
{
"phone": "+380501234567",
"conversationId": "conv_123"
}Response:
{
"firstMessage": "Hello John! How can I help you today?",
"context": {
"clientName": "John Doe",
"company": "Acme Corp",
"source": "Website",
"previousInteractions": "Last call: 2024-01-10"
}
}POST /post-webhook
Called by the voice/text assistant AFTER the conversation ends. Use this to create or update records in CRM.
Request:
{
"conversationId": "conv_123",
"phone": "+380501234567",
"transcript": "Full conversation transcript...",
"outcome": "completed",
"duration": 180
}Response:
{
"success": true,
"message": "Conversation processed successfully",
"recordId": "rec_456"
}Outcome values: completed, transferred, no_answer, busy, failed
GET /health
Check availability of all integration components (D1, KV, Credentials).
Response:
{
"timestamp": "2024-01-15T10:00:00.000Z",
"testId": "test_1705312800000",
"success": true,
"checks": {
"d1": { "success": true, "details": { "tableExists": true } },
"kv": { "success": true, "details": { "writeRead": true } },
"creds": { "success": true, "details": { "keysFound": ["API_KEY"] } }
}
}POST /webhook/:action
Generic webhook endpoint for custom actions. Handlers are called directly for processing.
Example:
curl -X POST https://integ.happ.tools/specprom/webhook/custom-action \
-H "Content-Type: application/json" \
-d '{"recordId": "123", "data": {...}}'Response:
{
"status": "accepted"
}Environment Variables
Cloudflare Bindings (wrangler.toml)
| Binding | Type | Description |
|---|---|---|
INTEG_DB | D1 | Database for credentials and data |
INTEG_KV | KV | KV storage for caching |
Global Secrets (Doppler)
| Variable | Description |
|---|---|
CRYPTO_KEY | Encryption key for credentials |
CRYPTO_SALT | Salt for encryption |
Integration Secrets (D1 creds table)
Configure your CRM-specific secrets in src/handlers/setup.ts:
const REQUIRED_SECRETS: (keyof ISpecpromCredentials)[] = [
"API_KEY",
"API_SECRET",
"WEBHOOK_URL",
];Implementing CRM Integration
1. Define Credentials
Edit src/types.ts:
export interface ISpecpromCredentials {
API_KEY: string;
API_SECRET: string;
FOLDER_ID: string;
}2. Update Setup Handler
Edit src/handlers/setup.ts:
const REQUIRED_SECRETS: (keyof ISpecpromCredentials)[] = [
"API_KEY",
"API_SECRET",
"FOLDER_ID",
];3. Implement Init Webhook
Edit src/handlers/init-webhook.ts:
import { YourCRMClient } from "@happ-integ/your-crm";
export async function handleInitWebhook(payload: IInitWebhookPayload) {
const secrets = await creds.get<ISpecpromCredentials>("specprom");
const crmClient = new YourCRMClient(secrets.API_KEY);
// Find contact by phone
const contact = await crmClient.findByPhone(payload.phone);
return {
firstMessage: `Hello ${contact.name}! How can I help you?`,
context: {
clientName: contact.name,
company: contact.company,
// ...
},
};
}4. Implement Post Webhook
Edit src/handlers/post-webhook.ts:
export async function handlePostWebhook(payload: IPostWebhookPayload) {
const secrets = await creds.get<ISpecpromCredentials>("specprom");
const crmClient = new YourCRMClient(secrets.API_KEY);
// Update CRM record
await crmClient.createCallRecord({
phone: payload.phone,
transcript: payload.transcript,
outcome: payload.outcome,
duration: payload.duration,
});
return { success: true };
}Database Migrations
Create migrations in migrations/ folder:
migrations/0001_create_calls.up.sql:
CREATE TABLE IF NOT EXISTS specprom_calls (
id TEXT PRIMARY KEY,
phone TEXT NOT NULL,
conversation_id TEXT UNIQUE,
status TEXT NOT NULL DEFAULT 'initiated',
transcript TEXT,
outcome TEXT,
duration INTEGER,
created_at TEXT DEFAULT (datetime('now')),
updated_at TEXT DEFAULT (datetime('now'))
);
CREATE INDEX idx_specprom_calls_phone ON specprom_calls(phone);
CREATE INDEX idx_specprom_calls_status ON specprom_calls(status);Testing
# Run tests
pnpm test
# Test healthcheck
curl https://integ.dev.happ.tools/specprom/health
# Test init webhook
curl -X POST https://integ.dev.happ.tools/specprom/init-webhook \
-H "Content-Type: application/json" \
-d '{"phone": "+380501234567", "conversationId": "test_123"}'Troubleshooting
Credentials not found
- Run
/setupendpoint first - Fill in secrets via integ-admin → Secrets page
- Run
/healthto verify
Database table not found
- Ensure migrations are defined in
src/migrations/index.ts - Run
/setupendpoint to apply migrations
Related Documentation
- INTEGRATION_CHECKLIST.md — Step-by-step guide
- SECRETS.md — Managing secrets
- DEVELOPMENT.md — Local development
- CODE_RULES.md — Coding standards