Add a Pay with U.CASH button to Teachable (and any external offer pages) via the Code Snippets feature. Non-custodial: U.CASH never holds funds, and every payment settles directly to the receive addresses you control.
This package gives you a drop-in JavaScript snippet (ucashpay-button.js) that renders a styled button and opens the U.CASH hosted checkout in a new tab, plus an optional server-side helper that pre-creates a tracked, idempotent checkout for every order.
Note: Teachable's built-in course checkout is a closed, hosted flow and cannot be replaced. This integration adds a Pay-with-U.CASH button to external offer pages and standalone sales pages that you control. See the Limitations section.
| File | Purpose |
|---|---|
ucashpay-button.js |
Client-side snippet. Renders the button and builds the embed.php pay link. Safe to expose (publishable Store Cloud Token). |
teachable-snippet.html |
Ready-to-paste snippet for Settings -> Code Snippets. |
server/create-transaction.example.js |
Optional server route that creates a tracked, idempotent checkout (create-transaction) before redirecting the buyer. |
This is the simplest path and needs no server.
-
Host
ucashpay-button.jssomewhere public (your Teachable Custom Files, a CDN bucket, or a GitHub Pages URL). You can minify it first:npm run minify. -
In Teachable, go to Settings -> Code Snippets and paste the contents of
teachable-snippet.htmlinto the Inside<head>block. ReplaceUCASH_STORE_CLOUD_TOKENand theredirectthank-you URL with your own values. -
On any external offer page, add a Custom HTML block with a button:
<button data-ucashpay data-amount="49.00" data-currency="USD" data-title="Crypto Fundamentals Course" data-external-reference="teachable-course-123"> </button>
-
Save and preview the page. The Pay with U.CASH button renders and opens the hosted checkout in a new tab when clicked.
| Attribute | Required | Default | Description |
|---|---|---|---|
data-amount |
yes | - | Charge amount in the fiat currency. |
data-currency |
no | USD |
ISO 4217 currency code. |
data-title |
no | Pay with U.CASH |
Description shown on the pay page. |
data-external-reference |
no | - | Your order id. Used to match the payment to your order. |
data-redirect |
no | current page URL | Where to send the buyer after payment. |
data-cloud |
no | global config | Override the Store Cloud Token per button. |
You can also set defaults once (instead of in the Teachable snippet) via window.UCASHPAY_CONFIG = { cloud, currency, redirect, title } before the script loads.
<div data-ucashpay-slot data-amount="19.00" data-title="Coaching call"></div>Or call the API directly:
window.UCASHPAY.render('#my-button', { amount: '19.00', title: 'Coaching call' });For better order matching, create a tracked, idempotent checkout on pay.u.cash before the buyer is redirected. The response includes a payment URL you send the buyer to.
See server/create-transaction.example.js. It calls:
POST https://pay.u.cash/payment/ajax.php
Content-Type: application/x-www-form-urlencoded
function=create-transaction
&amount=49.00
¤cy_code=USD
&cryptocurrency_code=
&external_reference=teachable-course-123
&title=Crypto%20Fundamentals%20Course
&redirect=https://your-school.teachable.com/courses/thanks
&cloud=<STORE_CLOUD_TOKEN>
&idempotent=1
Response:
{ "success": true, "response": ["https://pay.u.cash/...", "transactionId", ...] }The payment URL is the array element starting with http(s)://. Because idempotent=1 is set, repeated calls with the same external_reference return the same checkout instead of creating duplicates, so retries and double-clicks are safe.
Minimal Express route sketch:
const { createUcashTransaction } = require('./server/create-transaction.example.js');
app.post('/api/ucash/create', async (req, res) => {
try {
const result = await createUcashTransaction({
cloud: process.env.UCASH_STORE_CLOUD_TOKEN,
amount: req.body.amount,
currency: req.body.currency,
externalReference: req.body.offerId,
title: req.body.title,
redirect: 'https://your-school.teachable.com/courses/thanks'
});
res.json({ url: result.paymentUrl, transactionId: result.transactionId });
} catch (e) {
res.status(500).json({ error: e.message });
}
});Then point your offer page button at GET /api/ucash/create?offerId=... and redirect to the returned url.
- Sign up at pay.u.cash, then click the verification link in the email.
- Set receive addresses under Settings -> Addresses (raw address, ENS, Unstoppable Domains, or FIO).
- Create a store under Account -> Stores and copy its Store Cloud Token (use the store-level token, not the account-wide one).
- For fiat cards, connect your own Stripe under Settings -> Payment processors.
- Teachable's built-in checkout is closed. You cannot swap the native Teachable course-purchase checkout for U.CASH. This integration is for external offer pages and standalone sales/landing pages that you control outside the Teachable checkout. On those pages, the Pay-with-U.CASH button hands the buyer to the U.CASH hosted checkout.
- No automatic recurring billing. U.CASH crypto payments are one-time, non-custodial settlements. There is no automatic on-chain subscription/recurring charge. For a membership, gate access manually per successful payment (match on
external_reference) or use a one-time purchase model. - Order fulfillment is manual. After a successful payment, use the
external_referencevalue to match the buyer to your order and grant access in Teachable. Webhook/redirect-based auto-grant is possible but is not included in this minimal snippet.
This repo ships the packaging (package.json) but is not published. If you want to distribute it on npm:
npm version 0.1.0
npm login
npm publish --access publicThe files field already limits the published tarball to the snippet, the server helper, the README, and the LICENSE.
- Non-custodial. U.CASH never holds merchant funds. Buyers pay directly to your configured receive addresses.
- Publishable token. The Store Cloud Token is safe to expose in the browser/app. It only lets payers create checkouts pointed at your store; it cannot move funds.
- Idempotent server checkouts. Use
external_referenceas your stable order key and sendidempotent=1so retries never double-create.
MIT. See LICENSE.