OpenWA 5.5 can create native WhatsApp event cards and turn attendance responses into application events. A meetup invitation can stay in the conversation while your bot tracks going, maybe and not going. Events use the common runtime patch and don't require a licence.
Choose SDK or Easy API
Use the tabs below to choose an embedded Node.js SDK or an HTTP client. SDK examples assume a ready client. For Easy API, start the server, scan its QR, and use the printed address. Set these variables in the shell that runs your examples:
export OPENWA_API_URL='http://127.0.0.1:8080'export WA_API_KEY='REPLACE_WITH_YOUR_API_KEY'npx @open-wa/wa-automate@5.5.1 \ --host 127.0.0.1 --port 8080 --api-key "$WA_API_KEY"Python examples use requests: install it with python -m pip install requests. JavaScript examples use Node.js 22.21.1 or later and its built-in fetch. Keep the API key on your application server. Method responses contain { success: true, data }; the examples read data. The API explorer at /api-docs/ lists your server's routes and inputs.
Create an invitation
With a ready client, provide a future start time in Unix seconds:
const chatId = '447700900123@c.us';const startTime = Math.floor(Date.now() / 1000) + 3600;const eventId = await client.sendEvent(chatId, { name: 'Community meetup', startTime, endTime: startTime + 3600, description: 'Join us for a chat', location: 'London', extraGuestsAllowed: true,});The name must be nonblank and the end time must be at or after the start. sendEvent returns the submitted message ID. Use onAck for later delivery and read acknowledgements.
Only the creator can change an event. editEvent(eventId, changes) preserves omitted fields; endTime: null removes the end time, while an empty description or location clears that field. cancelEvent(eventId) leaves a canceled card in history.
Track attendance
const changes = client.onEvent(event => { console.log(event.id, event.name, event.isCanceled);});const responses = client.onEventResponse(response => { console.log(response.eventId, response.senderId, response.response);});The HTTP tabs display SSE frames. Parse each data: JSON envelope: event cards are at payload.event, and RSVPs are at payload.response. Open the stream before sending invitations; reconnect after a disconnect and use history reads for reconciliation.
onEvent reports native additions and changes, including your own sends. onEventResponse reads decrypted RSVP changes. History loading can emit callbacks too, so use response IDs and timestamps to avoid repeating a follow-up when your application rehydrates history. Both listener handles have .off() for cleanup.
Use getEventResponses(eventId) for the latest explicit response per participant. The creator's implied attendance isn't invented as an RSVP. Your bot can respond to an invitation with respondToEvent(eventId, 'going'), 'notGoing' or 'maybe'; reads may report 'unknown' for an unfamiliar native value.
Read and save events
getEvents(chatId, { limit: 20 }) reads the linked Web device's synced history, newest first. Pass its nextCursor as before for the next page in that chat. Limits range from 1 to 100. getEvent(eventId) returns null when the event isn't in available history.
import { serializeWhatsAppEvent, deserializeWhatsAppEvent,} from '@open-wa/client';const event = await client.getEvent(eventId);if (event) { const json = serializeWhatsAppEvent(event); const restored = deserializeWhatsAppEvent(json); console.log(restored.name);}Easy API readers use GET /api/events/getEvent?eventId=..., GET /api/events/getEventResponses?eventId=..., or GET /api/events/get?chatId=... with X-API-Key. Encode query values with URLSearchParams or your HTTP client. The data property already contains a JSON-safe snapshot.
Event and RSVP schemas are exported by @open-wa/schema and @open-wa/client. JSON serializers validate snapshots and exclude message secrets, encryption keys and encrypted response bytes. Event times use seconds; RSVP timestamps use milliseconds.
Put a call on the calendar
This example schedules January 1, 2030 at 00:00 UTC. Replace that Unix-second time with your own future date.
await client.sendEvent(chatId, { name: 'Planning call', startTime: 1893456000, // 2030-01-01 00:00 UTC callType: 'video', // or 'voice' isScheduledCall: true,});This creates an event with a native call link. A scheduled card doesn't start a call, and creating a video link doesn't enable camera streaming in the calling preview. Our receiving-phone demonstration showed RSVP and calendar controls; it didn't confirm a Join control. If link creation fails, the API rejects before sending the event.
Read the events guide and method reference for all seven methods, listeners, routes and models. Mutations don't retry automatically; inspect history before repeating a send whose outcome is uncertain.