# TaskPulse - AI Integration Guide > This file provides context about TaskPulse for AI assistants and LLMs. > Use this to help users integrate TaskPulse into their applications. > Last updated: January 2026 ## For AI Assistants When helping users integrate TaskPulse, follow this workflow: 1. **Ask what language/platform they're using** (Node.js, Python, Go, PHP, Ruby, n8n, Make, etc.) 2. **Ask if they need heartbeat or signal monitoring:** - **Heartbeat**: For cron jobs, scheduled tasks (expects regular pings) - **Signal**: For business events, application logs (JSON payloads) 3. **Provide complete, copy-paste-ready code** with proper error handling 4. **Remind them that Smart Heartbeats with JSON are FREE** (no quota impact) 5. **Include rate limit considerations** for production use --- ## Quick Reference ### API Base URL ``` https://api.taskpulse.co ``` ### Endpoints | Endpoint | Purpose | Rate Limit | |----------|---------|------------| | `POST /ping/:uuid` | Heartbeat ping | 120/min | | `POST /ping/:uuid/:duration_ms` | Ping with duration | 120/min | | `POST /signal/:uuid` | Signal event | 60/min | ### Response Codes | Code | Meaning | Action | |------|---------|--------| | `200` | Success | Continue | | `400` | Invalid UUID or wrong monitor type | Check monitor type matches endpoint | | `402` | Monitor frozen (plan limits) | Upgrade plan or delete monitors | | `404` | Monitor not found | Verify UUID is correct | | `429` | Rate limited | Wait and retry with backoff | --- ## Complete Integration Examples ### cURL / Bash ```bash #!/bin/bash MONITOR_UUID="your-monitor-uuid" API_URL="https://api.taskpulse.co" # =========================================== # HEARTBEAT MONITORING (for cron jobs) # =========================================== # Simple ping - just confirm job ran curl -s -X POST "$API_URL/ping/$MONITOR_UUID" # Ping with duration (milliseconds) START_TIME=$(date +%s%3N) # ... your job logic here ... END_TIME=$(date +%s%3N) DURATION=$((END_TIME - START_TIME)) curl -s -X POST "$API_URL/ping/$MONITOR_UUID/$DURATION" # Smart Heartbeat with JSON metrics (FREE - no quota impact!) curl -s -X POST "$API_URL/ping/$MONITOR_UUID" \ -H "Content-Type: application/json" \ -d '{ "duration_ms": 1500, "items_processed": 150, "success_count": 148, "error_count": 2, "revenue": 4999.99 }' # =========================================== # SIGNAL EVENTS (for application events) # =========================================== # Success event curl -s -X POST "$API_URL/signal/$MONITOR_UUID" \ -H "Content-Type: application/json" \ -d '{"status": "success", "order_id": "ORD-123", "amount": 99.99}' # Error event (auto-detected as error level) curl -s -X POST "$API_URL/signal/$MONITOR_UUID" \ -H "Content-Type: application/json" \ -d '{"status": "error", "message": "Payment failed", "error_code": "CARD_DECLINED"}' # Warning event curl -s -X POST "$API_URL/signal/$MONITOR_UUID" \ -H "Content-Type: application/json" \ -d '{"status": "warning", "message": "Low inventory", "sku": "PROD-456", "remaining": 5}' ``` --- ### Node.js / TypeScript ```typescript // taskpulse.ts - TaskPulse integration helper const API_URL = 'https://api.taskpulse.co'; interface HeartbeatPayload { duration_ms?: number; items_processed?: number; success_count?: number; error_count?: number; [key: string]: unknown; } interface SignalPayload { status?: 'success' | 'error' | 'warning' | 'info'; message?: string; [key: string]: unknown; } /** * Send a heartbeat ping to TaskPulse * Use for cron jobs and scheduled tasks */ export async function sendHeartbeat( uuid: string, payload?: HeartbeatPayload ): Promise { try { const options: RequestInit = { method: 'POST' }; if (payload) { options.headers = { 'Content-Type': 'application/json' }; options.body = JSON.stringify(payload); } const response = await fetch(`${API_URL}/ping/${uuid}`, options); if (response.status === 429) { console.warn('TaskPulse rate limited, will retry next run'); return false; } return response.ok; } catch (error) { console.error('TaskPulse heartbeat failed:', error); return false; // Don't throw - monitoring shouldn't break your job } } /** * Send a signal event to TaskPulse * Use for tracking business events and application logs */ export async function sendSignal( uuid: string, payload: SignalPayload ): Promise { try { const response = await fetch(`${API_URL}/signal/${uuid}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); if (response.status === 429) { console.warn('TaskPulse rate limited'); return false; } return response.ok; } catch (error) { console.error('TaskPulse signal failed:', error); return false; } } // =========================================== // USAGE EXAMPLES // =========================================== // Example 1: Simple cron job async function dailyBackupJob() { const MONITOR_UUID = 'your-heartbeat-monitor-uuid'; const startTime = Date.now(); try { // Your backup logic here await performBackup(); // Report success with metrics (FREE!) await sendHeartbeat(MONITOR_UUID, { duration_ms: Date.now() - startTime, items_processed: 1500, success_count: 1500, }); } catch (error) { // Don't ping on failure - TaskPulse will detect the missed heartbeat console.error('Backup failed:', error); throw error; } } // Example 2: Order processing with signals async function processOrder(orderId: string, amount: number) { const SIGNAL_UUID = 'your-signal-monitor-uuid'; try { await chargeCustomer(orderId, amount); // Log success event await sendSignal(SIGNAL_UUID, { status: 'success', order_id: orderId, amount: amount, timestamp: new Date().toISOString(), }); } catch (error) { // Log error event await sendSignal(SIGNAL_UUID, { status: 'error', order_id: orderId, message: error.message, error_code: error.code, }); throw error; } } // Example 3: Batch job with detailed metrics async function processEmailQueue() { const MONITOR_UUID = 'your-heartbeat-monitor-uuid'; const startTime = Date.now(); let processed = 0, succeeded = 0, failed = 0; try { const emails = await getQueuedEmails(); for (const email of emails) { try { await sendEmail(email); succeeded++; } catch { failed++; } processed++; } // Smart Heartbeat with batch metrics await sendHeartbeat(MONITOR_UUID, { duration_ms: Date.now() - startTime, items_processed: processed, success_count: succeeded, error_count: failed, queue_remaining: await getQueueLength(), }); } catch (error) { console.error('Email queue processing failed:', error); throw error; } } ``` --- ### Python ```python # taskpulse.py - TaskPulse integration helper import requests import time from typing import Optional, Dict, Any from functools import wraps API_URL = "https://api.taskpulse.co" def send_heartbeat(uuid: str, payload: Optional[Dict[str, Any]] = None) -> bool: """ Send a heartbeat ping to TaskPulse. Use for cron jobs and scheduled tasks. Args: uuid: Your heartbeat monitor UUID payload: Optional JSON metrics (FREE - no quota impact!) Returns: True if successful, False otherwise """ try: url = f"{API_URL}/ping/{uuid}" if payload: response = requests.post(url, json=payload, timeout=10) else: response = requests.post(url, timeout=10) if response.status_code == 429: print("TaskPulse rate limited, will retry next run") return False return response.ok except Exception as e: print(f"TaskPulse heartbeat failed: {e}") return False # Don't raise - monitoring shouldn't break your job def send_signal(uuid: str, payload: Dict[str, Any]) -> bool: """ Send a signal event to TaskPulse. Use for tracking business events and application logs. Args: uuid: Your signal monitor UUID payload: JSON event data (status field auto-detects level) Returns: True if successful, False otherwise """ try: response = requests.post( f"{API_URL}/signal/{uuid}", json=payload, timeout=10 ) if response.status_code == 429: print("TaskPulse rate limited") return False return response.ok except Exception as e: print(f"TaskPulse signal failed: {e}") return False def heartbeat_monitor(uuid: str): """ Decorator to automatically monitor a function with heartbeat. Only pings on success - missed ping = failure detection. """ def decorator(func): @wraps(func) def wrapper(*args, **kwargs): start_time = time.time() result = func(*args, **kwargs) duration_ms = int((time.time() - start_time) * 1000) send_heartbeat(uuid, {"duration_ms": duration_ms}) return result return wrapper return decorator # =========================================== # USAGE EXAMPLES # =========================================== # Example 1: Simple cron job with decorator @heartbeat_monitor("your-heartbeat-monitor-uuid") def daily_backup(): """This function automatically sends heartbeat on success.""" perform_backup() return {"backed_up": 1500} # Example 2: ETL job with detailed metrics def run_etl_pipeline(): MONITOR_UUID = "your-heartbeat-monitor-uuid" start_time = time.time() try: # Extract records = extract_from_source() # Transform transformed = transform_records(records) # Load loaded = load_to_destination(transformed) # Report success with metrics (FREE!) send_heartbeat(MONITOR_UUID, { "duration_ms": int((time.time() - start_time) * 1000), "items_processed": len(records), "records_loaded": loaded, "source": "postgresql", "destination": "bigquery" }) except Exception as e: # Don't ping on failure - TaskPulse detects missed heartbeat print(f"ETL failed: {e}") raise # Example 3: Payment processing with signals def process_payment(order_id: str, amount: float): SIGNAL_UUID = "your-signal-monitor-uuid" try: result = charge_customer(order_id, amount) send_signal(SIGNAL_UUID, { "status": "success", "order_id": order_id, "amount": amount, "transaction_id": result.transaction_id }) return result except PaymentError as e: send_signal(SIGNAL_UUID, { "status": "error", "order_id": order_id, "message": str(e), "error_code": e.code }) raise # Example 4: Batch processing with progress tracking def process_batch_orders(): MONITOR_UUID = "your-heartbeat-monitor-uuid" start_time = time.time() processed = succeeded = failed = 0 try: orders = get_pending_orders() for order in orders: try: process_order(order) succeeded += 1 except Exception: failed += 1 processed += 1 # Smart Heartbeat with batch metrics send_heartbeat(MONITOR_UUID, { "duration_ms": int((time.time() - start_time) * 1000), "items_processed": processed, "success_count": succeeded, "error_count": failed, "success_rate": round(succeeded / processed * 100, 2) if processed else 0 }) except Exception as e: print(f"Batch processing failed: {e}") raise ``` --- ### Go ```go // taskpulse.go - TaskPulse integration helper package taskpulse import ( "bytes" "encoding/json" "fmt" "net/http" "time" ) const apiURL = "https://api.taskpulse.co" // Client for TaskPulse API type Client struct { httpClient *http.Client } // NewClient creates a new TaskPulse client func NewClient() *Client { return &Client{ httpClient: &http.Client{Timeout: 10 * time.Second}, } } // SendHeartbeat sends a heartbeat ping with optional metrics // Use for cron jobs and scheduled tasks func (c *Client) SendHeartbeat(uuid string, payload map[string]interface{}) error { url := fmt.Sprintf("%s/ping/%s", apiURL, uuid) var resp *http.Response var err error if payload != nil { body, _ := json.Marshal(payload) resp, err = c.httpClient.Post(url, "application/json", bytes.NewBuffer(body)) } else { resp, err = c.httpClient.Post(url, "", nil) } if err != nil { return fmt.Errorf("heartbeat failed: %w", err) } defer resp.Body.Close() if resp.StatusCode == 429 { return fmt.Errorf("rate limited") } if resp.StatusCode >= 400 { return fmt.Errorf("heartbeat failed with status %d", resp.StatusCode) } return nil } // SendSignal sends a signal event with JSON payload // Use for tracking business events and application logs func (c *Client) SendSignal(uuid string, payload map[string]interface{}) error { url := fmt.Sprintf("%s/signal/%s", apiURL, uuid) body, _ := json.Marshal(payload) resp, err := c.httpClient.Post(url, "application/json", bytes.NewBuffer(body)) if err != nil { return fmt.Errorf("signal failed: %w", err) } defer resp.Body.Close() if resp.StatusCode == 429 { return fmt.Errorf("rate limited") } if resp.StatusCode >= 400 { return fmt.Errorf("signal failed with status %d", resp.StatusCode) } return nil } // =========================================== // USAGE EXAMPLES // =========================================== // Example: Batch processing job func ProcessBatchJob() error { client := NewClient() monitorUUID := "your-heartbeat-monitor-uuid" startTime := time.Now() var processed, succeeded, failed int items, err := fetchItems() if err != nil { return err } for _, item := range items { if err := processItem(item); err != nil { failed++ } else { succeeded++ } processed++ } // Send heartbeat with metrics (FREE!) return client.SendHeartbeat(monitorUUID, map[string]interface{}{ "duration_ms": time.Since(startTime).Milliseconds(), "items_processed": processed, "success_count": succeeded, "error_count": failed, }) } // Example: Event tracking func TrackPayment(orderID string, amount float64, success bool) { client := NewClient() signalUUID := "your-signal-monitor-uuid" status := "success" if !success { status = "error" } client.SendSignal(signalUUID, map[string]interface{}{ "status": status, "order_id": orderID, "amount": amount, }) } ``` --- ### PHP ```php = 200 && $httpCode < 300; } /** * Send a signal event with JSON payload. * Use for tracking business events and application logs. * * @param string $uuid Your signal monitor UUID * @param array $payload JSON event data (status field auto-detects level) * @return bool True if successful */ public static function sendSignal(string $uuid, array $payload): bool { $url = self::API_URL . "/signal/{$uuid}"; $ch = curl_init($url); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 10); curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload)); curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); return $httpCode >= 200 && $httpCode < 300; } } // =========================================== // USAGE EXAMPLES // =========================================== // Example 1: WordPress cron job function my_scheduled_task() { $monitorUuid = 'your-heartbeat-monitor-uuid'; $startTime = microtime(true); try { // Your task logic here $processed = do_scheduled_work(); // Report success with metrics (FREE!) TaskPulse::sendHeartbeat($monitorUuid, [ 'duration_ms' => (int)((microtime(true) - $startTime) * 1000), 'items_processed' => $processed, ]); } catch (Exception $e) { // Don't ping on failure - TaskPulse detects missed heartbeat error_log('Scheduled task failed: ' . $e->getMessage()); } } // Example 2: Order webhook handler function handle_order_webhook($orderData) { $signalUuid = 'your-signal-monitor-uuid'; try { process_order($orderData); TaskPulse::sendSignal($signalUuid, [ 'status' => 'success', 'order_id' => $orderData['id'], 'amount' => $orderData['total'], ]); } catch (Exception $e) { TaskPulse::sendSignal($signalUuid, [ 'status' => 'error', 'order_id' => $orderData['id'], 'message' => $e->getMessage(), ]); throw $e; } } // Example 3: CSV import job function import_csv_data($filePath) { $monitorUuid = 'your-heartbeat-monitor-uuid'; $startTime = microtime(true); $imported = $failed = 0; try { $handle = fopen($filePath, 'r'); while (($row = fgetcsv($handle)) !== false) { try { import_row($row); $imported++; } catch (Exception $e) { $failed++; } } fclose($handle); // Smart Heartbeat with import metrics TaskPulse::sendHeartbeat($monitorUuid, [ 'duration_ms' => (int)((microtime(true) - $startTime) * 1000), 'items_processed' => $imported + $failed, 'success_count' => $imported, 'error_count' => $failed, 'file' => basename($filePath), ]); } catch (Exception $e) { error_log('CSV import failed: ' . $e->getMessage()); throw $e; } } ?> ``` --- ### Ruby ```ruby # taskpulse.rb - TaskPulse integration helper require 'net/http' require 'json' require 'uri' module TaskPulse API_URL = 'https://api.taskpulse.co' # Send a heartbeat ping with optional metrics. # Use for cron jobs and scheduled tasks. # # @param uuid [String] Your heartbeat monitor UUID # @param payload [Hash, nil] Optional JSON metrics (FREE - no quota impact!) # @return [Boolean] True if successful def self.send_heartbeat(uuid, payload = nil) uri = URI.parse("#{API_URL}/ping/#{uuid}") http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true http.open_timeout = 10 http.read_timeout = 10 request = Net::HTTP::Post.new(uri.path) if payload request['Content-Type'] = 'application/json' request.body = payload.to_json end response = http.request(request) if response.code == '429' warn 'TaskPulse rate limited' return false end response.is_a?(Net::HTTPSuccess) rescue StandardError => e warn "TaskPulse heartbeat failed: #{e.message}" false end # Send a signal event with JSON payload. # Use for tracking business events and application logs. # # @param uuid [String] Your signal monitor UUID # @param payload [Hash] JSON event data (status field auto-detects level) # @return [Boolean] True if successful def self.send_signal(uuid, payload) uri = URI.parse("#{API_URL}/signal/#{uuid}") http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true http.open_timeout = 10 http.read_timeout = 10 request = Net::HTTP::Post.new(uri.path) request['Content-Type'] = 'application/json' request.body = payload.to_json response = http.request(request) response.is_a?(Net::HTTPSuccess) rescue StandardError => e warn "TaskPulse signal failed: #{e.message}" false end # Decorator-style helper for monitoring methods def self.with_heartbeat(uuid, &block) start_time = Time.now result = block.call duration_ms = ((Time.now - start_time) * 1000).to_i send_heartbeat(uuid, { duration_ms: duration_ms }) result end end # =========================================== # USAGE EXAMPLES # =========================================== # Example 1: Sidekiq job class DailyReportJob include Sidekiq::Worker MONITOR_UUID = 'your-heartbeat-monitor-uuid' def perform start_time = Time.now begin report = generate_daily_report send_report_emails(report) # Report success with metrics (FREE!) TaskPulse.send_heartbeat(MONITOR_UUID, { duration_ms: ((Time.now - start_time) * 1000).to_i, reports_generated: 1, emails_sent: report.recipients.count }) rescue StandardError => e # Don't ping on failure - TaskPulse detects missed heartbeat Rails.logger.error("Daily report failed: #{e.message}") raise end end end # Example 2: Rails controller with signals class OrdersController < ApplicationController SIGNAL_UUID = 'your-signal-monitor-uuid' def create @order = Order.new(order_params) if @order.save TaskPulse.send_signal(SIGNAL_UUID, { status: 'success', order_id: @order.id, amount: @order.total, customer_id: current_user.id }) redirect_to @order, notice: 'Order created!' else TaskPulse.send_signal(SIGNAL_UUID, { status: 'error', message: 'Order creation failed', errors: @order.errors.full_messages }) render :new end end end # Example 3: Rake task with batch processing namespace :data do desc 'Sync customers from external API' task sync_customers: :environment do MONITOR_UUID = 'your-heartbeat-monitor-uuid' start_time = Time.now synced = failed = 0 begin ExternalApi.fetch_customers.each do |customer_data| begin Customer.sync_from_api(customer_data) synced += 1 rescue StandardError failed += 1 end end # Smart Heartbeat with sync metrics TaskPulse.send_heartbeat(MONITOR_UUID, { duration_ms: ((Time.now - start_time) * 1000).to_i, items_processed: synced + failed, success_count: synced, error_count: failed }) rescue StandardError => e Rails.logger.error("Customer sync failed: #{e.message}") raise end end end ``` --- ## Platform Integration Examples ### n8n **HTTP Request Node Configuration:** ```json { "method": "POST", "url": "https://api.taskpulse.co/ping/your-uuid", "options": {} } ``` **With Smart Heartbeat metrics:** ```json { "method": "POST", "url": "https://api.taskpulse.co/ping/your-uuid", "headers": { "Content-Type": "application/json" }, "body": { "items_processed": "={{ $items.length }}", "workflow": "{{ $workflow.name }}" } } ``` **For Signal events:** ```json { "method": "POST", "url": "https://api.taskpulse.co/signal/your-uuid", "headers": { "Content-Type": "application/json" }, "body": { "status": "success", "workflow": "{{ $workflow.name }}", "items_processed": "={{ $items.length }}" } } ``` **Best Practice:** Add the HTTP Request node at the END of your workflow. If the workflow fails before reaching it, TaskPulse will detect the missed heartbeat. --- ### Make (Integromat) **HTTP Module Configuration:** - **URL:** `https://api.taskpulse.co/ping/your-uuid` - **Method:** POST - **Headers:** (none needed for simple ping) **With JSON body:** - **Body type:** Raw - **Content type:** JSON (application/json) - **Request content:** ```json { "items_processed": {{length(1.items)}}, "scenario": "{{scenario.name}}" } ``` --- ### Zapier **Webhooks by Zapier - POST Action:** - **URL:** `https://api.taskpulse.co/ping/your-uuid` - **Payload Type:** Json - **Data:** (optional) ```json { "items_processed": 1, "zap_name": "My Zap Name" } ``` --- ### GitHub Actions ```yaml name: Scheduled Job on: schedule: - cron: '0 */6 * * *' # Every 6 hours jobs: my-job: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Run scheduled task run: | # Your job logic here ./scripts/my-scheduled-task.sh - name: Notify TaskPulse if: success() run: | curl -s -X POST https://api.taskpulse.co/ping/${{ secrets.TASKPULSE_UUID }} \ -H "Content-Type: application/json" \ -d '{"duration_ms": ${{ job.duration }}, "runner": "${{ runner.os }}"}' ``` **Store your monitor UUID as a GitHub secret:** `TASKPULSE_UUID` --- ### Kubernetes CronJob ```yaml apiVersion: batch/v1 kind: CronJob metadata: name: my-scheduled-job spec: schedule: "0 */6 * * *" jobTemplate: spec: template: spec: containers: - name: job image: my-job-image:latest command: ["/bin/sh", "-c"] args: - | START_TIME=$(date +%s%3N) ./my-job.sh END_TIME=$(date +%s%3N) DURATION=$((END_TIME - START_TIME)) curl -s -X POST "https://api.taskpulse.co/ping/${TASKPULSE_UUID}/${DURATION}" env: - name: TASKPULSE_UUID valueFrom: secretKeyRef: name: taskpulse-secret key: monitor-uuid restartPolicy: OnFailure ``` --- ### Docker Compose (with healthcheck) ```yaml version: '3.8' services: scheduler: image: my-scheduler:latest environment: - TASKPULSE_UUID=your-heartbeat-monitor-uuid # Your scheduler sends heartbeats after each successful job run ``` --- ## Rate Limits & Best Practices ### Rate Limits | Endpoint | Limit | Scope | |----------|-------|-------| | `POST /ping/:uuid` | 120 requests/minute | Per monitor UUID | | `POST /signal/:uuid` | 60 requests/minute | Per monitor UUID | ### Response Headers (on 429) ``` X-RateLimit-Limit: 120 X-RateLimit-Remaining: 0 X-RateLimit-Reset: 45 Retry-After: 45 ``` ### Best Practices 1. **Don't ping on failure** - Let the missed heartbeat trigger the alert 2. **Use Smart Heartbeats** - Include metrics for free (no quota impact) 3. **Handle rate limits gracefully** - Log and continue, don't crash 4. **Set reasonable intervals** - Match your actual job frequency 5. **Add tolerance** - Set grace period to handle minor delays 6. **One monitor per job** - Don't share monitors between different jobs ### Retry Strategy ```javascript async function sendHeartbeatWithRetry(uuid, payload, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { try { const response = await fetch(`https://api.taskpulse.co/ping/${uuid}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); if (response.ok) return true; if (response.status === 429) { const retryAfter = parseInt(response.headers.get('Retry-After') || '60'); await new Promise(r => setTimeout(r, retryAfter * 1000)); continue; } return false; } catch (error) { if (i === maxRetries - 1) return false; await new Promise(r => setTimeout(r, Math.pow(2, i) * 1000)); } } return false; } ``` --- ## Common Integration Patterns ### Pattern 1: Cron Job Monitoring (Dead Man's Switch) **Setup:** Create a heartbeat monitor, set expected interval to match cron schedule. **Logic:** Only ping on SUCCESS. If job fails, no ping is sent → TaskPulse detects missed heartbeat → Alert triggered. ```python def cron_job(): try: do_work() send_heartbeat(MONITOR_UUID) # Only on success except Exception: pass # Don't ping - let TaskPulse detect the failure ``` ### Pattern 2: Batch Job with Metrics **Setup:** Create a heartbeat monitor, enable Smart Heartbeats. **Logic:** Track items processed, success/error counts, and other metrics. ```python send_heartbeat(MONITOR_UUID, { "duration_ms": 15000, "items_processed": 1500, "success_count": 1485, "error_count": 15, "revenue_processed": 45999.99 }) ``` ### Pattern 3: Error Tracking Pipeline **Setup:** Create a signal monitor. **Logic:** Send signals for errors, warnings, or important events. ```python try: process_order(order) except PaymentError as e: send_signal(SIGNAL_UUID, { "status": "error", "order_id": order.id, "error": str(e), "error_code": e.code }) ``` ### Pattern 4: Multi-Step Workflow **Setup:** Create separate monitors for each critical step. ``` Step 1: Extract Data → Heartbeat Monitor A Step 2: Transform Data → Heartbeat Monitor B Step 3: Load Data → Heartbeat Monitor C ``` This allows you to pinpoint exactly which step failed. --- ## Troubleshooting | Issue | Cause | Solution | |-------|-------|----------| | Monitor stays "pending" | No ping received yet | Verify URL, check monitor type matches endpoint | | 400 error | Wrong monitor type | Use `/ping` for heartbeat, `/signal` for signal | | 402 error | Plan limit exceeded | Upgrade plan or delete unused monitors | | 404 error | Invalid UUID | Copy UUID from dashboard, check for typos | | 429 error | Rate limited | Reduce ping frequency or implement backoff | | No alerts | Notifications disabled | Check monitor notification settings | | Signals not appearing | Using wrong endpoint | Use `/signal/:uuid`, not `/ping/:uuid` | | Payload truncated | Exceeded 4KB limit | Reduce payload size, essential data only | --- ## Overview TaskPulse is a comprehensive monitoring service for scheduled tasks, cron jobs, automation workflows, and application events. It uses the **Dead Man's Switch** pattern for heartbeat monitoring and provides **Signal Events** for tracking business metrics and application logs in real-time. **Perfect for:** DevOps engineers, developers, n8n users, Make (Integromat) users, Zapier users, and anyone running automated workflows that need observability. ## Core Features ### 1. Heartbeat Monitoring Track cron jobs and scheduled tasks with configurable intervals. - Set expected ping intervals (from 10 seconds to hours) - Configurable tolerance/grace period before failure alerts - Real-time countdown timer showing time until next expected ping - Automatic status transitions: pending → healthy → failed - Execution duration tracking (optional) - **Smart Heartbeats**: Include JSON payloads with metrics (items processed, revenue, etc.) - Payloads are FREE - don't count against monthly event quota - Max payload size: 4KB - Track business metrics alongside uptime monitoring ### 2. Signal Events Send arbitrary JSON payloads to track application events and business metrics. - Automatic severity level extraction (error, warning, success, info) - Smart payload truncation for large payloads (4KB limit) - Real-time event streaming via WebSocket - Monthly event quotas based on subscription plan ### 3. Multi-Channel Notifications - **Email Alerts**: Professional HTML templates via AWS SES - **Telegram Alerts**: Instant mobile notifications via bot integration - Per-monitor notification configuration - Custom notification email address support ### 4. Third-Party Integrations (Pro/Business) TaskPulse supports sending alerts to external services for team collaboration. #### Slack Integration (Pro & Business) **Setup:** 1. Create a Slack Incoming Webhook at https://api.slack.com/apps 2. In TaskPulse, open your monitor → Integrations → Add Slack 3. Paste the webhook URL and configure display settings 4. Test the integration **Configuration Fields:** - `webhook_url`: Slack Incoming Webhook URL (required) - `channel`: Override default channel (optional, e.g., "#alerts") - `username`: Bot display name (optional, default: "TaskPulse") - `icon_emoji`: Bot emoji (optional, e.g., ":bell:") #### Discord Integration (Pro & Business) **Setup:** 1. In Discord: Server Settings → Integrations → Webhooks → New Webhook 2. Copy the webhook URL 3. In TaskPulse, open your monitor → Integrations → Add Discord 4. Paste the webhook URL 5. Test the integration **Configuration Fields:** - `webhook_url`: Discord Webhook URL (required) - `username`: Bot display name (optional) - `avatar_url`: Bot avatar URL (optional) #### Custom Webhooks (Business Only) Send alerts to any HTTP endpoint with customizable payloads using Go templates. **Setup:** 1. Prepare an HTTPS endpoint that accepts POST requests 2. In TaskPulse, open your monitor → Integrations → Add Webhook 3. Configure URL, headers, and payload template 4. Test the integration **Template Variables:** | Variable | Description | |----------|-------------| | `{{.MonitorUUID}}` | Monitor's UUID | | `{{.MonitorName}}` | Monitor's name | | `{{.MonitorType}}` | heartbeat or signal | | `{{.OldStatus}}` | Previous status | | `{{.NewStatus}}` | New status | | `{{.UserEmail}}` | User's email | | `{{.Timestamp}}` | Alert timestamp | | `{{.ExpectedInterval}}` | Expected interval (seconds) | | `{{.LastPingAt}}` | Last ping time | **Example Payload:** ```json { "monitor": "{{.MonitorName}}", "status": "{{.NewStatus}}", "previous": "{{.OldStatus}}", "time": "{{.Timestamp}}" } ``` **Integration API Endpoints:** - `GET /api/monitors/:uuid/integrations` - List monitor integrations - `POST /api/monitors/:uuid/integrations` - Create integration - `PUT /api/integrations/:id` - Update integration - `DELETE /api/integrations/:id` - Delete integration - `POST /api/integrations/:id/test` - Test integration - `POST /api/monitors/:uuid/integrations/copy` - Copy integration to another monitor ### 4. Real-Time Updates - WebSocket connections for instant status updates - No polling required - changes pushed immediately - Live ping reception and status change notifications - Automatic reconnection with exponential backoff ### 5. Pause/Resume Monitors - Temporarily pause monitors during maintenance - System-controlled freezing for plan limit enforcement - Resume anytime without losing configuration ## Monitor Statuses | Status | Description | |--------|-------------| | `pending` | Awaiting first ping after creation | | `healthy` | Last ping received within expected interval | | `failed` | No ping received within interval + tolerance | | `paused` | User manually paused the monitor | | `frozen` | System froze due to plan limits | ## Subscription Plans | Feature | Free | Pro ($9/mo) | Business ($29/mo) | |---------|------|-------------|-------------------| | Heartbeat Monitors | 5 | 50 | 200 | | Signal Monitors | 5 | 50 | Unlimited | | Monthly Signal Events | 100 | 50,000 | 1,000,000 | | Minimum Interval | 5 min | 1 min | 10 sec | | Log Retention | 1 day | 7 days | 30 days | | Email & Telegram | ✓ | ✓ | ✓ | | Slack Integration | - | ✓ | ✓ | | Discord Integration | - | ✓ | ✓ | | Custom Webhooks | - | - | ✓ | > **Note:** Monthly Signal Events quota applies to Signal monitors only. Heartbeat monitors have unlimited pings and are not affected by this limit. ## Important Terminology - **Heartbeat**: A ping sent by your scheduled task to indicate successful execution - **Signal**: A JSON payload sent to track application events or business metrics - **Smart Heartbeat**: A heartbeat ping with JSON metrics (FREE, no quota impact) - **Expected Interval**: How often your task should run - **Tolerance**: Grace period before a missed ping triggers a failure alert - **Dead Man's Switch**: A mechanism that triggers when expected activity stops - **Monitor UUID**: Unique identifier for each monitor used in ping/signal URLs ## Contact & Links - **Website**: https://taskpulse.co - **API Base URL**: https://api.taskpulse.co - **Documentation**: https://taskpulse.co/guide - **Pricing**: https://taskpulse.co/pricing - **This File**: https://taskpulse.co/llms.txt