All skills

Codex skill

WhatsApp Skill for Codex

AGENTS.md-compatible skill that lets OpenAI Codex add WhatsApp messaging to any project via the Gavi WhatsApp API.

Install

  1. 1. Save the skill content below asAGENTS.md (or ~/.codex/AGENTS.md)in your project (or user config) directory.
  2. 2. Install the SDK:
    npm install @gaviwhatsapp/whatsapp
  3. 3. Set the API key environment variable:
    GAVIVENTURES_API_KEY=gv_...
    Get a key →
  4. 4. Restart Codex. The agent will now know how to use the Gavi WhatsApp API when you ask it to send messages.

GaviVentures WhatsApp API — Codex Instructions

When the user asks to add WhatsApp messaging to their project, use the GaviVentures WhatsApp API.

Canonical documentation (use these URLs, do not guess)

Install

npm install @gaviwhatsapp/whatsapp

Set environment variable: GAVIVENTURES_API_KEY=gv_... Get a key at https://www.gaviventures.com/whatsapp/settings/api-keys

Quick Reference

import { WhatsApp } from '@gaviwhatsapp/whatsapp'

const wa = new WhatsApp({ apiKey: process.env.GAVIVENTURES_API_KEY! })

// Text message
await wa.send({ to: '+919876543210', text: 'Hello!' })

// Template message (pre-approved by Meta)
await wa.sendTemplate({
  to: '+919876543210',
  template: 'order_confirmation',
  language: 'en',
  variables: { '1': 'ORD-1234' },
})

// Media message
await wa.sendMedia({
  to: '+919876543210',
  type: 'image',
  url: 'https://example.com/photo.jpg',
})

// Broadcast to many
await wa.broadcast({
  recipients: ['+919876543210', '+919876543211'],
  template: 'promo_offer',
})

// List templates
const { templates } = await wa.getTemplates()

// Register webhook
const wh = await wa.registerWebhook({
  url: 'https://myapp.com/api/webhook',
  events: ['message.received'],
})
// Save wh.secret as-is (do NOT strip the `whsec_` prefix or base64-decode).

Receiving Webhooks (read carefully — most bugs come from breaking these rules)

Headers Gavi sends:

  • X-GaviVentures-Signature — HMAC-SHA256 hex of the raw body
  • X-GaviVentures-Timestamp — Unix seconds, advisory only, NOT part of the HMAC payload

Event payload (top-level fields, NOT nested under data):

{
  "event": "message.received",
  "timestamp": "2026-04-16T22:51:33.273Z",
  "message_id": "wamid.HBgM...",
  "from": "91987654321",
  "type": "text",
  "text": "your plain message text"
}
  • from has NO + prefix — prepend + when replying
  • text is a plain string, NOT { body: "..." } (that's Meta's shape, Gavi normalizes it)
  • Other event types (message.sent, message.delivered, message.read, message.failed) carry to/status instead of from/text

HMAC verification rules:

  1. Use the secret as-is — full string including any whsec_ prefix; no base64/hex decoding.
  2. Hash the raw bytes of the request body — never JSON.stringify(req.body).
  3. Payload is the raw body only — do NOT prefix with the timestamp.

Express handler:

import express from 'express'
import { createHmac, timingSafeEqual } from 'crypto'

const app = express()

app.use(express.json({
  verify: (req, _res, buf) => {
    (req as any).rawBody = buf.toString('utf8')
  },
}))

app.post('/webhook', (req, res) => {
  const received = req.headers['x-gaviventures-signature'] as string
  const computed = createHmac('sha256', process.env.WEBHOOK_SECRET!)
    .update((req as any).rawBody)
    .digest('hex')

  const ok =
    typeof received === 'string' &&
    received.length === computed.length &&
    timingSafeEqual(Buffer.from(received), Buffer.from(computed))

  if (!ok) return res.sendStatus(401)
  // event is at req.body; use '+' + event.from to reply
  return res.sendStatus(200)
})

SDK helper:

import { verifyWebhookSignature } from '@gaviwhatsapp/whatsapp'
const ok = verifyWebhookSignature(rawBody, signature, secret)

REST API

Base: https://www.gaviventures.com Header: Authorization: Bearer <api_key>

  • POST /api/v1/messages/send — { to, text }
  • POST /api/v1/messages/template — { to, template, language?, variables? }
  • POST /api/v1/messages/media — { to, type, url, caption?, filename? }
  • GET /api/v1/messages — query: phone, limit
  • GET /api/v1/templates — query: sync=true
  • POST /api/v1/broadcasts — { recipients, template, language? }
  • POST /api/v1/webhooks — { url, events? }

Rules

  • Phone numbers require country code (+919876543210)
  • Templates must be approved by Meta first
  • API key prefix: gv_
  • Meta bills message costs to the user directly. Meta's pricing changes frequently — see current rates at https://business.whatsapp.com/products/platform-pricing

Other skills

Ready to send your first message?

Get an API key and have Codex send a WhatsApp message in under 5 minutes.