You picked Helcim as your payment processor for a reason: they actually approve merchants that Stripe, Square, and PayPal reject. Cannabis adjacent? Approved. High-APR lending? Approved. MLM? Often approved. "High risk" by traditional processor standards? Helcim welcomes you.
But you'll hit the same wall on the SMS side. Customers expect a text receipt when their payment clears. It builds trust, reduces chargebacks ("yes, this charge was me"), and is increasingly the default modern customer experience. Yet the major SMS providers that the rest of the world uses to send those receipts — Twilio, Bandwidth, Sinch — reject the same vertical Helcim approved you for.
There's a sideline that works: send the SMS receipt from an Android phone you already own, using Android Texter as the gateway. Helcim's webhook system fires the SMS automatically when a payment processes. No A2P 10DLC registration, no Twilio approval, no per-message charges that erode your margin.
This guide walks through the full setup. Total time: about an hour. You'll need a Helcim merchant account, an Android phone, and a free Android Texter account.
Table of contents
- The SMS receipt problem for Helcim merchants
- How Android Texter solves it
- Architecture overview
- Step 1 — pair an Android phone to Android Texter
- Step 2 — configure Helcim webhooks
- Step 3 — write the middleware handler
- Step 4 — write the receipt template
- Step 5 — test end-to-end
- Beyond receipts: failed payments, refunds, subscriptions
- FAQ for high-risk merchants
The SMS receipt problem for Helcim merchants
Most payment processors handle SMS receipts through one of two paths:
- Built-in via Twilio — Stripe, Square, PayPal all have native SMS receipt features that ride on top of Twilio. This works for merchants in their approved categories.
- DIY via Zapier or webhooks — for any payment processor with API/webhook support, you can connect to Twilio (or another SMS provider) to send receipts.
Both paths assume Twilio (or equivalent) will let you send the SMS. For Helcim merchants in industries Twilio rejects, neither works:
- Cannabis dispensaries processing card-present transactions through Helcim — Twilio rejects cannabis at A2P 10DLC registration
- High-APR consumer lenders doing loan funding payouts through Helcim — Twilio rejects payday lending
- MLM compensation processing via Helcim — Twilio rejects MLM
- Debt collection payments processed through Helcim — Twilio rejects debt collection
- Adult industry merchants — Twilio rejects SHAFT-S
You can route through cannabis-specific SMS providers or "high-risk friendly" SMS vendors, but they charge $0.02-$0.05 per message (2-5x Twilio rates) and the same carrier policies still apply upstream. One carrier policy change and your SMS provider can disconnect you with 30 days notice.
A better approach: send the SMS from a real phone you own, the same way an individual would text a friend. Carrier networks can't reject person-to-person SMS without breaking everyone's regular texting. Android Texter is the gateway that exposes this approach as an API.
How Android Texter solves it
Android Texter is a self-hosted SMS gateway running through an Android phone with an active carrier SIM. Helcim fires a webhook when a payment processes, your middleware catches the webhook, formats the receipt SMS, and posts to Android Texter's send endpoint. Android Texter forwards to the phone, the phone sends the SMS via its existing carrier connection.
Cost vs. native paths:
| Native (Twilio) | Android Texter | |
|---|---|---|
| Setup | Twilio account + 10DLC vetting | Pair phone via QR |
| Approval timeline | 1-3 weeks (often rejected) | Immediate |
| Monthly cost | Twilio account fees + per-msg | $10/mo per phone |
| Per-message cost | $0.0079 + carrier fees | $0 |
| Vertical restrictions | Yes (SHAFT-C, payday, MLM, etc.) | None |
| Approval for cannabis | Denied | Just works |
For a Helcim merchant doing 500 transactions/month with SMS receipts: Twilio costs ~$4/mo in pure delivery, Android Texter $10 flat. The break-even is at 1,250 messages/mo against Twilio's per-message rate; below that Twilio is cheaper, above that Android Texter wins. But the real value isn't pure cost — it's that for many Helcim merchants, Twilio simply isn't available.
Architecture overview
Helcim transaction.completed event
│
▼
Helcim webhook → your endpoint
│
▼
Cloudflare Worker (or AWS Lambda / Node app)
│
▼
Android Texter API (HTTPS, X-API-Key auth)
│
▼
FCM push to your paired phone
│
▼
Phone sends SMS to customer
The middleware translates Helcim's webhook payload into the SMS body your customers will receive. We'll use a Cloudflare Worker because it's free, handles spike traffic well, and deploys in 10 minutes.
Step 1 — pair an Android phone to Android Texter
- Sign up at androidtexter.com — click "Continue with Google"
- Dashboard → Devices → Add Device → QR code appears
- Download Android Texter from androidtexter.com/download to the phone, open the app, tap QR scanner, scan
- Grant SMS + notification permissions
- Dashboard shows the phone as Online within 30 seconds
Generate an API key while you're there: Settings → API Keys → Create
new key, name it helcim-webhook. Copy the atx_... string.
Step 2 — configure Helcim webhooks
In your Helcim merchant console:
- Settings → Integrations → Webhooks
- Click Add Webhook
- Webhook URL: placeholder for now — we'll update after deploying
the Cloudflare Worker (e.g.
https://helcim-sms.your-domain.workers.dev/) - Events to subscribe to:
cardTransaction.approved— fires on successful card chargescardTransaction.declined— fires on declined charges (optional; for failed-payment SMS to the customer)subscription.renewed— for recurring billing receiptsrefund.processed— for refund confirmations
- HTTP method: POST (Helcim default)
- Security: Helcim signs every webhook with HMAC-SHA256 using your secret. Copy the signing secret and save it — your middleware will use it to verify webhooks actually came from Helcim.
Helcim's webhook payload structure for cardTransaction.approved:
{
"id": "evt_abc123",
"type": "cardTransaction.approved",
"data": {
"transaction_id": "txn_xyz789",
"amount": 47.50,
"currency": "USD",
"customer": {
"id": "cus_456",
"first_name": "Jordan",
"last_name": "Lee",
"email": "[email protected]",
"phone": "+12025551234"
},
"card": {
"last_four": "4242",
"brand": "VISA"
},
"merchant_reference": "INV-1042"
},
"created_at": "2026-05-26T14:30:00Z"
}
(Exact field names may vary slightly with Helcim API version — check Helcim's webhook docs for your account. The middleware logic stays the same; only the field paths change.)
Step 3 — write the middleware handler
A complete Cloudflare Worker that:
- Verifies the webhook came from Helcim (HMAC signature check)
- Formats a customer-facing receipt SMS
- POSTs to Android Texter
// Verifies the Helcim webhook signature, then sends an SMS receipt
// via Android Texter. Set ANDROIDTEXTER_API_KEY and HELCIM_WEBHOOK_SECRET
// as Wrangler secrets.
async function verifySignature(body, signature, secret) {
const encoder = new TextEncoder();
const key = await crypto.subtle.importKey(
'raw',
encoder.encode(secret),
{ name: 'HMAC', hash: 'SHA-256' },
false,
['sign']
);
const sig = await crypto.subtle.sign('HMAC', key, encoder.encode(body));
const computed = Array.from(new Uint8Array(sig))
.map(b => b.toString(16).padStart(2, '0'))
.join('');
return computed === signature;
}
export default {
async fetch(request, env) {
// 1. Verify HMAC signature
const body = await request.text();
const signature = request.headers.get('X-Helcim-Signature');
const valid = await verifySignature(body, signature, env.HELCIM_WEBHOOK_SECRET);
if (!valid) return new Response('Unauthorized', { status: 401 });
// 2. Parse the payload
const event = JSON.parse(body);
if (event.type !== 'cardTransaction.approved') {
return new Response('Ignored', { status: 200 });
}
// 3. Build the SMS body
const { customer, amount, currency, card, merchant_reference } = event.data;
const dollars = amount.toFixed(2);
const message = `Hi ${customer.first_name}, we received your ${currency} ${dollars} payment on card ending in ${card.last_four}. Reference: ${merchant_reference}. Reply STOP to opt out.`;
// 4. Send via Android Texter
const resp = await fetch('https://androidtexter.com/api/messages/send', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': env.ANDROIDTEXTER_API_KEY,
},
body: JSON.stringify({
phone: customer.phone,
message,
}),
});
if (!resp.ok) {
console.error('AT API error:', await resp.text());
return new Response('SMS failed', { status: 502 });
}
return new Response('OK', { status: 200 });
},
};
Deploy:
npm install -g wrangler
wrangler login
wrangler init helcim-sms
# paste the code into src/index.js
wrangler secret put ANDROIDTEXTER_API_KEY # paste atx_...
wrangler secret put HELCIM_WEBHOOK_SECRET # paste from Helcim
wrangler deploy
Wrangler prints the deployed URL. Copy it back into Helcim's webhook configuration to replace the placeholder.
Step 4 — write the receipt template
A few notes on receipt SMS templates that matter for high-risk merchants specifically:
Be specific without being suggestive. Say "we received your payment" — not "your cannabis order is paid" or "your loan funding cleared." Even though the SMS rides on consumer-handset traffic that carriers can't filter, content-based spam classifiers can still flag keyword-heavy messages. Generic transactional language gets through cleanest.
Include the last four of the card. Customers cross-reference this with their email confirmation and bank notification. Builds trust, reduces "is this charge real?" support inquiries.
Include a reference number. Helcim's merchant_reference (your
invoice ID) or transaction_id makes customer-service conversations
much faster.
Include STOP. Even though strict A2P 10DLC opt-out rules don't apply to P2P SMS, modern consumers expect a STOP option and it's TCPA-safer to include it.
Template that works:
Hi Jordan, we received your USD 47.50 payment on card ending in 4242. Reference: INV-1042. Reply STOP to opt out.
Template that might get spam-flagged:
🎉💵 PAYMENT RECEIVED! $47.50 LOAN FUNDED!! Track at bit.ly/x7g3...
Step 5 — test end-to-end
- In Helcim's test mode, process a $1 sandbox transaction
wrangler tail(in another terminal) — watch the Worker logs stream as the webhook fires- Android Texter dashboard → Messages — the outbound SMS shows
up within seconds, status going
queued → sent → delivered - The test customer's phone receives the SMS
If issues:
- 401 on the Worker → HMAC verification failing. Check the secret matches what Helcim shows in your webhook config.
- 400 from Android Texter → phone number malformed. Helcim sometimes stores phones with dashes or parens. Android Texter auto-normalizes 10-digit US/Canada formats, but international formats might need pre-processing.
- Phone offline, message queued → check the Devices page. Wake the paired phone (open the app briefly) and the queue drains.
Beyond receipts: failed payments, refunds, subscriptions
Same webhook pattern, different SMS bodies:
| Helcim event | SMS use case | Template hint |
|---|---|---|
cardTransaction.declined | Recovery / alternate payment request | "Card declined — try another card here: [link]" |
refund.processed | Refund confirmation | "Your $X.XX refund has been processed and will appear in 5-10 business days." |
subscription.renewed | Recurring billing receipt | "Your monthly $X.XX subscription renewed. Manage here: [link]" |
subscription.failed | Dunning sequence step | "We couldn't renew your subscription. Update your card to keep service active: [link]" |
dispute.opened | Internal alert (your team) | "Dispute opened: $X.XX, customer X, reason: Y. Investigate within 48h." |
For high-volume merchants doing 1,000+ transactions/day, use Android Texter's Send Broadcast endpoint for end-of-day batch notifications instead of per-transaction SMS.
FAQ for high-risk merchants
Will this hold up if my industry classification changes? The phone sends person-to-person SMS via its consumer SIM. Carrier classification changes that target A2P traffic don't affect P2P traffic. The system is structurally resilient to A2P policy shifts.
What's the carrier daily limit? Consumer carriers throttle outgoing SMS to ~250-1,000 messages per 24h per number. For Helcim merchants doing more than that, pair multiple phones — Android Texter load-balances automatically across all online devices on Pro plan.
What if my customer is international? The paired phone uses its SIM's country. Phone with US SIM = US domestic SMS rates. International outbound from US carriers typically costs the same as a regular text on your plan; for high-volume international receipts, pair phones in destination countries.
Can I use this for refund confirmations + dispute responses too? Yes. Helcim fires webhooks for refund.processed, dispute.opened, dispute.closed, and most other lifecycle events. Add additional handlers in the same Worker.
What about TCPA / TCPA-FCC compliance? The TCPA governs commercial SMS based on consent, not delivery mechanism. Get explicit opt-in from your customer at sign-up or checkout for SMS communications; honor STOP requests. Android Texter doesn't add new consent vetting on top — that's the merchant's responsibility regardless of which gateway you use.
How does this compare to Klaviyo SMS, Postscript, or Attentive? Those are marketing-focused SMS platforms with strong opt-in flows and segmentation but built on Twilio. They reject the same verticals Twilio does. Use them for marketing if your industry passes; use Android Texter for transactional receipts regardless.
My Helcim account uses Helcim Pay.js (hosted checkout) — does this still work? Yes. Helcim Pay.js still fires the same backend webhooks when transactions complete. The middleware doesn't care whether the transaction was initiated via API, hosted page, or in-person terminal.
