To integrate Replit with Zendesk Sunshine Conversations (formerly Smooch), create a Sunshine Conversations app in the Zendesk developer console, store your App ID, Key ID, and Key Secret in Replit Secrets (lock icon 🔒), and use the Sunshine Conversations REST API from an Express or Flask server to send and receive messages across WhatsApp, Facebook Messenger, SMS, and web chat through a unified omnichannel API.
Why Integrate Replit with Zendesk Sunshine Conversations?
Zendesk Sunshine Conversations is the messaging layer that powers multi-channel communication for the Zendesk platform. When you integrate it with Replit, you gain access to a unified API that lets you reach users on whatever channel they prefer — WhatsApp, Facebook Messenger, SMS, Apple Messages for Business, Line, Telegram, and custom web/mobile SDK channels — all through a single consistent API surface. Instead of maintaining separate integrations for each messaging platform, Sunshine Conversations abstracts the differences and handles the channel-specific protocol details.
This is an Advanced integration for three reasons. First, authentication uses JWT (JSON Web Token) signed with your Key Secret rather than a simple Bearer token — you must generate a correctly signed JWT for every API call. Second, the Sunshine Conversations data model introduces Apps, Users, Conversations, and Messages as distinct entities with relationships that must be understood to build correct API calls. Third, a production-grade webhook handler requires signature verification, idempotency handling (Sunshine Conversations retries webhooks on failure), and channel-aware message routing since different channels support different message types.
For teams already using Zendesk for customer support, Sunshine Conversations is the bridge that connects incoming messages from any channel into the Zendesk agent workspace. Your Replit backend can act as a bot layer that handles common queries automatically before escalating to a human agent, creating a hybrid automation and human support workflow.
Integration method
Replit connects to Zendesk Sunshine Conversations via its REST API using JWT authentication derived from a Key ID and Key Secret stored in Replit Secrets. Your Express or Flask server sends messages to users across multiple channels (WhatsApp, Messenger, SMS, web chat) through a single unified API, receives incoming messages and events via webhooks, and manages conversation state. This is an Advanced integration due to the JWT signing requirement, webhook verification, multi-channel routing complexity, and the need for a highly available webhook endpoint.
Prerequisites
- A Zendesk account with Sunshine Conversations enabled (Suite Professional or above, or a standalone Sunshine Conversations subscription)
- A Sunshine Conversations App created in the Zendesk developer console with an API Key generated
- A Replit account with a Node.js or Python Repl created
- Understanding of JWT (JSON Web Token) authentication and how tokens are signed
- At least one messaging channel configured in your Sunshine Conversations App (WhatsApp Business, Facebook Messenger, Twilio SMS, or web SDK)
- Familiarity with Express (Node.js) or Flask (Python) and webhook concepts
Step-by-step guide
Create a Sunshine Conversations App and generate API keys
Create a Sunshine Conversations App and generate API keys
Log in to your Zendesk account and navigate to the Sunshine Conversations section. In the Zendesk Admin Center, go to Platform > Sunshine Conversations (or access it at app.smooch.io if you have a standalone Smooch account). Create a new App or use an existing one. An App in Sunshine Conversations is the container for your messaging configuration — it holds the connected channel integrations, webhook configurations, and API keys. Once inside your App, navigate to Settings > API Keys and create a new key pair. The system will generate a Key ID (starting with 'app_') and a Key Secret (a long random string). These two values, combined with your App ID (visible in the URL when viewing your App), are the three credentials you need for authentication. Copy all three immediately — the Key Secret is only shown once. Store them in Replit Secrets as SMOOCH_APP_ID, SMOOCH_KEY_ID, and SMOOCH_KEY_SECRET. Also configure at least one messaging channel in your App (e.g., Twilio SMS or a Web Messenger) before testing — you cannot send messages without a channel configured. Note: the API base URL changed from api.smooch.io to api.smooch.io or the newer https://api.zendesk.com/sc depending on your Zendesk plan — check your dashboard for the correct API host.
1# Python — install required packages2# Run in Replit Shell:3# pip install requests pyjwt flask4# Or add to requirements.txt:5# requests>=2.28.06# PyJWT>=2.8.07# flask>=2.3.089# For Node.js:10# npm install express axios jsonwebtoken1112# Verify PyJWT is installed13try:14 import jwt15 print(f'PyJWT version: {jwt.__version__}')16except ImportError:17 print('Run: pip install PyJWT')Pro tip: Sunshine Conversations App IDs, Key IDs, and Key Secrets are separate from your Zendesk API credentials. Do not confuse them — the Sunshine Conversations API requires its own specific credentials even if you are already using the Zendesk Support API.
Expected result: A Sunshine Conversations App is created with an App ID, Key ID, and Key Secret. All three are stored in Replit Secrets. At least one messaging channel is configured in the App.
Generate JWT tokens for API authentication
Generate JWT tokens for API authentication
Sunshine Conversations uses JWT (JSON Web Token) authentication for all API calls. Unlike Bearer token auth where you include a pre-generated token, with JWT you generate a new signed token for each session or request batch. The JWT must be signed with the HS256 algorithm using your Key Secret as the signing key. The JWT payload must include the 'scope' claim set to 'app' (for app-level access to all conversations) or 'appUser' (for user-scoped access). The header must set the 'kid' claim to your Key ID so the API knows which key was used to sign the token. Tokens should include standard JWT claims: 'iat' (issued at, Unix timestamp) and optionally 'exp' (expiration, recommended to be iat + 1 hour to limit token lifetime). Build a utility function that generates a fresh JWT — call this function at the start of each API request rather than caching tokens long-term. In Python, use the PyJWT library; in Node.js, use the jsonwebtoken package. Both handle the HS256 signing algorithm. Once you have a valid JWT, include it in every API request as the Authorization header: 'Bearer YOUR_JWT'.
1// Node.js — JWT generation utility (jwt-utils.js)2const jwt = require('jsonwebtoken');34const KEY_ID = process.env.SMOOCH_KEY_ID;5const KEY_SECRET = process.env.SMOOCH_KEY_SECRET;67function generateAppToken() {8 if (!KEY_ID || !KEY_SECRET) {9 throw new Error('SMOOCH_KEY_ID and SMOOCH_KEY_SECRET must be set in Replit Secrets (lock icon 🔒)');10 }11 const payload = { scope: 'app' };12 const options = {13 header: { alg: 'HS256', typ: 'JWT', kid: KEY_ID },14 expiresIn: '1h'15 };16 return jwt.sign(payload, KEY_SECRET, options);17}1819function getAuthHeaders() {20 return { Authorization: `Bearer ${generateAppToken()}` };21}2223module.exports = { generateAppToken, getAuthHeaders };2425// Test JWT generation26try {27 const token = generateAppToken();28 console.log(`JWT generated successfully (${token.length} chars)`);29 const decoded = jwt.decode(token, { complete: true });30 console.log('Header:', JSON.stringify(decoded.header));31 console.log('Payload scope:', decoded.payload.scope);32} catch (err) {33 console.error('JWT generation failed:', err.message);34}Pro tip: Generate a fresh JWT for each API call or batch of calls within a short window. Do not cache tokens for more than 30 minutes — the API will reject expired tokens and debugging stale token issues is time-consuming.
Expected result: The JWT generation script outputs a valid token with the correct header (kid = your Key ID, alg = HS256) and payload (scope = app). No errors are thrown.
Send messages via the Sunshine Conversations API
Send messages via the Sunshine Conversations API
With JWT generation working, you can now send messages to users. The API base URL is https://api.smooch.io/v2. To send a message, you need the App ID, the Conversation ID (or User ID to start a new conversation), and the message content formatted for the target channel. The main send endpoint is POST /apps/{appId}/conversations/{conversationId}/messages. The message body varies by type: text messages use type 'text' with a text field; image messages use type 'image' with a mediaUrl; location messages use type 'location' with lat/long. Not all message types are supported on all channels — WhatsApp only accepts template messages for business-initiated conversations unless the user has messaged in the last 24 hours. To create a new conversation or find an existing user's conversation, first get or create the user via POST /apps/{appId}/users (passing an externalId that maps to your own user identifier), then list their conversations via GET /apps/{appId}/conversations?filter[userId}={userId}. Build a send function that abstracts the conversation lookup and message creation into a single call: given an externalUserId and message text, it finds or creates the conversation and posts the message.
1# Python — send messages via Sunshine Conversations (send_message.py)2import requests3import jwt4import time5import os67APP_ID = os.environ['SMOOCH_APP_ID']8KEY_ID = os.environ['SMOOCH_KEY_ID']9KEY_SECRET = os.environ['SMOOCH_KEY_SECRET']10BASE_URL = 'https://api.smooch.io/v2'1112def generate_jwt():13 payload = {'scope': 'app', 'iat': int(time.time())}14 headers_extra = {'kid': KEY_ID}15 return jwt.encode(payload, KEY_SECRET, algorithm='HS256', headers=headers_extra)1617def get_headers():18 return {'Authorization': f'Bearer {generate_jwt()}', 'Content-Type': 'application/json'}1920def get_or_create_user(external_id):21 """Get or create a Sunshine Conversations user by external ID."""22 resp = requests.post(23 f'{BASE_URL}/apps/{APP_ID}/users',24 json={'externalId': external_id},25 headers=get_headers()26 )27 return resp.json().get('user', {})2829def get_user_conversation(user_id):30 """Get the default conversation for a user."""31 resp = requests.get(32 f'{BASE_URL}/apps/{APP_ID}/conversations',33 params={'filter[userId]': user_id},34 headers=get_headers()35 )36 convos = resp.json().get('conversations', [])37 if convos:38 return convos[0]['id']39 # Create a conversation if none exists40 create_resp = requests.post(41 f'{BASE_URL}/apps/{APP_ID}/conversations',42 json={'type': 'personal', 'participants': [{'userId': user_id}]},43 headers=get_headers()44 )45 return create_resp.json().get('conversation', {}).get('id')4647def send_text_message(external_user_id, text):48 """Send a text message to a user by their external ID."""49 user = get_or_create_user(external_user_id)50 user_id = user.get('id')51 convo_id = get_user_conversation(user_id)52 payload = {53 'author': {'type': 'business'},54 'content': {'type': 'text', 'text': text}55 }56 resp = requests.post(57 f'{BASE_URL}/apps/{APP_ID}/conversations/{convo_id}/messages',58 json=payload,59 headers=get_headers()60 )61 result = resp.json()62 print(f'Message sent: {result.get("messages", [{}])[0].get("id", "unknown")}')63 return result6465# Send a test message66send_text_message('test-user-001', 'Hello from Replit! This is a test message.')Pro tip: For WhatsApp Business-initiated messages, you must use an approved message template rather than freeform text. The template must be approved by Meta before it can be sent. Test your integration with SMS or the web channel first since they have no template restrictions.
Expected result: The send function creates or retrieves the user, finds or creates a conversation, and sends a text message. The message ID is returned and the message appears in the conversation on the configured channel.
Configure and handle webhooks
Configure and handle webhooks
Webhooks are how Sunshine Conversations notifies your server of incoming messages and conversation events. To configure a webhook, make a POST request to /apps/{appId}/integrations (or use the Sunshine Conversations dashboard UI to add a webhook integration). Specify your webhook URL, the events to subscribe to (message:appUser for incoming messages, conversation:read for read receipts, etc.), and optionally a shared secret for payload verification. Sunshine Conversations will POST a JSON payload to your URL whenever a subscribed event occurs. Your webhook handler must return HTTP 200 within 5 seconds or Sunshine Conversations will retry. Implement webhook signature verification using the shared secret: Sunshine Conversations sends an X-Api-Key header with the webhook secret on each request — verify this matches your SMOOCH_WEBHOOK_SECRET before processing the payload. Your webhook handler must be idempotent since retries can deliver the same event multiple times. Deploy as Autoscale to ensure the webhook endpoint is always reachable — Sunshine Conversations will stop retrying after a configurable number of failed attempts, causing message loss.
1// Node.js — Sunshine Conversations webhook handler (webhook.js)2const express = require('express');3const crypto = require('crypto');45const app = express();67// Use raw body for signature verification8app.use(express.json());910const WEBHOOK_SECRET = process.env.SMOOCH_WEBHOOK_SECRET;11const APP_ID = process.env.SMOOCH_APP_ID;1213function verifyWebhookSignature(req) {14 if (!WEBHOOK_SECRET) return true; // Skip verification if no secret configured15 const receivedKey = req.headers['x-api-key'];16 return receivedKey === WEBHOOK_SECRET;17}1819app.post('/webhook', (req, res) => {20 // Verify webhook authenticity21 if (!verifyWebhookSignature(req)) {22 console.error('Invalid webhook signature');23 return res.status(401).json({ error: 'Invalid signature' });24 }2526 const payload = req.body;27 const appId = payload.app?.id;2829 if (appId !== APP_ID) {30 return res.status(400).json({ error: 'App ID mismatch' });31 }3233 // Always respond 200 first, then process34 res.json({ received: true });3536 const events = payload.events || [];37 for (const event of events) {38 const type = event.type;39 console.log(`Event: ${type}`);4041 if (type === 'conversation:message') {42 const msg = event.payload?.message;43 const author = event.payload?.conversation;44 if (msg?.author?.type === 'user') {45 const text = msg.content?.text || '[non-text message]';46 const channel = msg.source?.type || 'unknown';47 console.log(`Incoming [${channel}]: ${text}`);48 // Add routing logic here49 }50 }51 }52});5354app.listen(3000, '0.0.0.0', () => console.log('Sunshine Conversations webhook server running'));Pro tip: Always respond with HTTP 200 before processing webhook events asynchronously. If your processing logic throws an error after the 5-second timeout, Sunshine Conversations will retry the webhook, resulting in duplicate processing. Use a processed-event ID set to skip already-handled events.
Expected result: Incoming messages from any connected channel trigger the webhook handler. The server logs the channel type and message text, responds with 200, and is ready for routing logic.
Deploy as Autoscale and implement multi-channel routing
Deploy as Autoscale and implement multi-channel routing
For a production Sunshine Conversations integration, your Replit server must be reliably available since webhook delivery failures directly mean missed customer messages. Deploy as Autoscale: click Deploy in the Replit toolbar, select Autoscale, and set the start command. After deploying, copy the production URL from the Deployments panel and update your Sunshine Conversations webhook URL (via the API or the dashboard). Add a .replit config file with the correct port binding and deployment target. Implement channel-aware routing in your webhook handler: extract the message source type (whatsapp, messenger, sms, web, etc.) from the event payload and apply different response logic per channel. WhatsApp requires template messages for proactive notifications; SMS has 160-character limits; web channels support rich message types. Build a message router that abstracts these differences so your business logic does not need to be channel-aware. Additionally, add a simple deduplication store (a JavaScript Set or Python set in memory, or a Redis-backed store for production) to track processed message IDs and skip retried duplicates. This prevents double-processing when Sunshine Conversations retries webhook delivery.
1# Python — multi-channel message router with deduplication (router.py)2from flask import Flask, request, jsonify3import os45app = Flask(__name__)67WEBHOOK_SECRET = os.environ.get('SMOOCH_WEBHOOK_SECRET', '')8processed_ids = set() # In production, use Redis for persistence910CHANNEL_HANDLERS = {11 'whatsapp': lambda text: f'[WhatsApp template response for: {text[:50]}]',12 'sms': lambda text: text[:160], # SMS length limit13 'messenger': lambda text: text,14 'web': lambda text: text,15}1617@app.route('/webhook', methods=['POST'])18def webhook():19 # Verify webhook secret20 if WEBHOOK_SECRET and request.headers.get('x-api-key') != WEBHOOK_SECRET:21 return jsonify({'error': 'Unauthorized'}), 4012223 payload = request.get_json()24 res = jsonify({'received': True}), 200 # Respond immediately2526 events = payload.get('events', [])27 for event in events:28 event_id = event.get('id', '')29 if event_id in processed_ids:30 print(f'Skipping duplicate event: {event_id}')31 continue32 processed_ids.add(event_id)3334 if event.get('type') == 'conversation:message':35 msg = event.get('payload', {}).get('message', {})36 if msg.get('author', {}).get('type') == 'user':37 channel = msg.get('source', {}).get('type', 'unknown')38 text = msg.get('content', {}).get('text', '')39 handler = CHANNEL_HANDLERS.get(channel, lambda t: t)40 formatted = handler(text)41 print(f'[{channel}] Received: {text}')42 print(f'[{channel}] Would send: {formatted}')43 # Call send_text_message(user_id, formatted) here4445 return res4647if __name__ == '__main__':48 app.run(host='0.0.0.0', port=3000)Pro tip: In production, replace the in-memory deduplication set with a Redis store or database table with a TTL — the in-memory set is reset on every deployment and does not survive server restarts, meaning retried webhooks from before a restart will be processed twice.
Expected result: The deployed Autoscale server receives webhooks from all connected channels, deduplicates events, routes messages to channel-specific handlers, and responds reliably within the 5-second webhook timeout.
Common use cases
Omnichannel Customer Support Bot
Your Replit server receives webhook events from Sunshine Conversations whenever a customer sends a message on any connected channel (WhatsApp, Messenger, SMS). The server matches the message against a keyword-based FAQ database and sends an automated reply through the same channel. If no match is found, it creates a Zendesk ticket and notifies the support team, providing a seamless escalation path from bot to human.
Build an Express server with a POST /webhook endpoint that receives Sunshine Conversations webhook events, extracts the message text and channel type, matches against a FAQ map object keyed by keywords, and sends an automated reply via the Sunshine Conversations API. For unmatched messages, log the conversation ID for human follow-up. Store SMOOCH_APP_ID, SMOOCH_KEY_ID, SMOOCH_KEY_SECRET, and SMOOCH_WEBHOOK_SECRET in Replit Secrets.
Copy this prompt to try it in Replit
Proactive Notification System
When specific events occur in your application (order shipped, appointment reminder, subscription renewing), your Replit backend looks up the customer's preferred messaging channel from your database, creates a Sunshine Conversations message to that user on their preferred channel, and sends a formatted notification. WhatsApp users receive a template message (required for business-initiated WhatsApp), while SMS users receive plain text.
Build a Flask endpoint at /notify that accepts a JSON payload with user ID, channel type (whatsapp or sms), and notification data (event type, order number, estimated delivery). Format the message appropriately for the channel (template for WhatsApp, plain text for SMS) and send via the Sunshine Conversations API. Store app credentials in Replit Secrets.
Copy this prompt to try it in Replit
Cross-Channel Conversation Aggregator
Your customer contacts you on WhatsApp on Monday and via your website chat on Thursday. Sunshine Conversations links these into a single user profile if configured correctly. Your Replit backend queries the Conversations API to retrieve the full cross-channel history for a given user, formats it into a unified timeline, and displays it in your custom CRM — giving agents a complete picture without switching between channel-specific inboxes.
Build an Express endpoint at /customer-history/:userId that calls the Sunshine Conversations API to list all conversations for the given user, fetches messages from each conversation, merges and sorts them by timestamp, and returns a unified JSON timeline with channel source labels for each message.
Copy this prompt to try it in Replit
Troubleshooting
API returns 401 Unauthorized with 'invalid token' even though the JWT looks correct
Cause: The JWT may have an incorrect 'kid' header claim (should equal the Key ID), wrong algorithm (must be HS256), or the Key Secret used for signing does not match the Key ID. Another common cause is clock skew — if the 'iat' claim is in the future (server clock is ahead), some servers reject the token.
Solution: Verify the JWT header includes kid matching your SMOOCH_KEY_ID and alg set to 'HS256'. Use jwt.decode() without verification to inspect the generated token. Ensure you are signing with the Key Secret (not the App ID or Key ID). Sync your server clock or subtract a few seconds from the iat timestamp.
1// Debug: inspect generated JWT without verifying2const jwt = require('jsonwebtoken');3const token = generateAppToken();4const decoded = jwt.decode(token, { complete: true });5console.log('Header:', JSON.stringify(decoded.header));6console.log('Payload:', JSON.stringify(decoded.payload));Webhooks are received but the same event is processed multiple times
Cause: Sunshine Conversations retries webhook delivery if your server returns a non-200 response or times out. If your handler takes longer than 5 seconds to process, the retry triggers a duplicate delivery.
Solution: Return HTTP 200 immediately at the start of the webhook handler and process the event asynchronously. Implement event ID deduplication — store processed event IDs and skip any event whose ID is already in the processed set.
1# Respond immediately, then process2@app.route('/webhook', methods=['POST'])3def webhook():4 payload = request.get_json()5 # Return 200 FIRST6 response = jsonify({'received': True})7 # Process asynchronously (simplified - use threading.Thread in production)8 process_events(payload.get('events', []))9 return response, 200WhatsApp messages fail with 'template required' or 'outside 24-hour window' error
Cause: WhatsApp Business API requires that business-initiated messages (sent outside a 24-hour window after the last user message) use pre-approved message templates. Sending freeform text in this scenario is not permitted by WhatsApp.
Solution: Create and get approval for WhatsApp message templates in your Meta Business Manager account. When sending proactive notifications to WhatsApp users, use the template message type instead of text. Check whether the user has messaged within the last 24 hours — if so, freeform text is allowed; if not, use a template.
1// Send WhatsApp template message2const templatePayload = {3 author: { type: 'business' },4 content: {5 type: 'template',6 template: {7 name: 'order_shipped',8 language: { policy: 'deterministic', code: 'en' },9 components: [{ type: 'body', parameters: [{ type: 'text', text: orderNumber }] }]10 }11 }12};Webhook events stop arriving after the Replit Repl goes to sleep
Cause: The Repl is not deployed and went to sleep due to inactivity. Sunshine Conversations will retry failed webhook deliveries a limited number of times, after which events are dropped.
Solution: Deploy the Repl as an Autoscale deployment to get a stable always-on production URL. Update the webhook URL in Sunshine Conversations to the production deployment URL, not the development preview URL. Production Autoscale deployments remain available even when not actively processing requests.
Best practices
- Store SMOOCH_APP_ID, SMOOCH_KEY_ID, SMOOCH_KEY_SECRET, and SMOOCH_WEBHOOK_SECRET in Replit Secrets (lock icon 🔒) — never hardcode credentials or JWT signing keys
- Generate a fresh JWT for each API call or request batch — do not cache JWTs for more than 30 minutes to limit the window of exposure for a compromised token
- Return HTTP 200 from webhook handlers immediately and process events asynchronously to prevent Sunshine Conversations from triggering retries due to timeout
- Implement message ID deduplication in your webhook handler — Sunshine Conversations retries on failure, and duplicate processing can cause duplicate messages or double-counted events
- Deploy as Autoscale rather than keeping the Repl in development mode — missed webhooks due to sleeping Repls directly translate to missed customer messages
- Handle channel-specific message type restrictions in a routing layer: WhatsApp templates for proactive messages, SMS character limits, rich messages only for web/Messenger
- Verify the X-Api-Key header on all incoming webhooks against SMOOCH_WEBHOOK_SECRET to prevent unauthorized parties from injecting fake events into your webhook handler
- Use the externalId field when creating Sunshine Conversations users to map them to your own user IDs, making it easy to look up conversations for any user without storing Sunshine Conversations internal IDs
Alternatives
The full Zendesk Support API is the better choice if you primarily need ticket management and SLA tracking rather than the raw multi-channel messaging API that Sunshine Conversations provides.
Intercom provides a comparable omnichannel inbox with a simpler API setup and stronger product tour features, making it easier to integrate for teams new to omnichannel messaging.
LiveChat is a simpler real-time customer support chat tool with a more straightforward API, better suited for teams that only need web-based live chat without multi-channel complexity.
Twilio provides direct channel-specific APIs (SMS, WhatsApp, Voice) with extensive documentation — better suited if you need deep control over specific channels rather than a unified omnichannel abstraction.
Frequently asked questions
How do I connect Replit to Zendesk Sunshine Conversations?
Create a Sunshine Conversations App in the Zendesk developer console, generate an API Key (Key ID and Key Secret), store SMOOCH_APP_ID, SMOOCH_KEY_ID, and SMOOCH_KEY_SECRET in Replit Secrets (lock icon 🔒), and generate a JWT signed with HS256 for each API request. Use the JWT as a Bearer token in the Authorization header of all API calls.
Does Replit work with Sunshine Conversations for free?
Sunshine Conversations is part of Zendesk's paid platform tiers (Suite Professional and above) or available as a standalone subscription. Replit's free tier is sufficient for development and testing, but a paid Replit Autoscale deployment is necessary for production webhook servers that must be always available.
What is the difference between Smooch and Zendesk Sunshine Conversations?
Smooch was an independent company that built the omnichannel messaging API. Zendesk acquired Smooch in 2019 and rebranded it as Sunshine Conversations. The API and core architecture are the same product, just under a new brand. Older documentation and tutorials may still refer to it as Smooch, and the API domain (api.smooch.io) still works.
Why do I need to generate a JWT instead of using a simple API key?
Sunshine Conversations uses JWT authentication to allow scoped access (app-level vs user-level) and token expiry enforcement, which is more secure than long-lived API keys. The JWT is signed with your Key Secret using HS256, allowing the API to verify the token's authenticity without storing it. Use PyJWT in Python or the jsonwebtoken package in Node.js to handle JWT generation.
How do I send WhatsApp messages through Sunshine Conversations from Replit?
Connect a WhatsApp Business account to your Sunshine Conversations App, create approved message templates in Meta Business Manager for business-initiated messages (sent when the user has not contacted you in the last 24 hours), and use the template message type in your API call. Freeform WhatsApp messages are only permitted within a 24-hour window after the customer's last message.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation