Deploying SaleSprint Pay
SaleSprint Pay is the page a customer lands on when they open an invoice, statement,
receipt or quote link, and the hosted page where they pay. On the managed service it is
https://pay.salesprint.org. The source is the pay/ directory of the repository.
One deployment serves every tenant. The tenant is in the path of each link, and everything is fetched from the SaleSprint API per request. It has no database, no sessions and no cookies.
What it serves
Section titled “What it serves”| Path | What |
|---|---|
/d/{tenant}/{token} |
A customer document: invoice, statement, credit note, receipt, quote, order, delivery, refund. Print / save as PDF. |
/pay/{tenant}/{slug} |
The hosted payment page: Mobile Money (MTN, Telecel, AirtelTigo) or card through the tenant’s gateway. Polls until the payment is decided. |
/api/health |
Health probe. |
/ |
A minimal landing page. It lists nothing. |
/robots.txt |
Disallows everything. |
It is deliberately separate from the storefront (ecommerce/): billing documents belong
to every tenant, including service businesses with no shop. The storefront’s older
/document-links/{token} and /pay/{tenant}/{slug} addresses redirect to it, so links
already sent keep working.
Configure it
Section titled “Configure it”All settings are server-side environment variables.
| Variable | Required | Notes |
|---|---|---|
SALESPRINT_API_URL |
yes | Base URL of the SaleSprint API, as the pay app’s server can reach it. |
PAY_PUBLIC_URL |
no | This site’s public origin, used to build the address a payment gateway sends the customer back to. Defaults to https://pay.salesprint.org in production — set it if you host under another name. |
STOREFRONT_PROXY_KEY |
no | The same shared secret the storefront uses. With it, the API records the visitor’s IP on link views. The pages work without it. |
SALESPRINT_API_TIMEOUT_MS |
no | How long to wait for the API. Default 10000. |
PAY_MEDIA_HOSTS |
no | Comma-separated image hosts allowed by the page’s security policy. |
PAY_CHECKOUT_HOSTS |
no | Extra https:// checkout origins the page may send a card payment to. Paystack and theTeller are already allowed. |
Run it
Section titled “Run it”The directory ships a Dockerfile. The container listens on port 3000.
docker build -t salesprint-pay ./paydocker run -p 3000:3000 \ -e SALESPRINT_API_URL=https://api.example.com \ -e PAY_PUBLIC_URL=https://pay.example.com \ salesprint-payPut it behind TLS on its public hostname and point your health check at /api/health.
For local development: pnpm install, create .env.local with at least
SALESPRINT_API_URL, then pnpm dev (port 3001).
Point the API at it
Section titled “Point the API at it”The pay app only displays links. The API creates them, and needs to know where the pay app lives.
Set on the API and the scheduler (which sends reminders and statements), with the same values on both:
| Variable | What it does |
|---|---|
PAY_BASE_URL |
The pay app’s public origin, e.g. https://pay.example.com. Invoice, statement and credit-note links, every pay button and every hosted pay link are built on it. It is also the last fallback for other customer links when a tenant has no shop address. The older name PUBLIC_PORTAL_BASE_URL is still read when this is unset. |
DOCUMENT_LINK_SECRET |
The key every customer link is derived from. Rotating it invalidates every link already sent — that is the intended kill switch, so treat it as long-lived. |
With PAY_BASE_URL unset, links fall back to each tenant’s storefront address or their
Customer Portal Base Url setting, and a tenant with neither gets no link at all.
PAY_BASE_URL on the API and PAY_PUBLIC_URL on the pay app must be the same origin.
Check it works
Section titled “Check it works”- Open
/api/healthon the pay app. - In a test workspace, post a customer invoice for a customer with an email address.
- Open the link in the email. The invoice should render under the business’s name.
- If the workspace has a payment gateway, press Pay now and complete a small payment. The page should turn to Payment received on its own.