← Back to blogpayments

SMS Payment Receipts from Helcim: A Setup Guide for High-Risk Merchants

May 26, 2026 · Android Texter

SMS Payment Receipts from Helcim: A Setup Guide for High-Risk Merchants

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

  1. The SMS receipt problem for Helcim merchants
  2. How Android Texter solves it
  3. Architecture overview
  4. Step 1 — pair an Android phone to Android Texter
  5. Step 2 — configure Helcim webhooks
  6. Step 3 — write the middleware handler
  7. Step 4 — write the receipt template
  8. Step 5 — test end-to-end
  9. Beyond receipts: failed payments, refunds, subscriptions
  10. FAQ for high-risk merchants

The SMS receipt problem for Helcim merchants

Most payment processors handle SMS receipts through one of two paths:

  1. 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.
  2. 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
SetupTwilio account + 10DLC vettingPair phone via QR
Approval timeline1-3 weeks (often rejected)Immediate
Monthly costTwilio account fees + per-msg$10/mo per phone
Per-message cost$0.0079 + carrier fees$0
Vertical restrictionsYes (SHAFT-C, payday, MLM, etc.)None
Approval for cannabisDeniedJust 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

  1. Sign up at androidtexter.com — click "Continue with Google"
  2. Dashboard → DevicesAdd Device → QR code appears
  3. Download Android Texter from androidtexter.com/download to the phone, open the app, tap QR scanner, scan
  4. Grant SMS + notification permissions
  5. 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:

  1. Settings → Integrations → Webhooks
  2. Click Add Webhook
  3. Webhook URL: placeholder for now — we'll update after deploying the Cloudflare Worker (e.g. https://helcim-sms.your-domain.workers.dev/)
  4. Events to subscribe to:
    • cardTransaction.approved — fires on successful card charges
    • cardTransaction.declined — fires on declined charges (optional; for failed-payment SMS to the customer)
    • subscription.renewed — for recurring billing receipts
    • refund.processed — for refund confirmations
  5. HTTP method: POST (Helcim default)
  6. 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:

  1. Verifies the webhook came from Helcim (HMAC signature check)
  2. Formats a customer-facing receipt SMS
  3. 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

  1. In Helcim's test mode, process a $1 sandbox transaction
  2. wrangler tail (in another terminal) — watch the Worker logs stream as the webhook fires
  3. Android Texter dashboard → Messages — the outbound SMS shows up within seconds, status going queued → sent → delivered
  4. 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 eventSMS use caseTemplate hint
cardTransaction.declinedRecovery / alternate payment request"Card declined — try another card here: [link]"
refund.processedRefund confirmation"Your $X.XX refund has been processed and will appear in 5-10 business days."
subscription.renewedRecurring billing receipt"Your monthly $X.XX subscription renewed. Manage here: [link]"
subscription.failedDunning sequence step"We couldn't renew your subscription. Update your card to keep service active: [link]"
dispute.openedInternal 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.