Back to samples
Ascend 2028 logo
Civic

Ascend 2028

Voter outreach, donations, events, and volunteering

4 min read

Note: the visuals in this demo recording have since been refreshed with sharper brand assets. The conversation flow is identical to what you'll get from a fresh clone.

What's inside

  • Browse upcoming town halls and rallies with RSVP
  • Policy positions across major issues, served as rich cards
  • Volunteer signup with role selection
  • Tiered donation flow with custom amount support
  • Polling location lookup and voting info

A political campaign chatbot that runs entirely over RCS. Voters can RSVP to upcoming events, read policy positions, sign up to volunteer, donate at fixed or custom amounts, and check their voter registration — all from inside the messages app.

This guide walks you from a fresh clone to a working campaign demo on your phone in under 10 minutes.

What you'll build

  • A Pinnacle RCS agent for voter outreach and engagement
  • Tiered donation flow with a processDonation confirmation step
  • Custom donation amount input flow
  • Event RSVP, volunteer signup, and policy position cards
  • Voter registration check inside the conversation

Prerequisites

1. Clone and install

Bash
git clone https://github.com/pinnacle-samples/Ascend-2028
cd Ascend-2028
npm install

2. Configure environment

Bash
cp .env.example .env
env
PINNACLE_API_KEY=your_pinnacle_api_key_here
PINNACLE_AGENT_ID=your_agent_id_here
PINNACLE_SIGNING_SECRET=your_signing_secret_here
TEST_MODE=false
PORT=3000

3. Expose your webhook

Bash
ngrok http 3000

4. Connect the webhook

In the Webhooks dashboard:

  1. Add https://<your-tunnel-domain>/webhook
  2. Attach it to your RCS agent
  3. Copy the signing secret into PINNACLE_SIGNING_SECRET

5. Run it

Bash
npm run dev

Send MENU or START to your agent. You'll see the Ascend 2028 landing card with Events, Policies, Donate, Volunteer, and Voting Info entry points.

How the pieces fit together

Ascend-2028/
├── server.ts              # Express bootstrap
├── router.ts              # /webhook POST — verifies + dispatches
├── lib/
│   ├── rcsClient.ts       # PinnacleClient instance
│   ├── baseAgent.ts       # Shared send + typing helpers
│   ├── typing.ts          # Fire-and-forget typing indicator
│   ├── agent.ts           # AscendAgent — every action handler
│   └── data.ts            # Events, policies, donation tiers, volunteer roles

Action handlers

ActionWhat it does
mainMenu / showMainMenuLanding card with all entry points
viewEvents / rsvpEventBrowse and RSVP to town halls and rallies
viewPoliciesPolicy positions as a card carousel
donate / processDonationTiered donation flow with confirmation
customDonationFree-form custom amount input
volunteer / signUpVolunteerVolunteer role picker and signup
votingInfo / checkRegistrationVoter info + registration check

Customize the campaign

lib/data.ts is where everything lives. Drop in your own:

  • upcomingEvents — town halls and rallies, with name, date, time, address, and capacity
  • policyPositions — issues and stances, served as rich card carousels
  • volunteerOpportunities — roles voters can sign up for
  • donationTiers — preset amounts and tier names
  • votingInfo — registration and voting deadlines for your district

Custom donations

The agent has a pendingCustomDonations set for users in the middle of a custom donation flow — they tap "Other amount", the agent waits for a number, and then processDonation confirms. The sendStrictFormatMessage helper repeats donation buttons whenever a user sends free-form text outside of that flow, keeping the conversation on rails.

Going to production

  • Set TEST_MODE=false and submit your agent for carrier approval
  • Wire donations to your real payment processor (Stripe, ActBlue, WinRed)
  • Replace the in-memory state with Postgres
  • Use proactive RCS messages for GOTV reminders, debate alerts, and event RSVPs

Compliance note

Political messaging is heavily regulated. Make sure to:

  • Honor STOP and HELP keywords (the SDK does this for you)
  • Comply with TCPA opt-in/opt-out rules
  • Add required disclosures to fundraising messages — your campaign's compliance lead will know what's required in your jurisdiction

Resources

© 2026 Pinnacle Software Development, Inc.