Which one is for you
Process Now plugin
Install, paste your Process Now key, done. The plugin opens Whitcomb’s hosted payment page at checkout, marks the order paid after a server-side check, and keeps your Whitcomb dashboard current on its own.
Process Now API
Four calls from your own server: activate once, start a payment, confirm it, and (optionally) report your orders. Your buyer pays on Whitcomb’s hosted page and comes back to your site. No card data ever touches your server.
Both run on your Process Now key — one key per business, issued by your Whitcomb desk and shown in your merchant portal under Set up. Your account takes money only once Whitcomb has approved it (or approved it for a trial); until then both the plugin and the API answer “not armed” and no card page opens.
Process Now — WooCommerce plugin
- Download the plugin from your merchant portal (Set up tab) and install it under Plugins → Add New → Upload. WordPress 5.8+, PHP 7.4+, WooCommerce (classic and block checkout).
- Activate it with your Process Now key (WooCommerce → Settings → Payments → Process Now by Whitcomb Payments). The plugin exchanges the key for your store’s brand code and store secret and keeps them in your WordPress options — the key is never typed again.
- Sell. When the account is armed, “Credit or debit card” (Whitcomb Payments — the title is yours to change) appears at checkout. The buyer is sent to Whitcomb’s payment page and returned to your order-received page; the order is marked paid only after the plugin re-checks the payment with Whitcomb server-side. A buyer who closes the tab is caught by the plugin’s five-minute sweep for a day.
- Reporting is automatic: every order (whatever it was paid with) is reported in a signed batch, the whole history is synced once at activation, and a daily heartbeat tells your desk the store is alive and what it holds. Nothing to configure.
- Updates arrive on your Plugins screen like any other plugin.
Process Now API — custom sites
Base URL https://whitcombpayments.com. Every call is JSON over HTTPS from your server — never from a browser, because your store secret must never leave your backend. The flow:
- Activate once with your Process Now key → you receive your
brandcode and yoursecret. Store both server-side. - Sign every call after that: base64url the JSON payload, HMAC-SHA256 it with the secret, send both.
- Start a payment for an order → you receive a payment page URL and a reference. Redirect the buyer there.
- Confirm the payment when the buyer comes back (and again on a timer): mark the order paid only when Whitcomb says
paid: true. - Optionally report your orders and send a heartbeat so your Whitcomb dashboard shows the whole store, not just the card payments.
Activation
Plain JSON (this is the one unsigned call). Do it once and keep the answer; do not activate on every request.
{
"k": "your Process Now key, exactly as it was given to you",
"u": "https://yourstore.com", // your site's address, shown to your desk
"sn": "Your Store", // shown to your desk
"pv": "1.0" // your integration's version, for your desk's eyes
}
200
{
"ok": true,
"merchant": "Your Business LLC",
"brand": "yourbusiness", // your brand code — goes into every signed payload as "b"
"secret": "…", // your store secret — signs every call; never leaves your server
"status": "active", // or "pending" while your application is being reviewed
"armed": true, // may this account take money right now?
"why": "", // when armed is false: the reason, in words you can show the merchant
"endpoint": "https://whitcombpayments.com/api/ingest"
}
| Status | Meaning |
|---|---|
| 404 | The key was not recognised (or the account is not switched on for Process Now). Check it with your desk. |
| 429 | Ten failed attempts from one address in fifteen minutes. Wait, then try again. |
| 503 | Activation is temporarily unavailable. Try again shortly. |
Signing a request
Every call after activation carries the same envelope. Build your payload object, add b (your brand code) and t (the current time in milliseconds since the epoch), JSON-encode it, base64url-encode that string (no padding), and sign the encoded string with HMAC-SHA256 using your secret. Send { "p": encoded, "s": signature } with Content-Type: application/json.
payload = { ...your fields, "b": brand, "t": now_ms }
p = base64url( JSON.stringify(payload) ) // '-' and '_' instead of '+' and '/', no '=' padding
s = hex( HMAC_SHA256( key = secret, message = p ) )
POST { "p": p, "s": s }
Node.js
const crypto = require('crypto');
async function whitcomb(path, fields) {
const p = Buffer.from(JSON.stringify({ ...fields, b: BRAND, t: Date.now() })).toString('base64url');
const s = crypto.createHmac('sha256', SECRET).update(p).digest('hex');
const r = await fetch('https://whitcombpayments.com' + path, {
method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ p, s })
});
return { status: r.status, body: await r.json() };
}
PHP
function whitcomb($path, array $fields) {
$fields['b'] = BRAND; $fields['t'] = (int) round(microtime(true) * 1000);
$p = rtrim(strtr(base64_encode(json_encode($fields)), '+/', '-_'), '=');
$s = hash_hmac('sha256', $p, SECRET);
$ch = curl_init('https://whitcombpayments.com' . $path);
curl_setopt_array($ch, [CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode(['p' => $p, 's' => $s])]);
$body = json_decode(curl_exec($ch), true); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
return [$code, $body];
}
Python
import base64, hashlib, hmac, json, time, requests
def whitcomb(path, fields):
payload = dict(fields, b=BRAND, t=int(time.time() * 1000))
p = base64.urlsafe_b64encode(json.dumps(payload).encode()).decode().rstrip('=')
s = hmac.new(SECRET.encode(), p.encode(), hashlib.sha256).hexdigest()
r = requests.post('https://whitcombpayments.com' + path, json={'p': p, 's': s}, timeout=25)
return r.status_code, r.json()
A request is refused when the signature does not match (401, "code":"unlinked"), when it is missing (400 Unsigned request.), or when t is more than an hour from Whitcomb’s clock (400, "code":"skew" — check your server time).
Start a payment
Call this when the buyer chooses to pay by card. You get back the address of Whitcomb’s hosted payment page for that order; redirect the buyer there. Save the reference with your order.
{
"a": "checkout",
"oid": "10442", // your order number — required, up to 40 characters
"c": 12999, // amount in CENTS (integer): $129.99 — required
"cur": "USD", // USD only
"em": "buyer@example.com", // optional — prefilled on the payment page
"fn": "Jane", "ln": "Smith", // optional
"ph": "5125550100", // optional
"ret": "https://yourstore.com/order/10442/thank-you", // where the buyer is sent after paying
"u": "https://yourstore.com" // your site — "ret" must be on this same host
}
200
{ "ok": true, "url": "https://whitcombpayments.com/pay/?t=ws_…", "reference": "ws_…" }
200 — the same order was already started and is still open at the same amount (the buyer came back):
{ "ok": true, "url": "…", "reference": "ws_…", "reused": true }
200 — the order is ALREADY PAID: no new charge; the page says "payment received" and returns the buyer:
{ "ok": true, "url": "…", "reference": "ws_…", "reused": true, "paid": true }
| Field | Rules |
|---|---|
| oid | Your order number. One order gets one charge: the same oid at the same amount reuses the open link; a paid oid is never charged again. |
| c | Whole cents, greater than zero, at most 100,000,000 ($1,000,000). Send 12999, never 129.99. |
| cur | Only USD is accepted today. |
| ret | Must be an https:// (or http://) address on the same host as u. Anything else is dropped and the buyer stays on Whitcomb’s receipt page. |
Refusals (see Errors): 403 code:"off" Process Now is not switched on for this account; 403 code:"not_armed" the account may not take money yet — the error text says why, in words for the merchant, not the buyer; 503 code:"paused" card payments are paused across the platform for the moment; 400 for a missing order number, a bad amount or a currency other than USD.
Confirm a payment
Ask Whitcomb whether a reference was paid. Call it when the buyer lands on your return page before you render the receipt, and again on a timer for orders still pending (the plugin sweeps every five minutes for 24 hours). Mark the order paid only when paid is true — never from the redirect alone.
{ "a": "status", "ref": "ws_…" }
200
{ "ok": true, "reference": "ws_…", "status": "paid", "paid": true, "amount_cents": 12999, "paid_at": "2026-09-16T14:07:31.000Z" }
// still open: "status": "open", "paid": false
// buyer cancelled: "status": "cancelled", "paid": false → cancel or leave the order unpaid
// paid on another link for the same order (rare): "status": "paid", "paid": true, "twin": true, "paid_reference": "ws_…"
404 { "error": "No such payment." }
A status call always asks the card processor for the freshest reading, so it is safe to trust and cheap to repeat. There are no webhooks to register: polling is how you learn you were paid, and it is the same method the WooCommerce plugin uses.
Heartbeat & order reporting (optional)
Ping is your “test connection” and your way of learning when the account becomes armed — a merchant approved this afternoon starts taking cards without touching anything. Send it once a day, and on demand.
{ "a": "ping", "u": "https://yourstore.com", "sn": "Your Store", "pv": "1.0", "cur": "USD", "oc": 1284 }
// oc: how many orders your store holds (optional)
200
{ "ok": true, "merchant": "Your Business LLC", "brand": "yourbusiness", "status": "active",
"armed": true, "why": "", "process_now": true, "orders_on_file": 1280, … }
Orders feed the Payments and reporting views in your merchant portal with every order your store takes, however it was paid. Send up to 250 orders per call; sending an order again updates it (its id is the key), so you can resend freely after a change or a dropped request.
{ "a": "orders", "u": "https://yourstore.com", "pv": "1.0", "oc": 1284,
"o": [ {
"id": "10442", // your permanent order id — required, the idempotency key
"no": "10442", // the number you show the customer
"st": "processing", // your order status, as text
"c": "USD",
"t": 12999, // total, cents "tx": 900 tax "sh": 599 shipping "rf": 0 refunded
"cn": "Jane Smith", "em": "buyer@example.com", "ph": "5125550100",
"ba": "1 Main St, Austin, TX 78701, US",
"pm": "whitcomb_process_now", "pt": "Credit or debit card", // payment method id and title, your own values
"tid": "ws_…", // the Whitcomb reference for a card payment
"ic": 2, "it": [ { "n": "Blue widget", "q": 2, "t": 11000 } ], // items: name, quantity, line total in cents (up to 100)
"d": 1758031651000, // placed, ms since epoch
"pd": 1758031700000 // paid, ms since epoch, or null
} ],
"bf": "done" // optional: send once, on the last batch of a full-history sync
}
200 { "ok": true, "written": 1 }
Errors
Every error is { "error": "…" } with a sensible HTTP status, and some carry a short code you can branch on. The error text on the checkout call is written to be shown to a buyer as-is if you have nothing better.
| Code | Status | What it means |
|---|---|---|
| unlinked | 401 | Wrong brand code or secret, or the account was closed. Re-activate with your key. |
| skew | 400 | Your t is more than an hour from Whitcomb’s clock. Fix your server time. |
| off | 403 | Process Now is not switched on for this account. Chat with your desk. |
| not_armed | 403 | The account is not yet allowed to take money (still in review, over its monthly limit, or paused by the desk). error says which. |
| paused | 503 | Card payments are paused platform-wide for the moment. Offer the buyer another way to pay and try again later. |
Rules of the road
- Keep the secret on your server. Sign there; never ship the secret in page source, a mobile app, or a client-side bundle. If it leaks, ask your desk to rotate it.
- Amounts are integers in cents, USD only.
- One order, one charge. Store the
referenceon the order and re-use it; a paid order is never charged twice by Whitcomb, and you should not ask twice either. - Never mark an order paid from the redirect. Only
statuswithpaid: truecounts. A buyer can bookmark your return URL. - No sandbox. Whitcomb approves accounts for a trial so you can integrate and run one real test payment on your own card; that payment ends the trial. Ask your desk for it before you start.
- Refunds are issued by your Whitcomb desk — ask from your portal’s chat with the order number and the amount; there is no refund endpoint.
- Rate limits: activation, ten tries per address per fifteen minutes; signed calls, be reasonable — one status check per order per five minutes is plenty.
- Your customer sees Whitcomb Payments on the payment page, which is titled with your order number (“Order 10442”) and nothing else about the buyer.
Stripe Express — WooCommerce plugin
Whitcomb Payments — Stripe is a WordPress payment gateway for merchants on the Stripe Express program. Buyers pay on Stripe’s hosted checkout opened on your own Stripe account: the money settles to you, your business name appears on the customer’s card statement, and Whitcomb’s account is not involved.
- Download the plugin from your merchant portal’s Set up tab (or ask us — chat with us now). Paste the publishable and secret keys from your Stripe dashboard into the plugin settings. They stay on your server and are used only to charge cards into your own account.
- Orders are marked paid only after the plugin re-checks the session with Stripe server-side — amount, currency, and order identity all have to match, so a total can never be altered in a browser. Refunds issued in WooCommerce are sent to your Stripe account automatically.
- Optional but recommended: add a Stripe webhook for
checkout.session.completedat the URL shown in the plugin settings, so orders complete even if the buyer closes the tab. - Signed reporting. With Report sales to Whitcomb switched on, the plugin sends your Whitcomb dashboard a short signed summary of each sale and a daily health check (plugin, WordPress and WooCommerce versions, and whether your Stripe account is accepting charges) — the same signed channel described under Heartbeat & orders. Your Stripe keys and your customer list are never sent.
Security model
- Card data never touches your server. Buyers enter card details on Whitcomb’s hosted payment page (Process Now) or Stripe’s certified hosted page (Stripe Express).
- Server-side verification. An order is paid only after a server-to-server check — never from a browser redirect alone.
- Signed requests. Every call after activation is HMAC-SHA256-signed with your store secret over a base64url payload with a timestamp; unsigned, forged, tampered or stale requests are refused, and “no such store” and “wrong secret” are answered with the same words so nobody can enumerate merchants.
- Return addresses are pinned to your own site. The payment page only ever sends a buyer back to the host you declared, so the checkout cannot be turned into a redirect to somewhere else.
- Your keys stay yours. On Stripe Express, Stripe keys live in your own WordPress settings and are sent only to Stripe’s API; Whitcomb never asks for or stores your Stripe secret key.
Retired: the built-in checkout (Instant Plugin)
Whitcomb’s earlier embedded checkout — the “Instant Plugin”, its plugin.js embed and the original whitcomb-payments WooCommerce gateway — was retired on August 23, 2026 and no longer accepts merchant payments. Stores that used it have been moved to Process Now or Stripe Express; if yours hasn’t been, chat with us now and we’ll switch you across — most accounts are moved the same business day.
Support
Keys, brand codes and store secrets are issued by your Whitcomb desk — there is no self-serve signup, because every account is placed and configured for the specific business. Chat with us now and give your business name; most requests turn around the same business day. Your merchant portal’s Set up tab walks the whole plugin setup end to end.
Questions: Chat with us now · (337) 242-3039 · 660 Madison Avenue, Suite 2349, New York, NY 10065.