Integrate with one prompt.
Most developers building Deriv sites already use Claude, Cursor, Codex, Copilot, or Gemini. So we made the integration AI-first. The prompt below is codebase-agnostic— it tells the AI to scan whatever repo it's sitting in, match that repo's conventions (framework, styling, state, auth), and build the deposit + withdrawal flow to fit. It explicitly tells the AI not to assume any reference implementation, so the integration ends up shaped like the rest of your code instead of bolted on from a template.
Copy the prompt
Hit the copy button below — under 4,500 characters, terse and self-contained.
Paste into your AI
Claude Code, Cursor agent, Codex, Copilot Chat, Gemini CLI — anything that can read your repo.
Verify + plug your key
The AI tells you exactly which env var to set and walks through a real test transaction.
The prompt
Six tight sections — scan, contract, sign + call, UI, don'ts, hand-off. Designed for speed: imperative, no banner art, no nested decision trees. The AI scans your repo, locates the three Deriv inputs (loginid, userToken, appId), and asks onceif it can't find them — instead of looping or inventing a flow. It's explicitly told not to scaffold a backend, build a proxy server, or introduce new auth — just store the API key in an env var and call Deripay from the server-side surface that already exists in your stack. Full reference (status meanings, error codes, troubleshooting) lives at deripay.site/docs.
# Add Deripay payments to THIS repo
Deripay is an HMAC-signed REST gateway between M-Pesa and Deriv's
payment-agent rails. Add a Cashier modal (Deposit + Withdraw tabs) that
fits this codebase's existing patterns. Don't copy from any other repo —
read what's actually here and match it.
## 1. SCAN — find these in this repo (file paths only, no analysis):
- Deriv `loginid`, `userToken`, `appId` — where the user is authenticated
- Existing modal/dialog component (use it; don't add a new lib)
- CSS system (Tailwind / CSS modules / styled / UI kit) — match it
If the 3 Deriv inputs aren't findable, ASK. Don't invent an auth flow.
The user will store the API key in an env var (`DERIPAY_API_KEY`). You do
NOT need to design or scaffold a backend — use whatever server-side surface
this repo already has (Next route handler, server action, existing Express
endpoint, etc.) to read the env var. Don't build new infrastructure.
## 2. API CONTRACT
Base: `https://deripay.site`
Headers (every call):
- `X-API-Key: <keyId>:<secret>` ← full `DERIPAY_API_KEY`
- `X-Timestamp: <ISO-8601>` ← within ±300s
- `X-Signature: <hex>` ← HMAC-SHA256(secret, payload)
Payload to sign:
```
${ts}\n${METHOD}\n${path}\n${sha256_hex(body)}
```
Endpoints:
- `POST /api/v1/rates` → live USD/KES + limits
- `POST /api/v1/deposit` → start deposit (STK push)
- `POST /api/v1/withdrawals/initiate` → email user a verification code
- `POST /api/v1/withdrawals/confirm` → confirm with code
- `GET /api/v1/transactions/:id` → poll status
Body for deposit + withdrawals.initiate (same shape):
`{ phoneNumber, usdAmount, loginid, userToken, appId, idempotencyKey? }`
Body for withdrawals.confirm:
`{ transactionId, verificationCode }` ← code is CASE-SENSITIVE, only `.trim()`
`userToken` needs the `payments` scope for BOTH deposits and withdrawals.
Terminal statuses (stop polling): `completed | failed | cancelled`.
`deriv_processing` is NOT terminal — keep polling until `completed`.
## 3. SIGN + CALL DERIPAY (server-side only)
Read `DERIPAY_API_KEY` from env, split on `:` into `keyId` and `secret`.
Then sign and call Deripay from whatever server-side code path this repo
already has (route handler, server action, existing API endpoint).
Signing helper (TS pseudocode):
```ts
const ts = new Date().toISOString();
const bodyHash = sha256_hex(JSON.stringify(body));
const sig = hmac_sha256_hex(secret, `${ts}\n${METHOD}\n${path}\n${bodyHash}`);
```
Send the three required headers; return Deripay's JSON to your client.
Pull `loginid`, `userToken`, `appId` from the authenticated user's
session — NEVER from client-supplied form fields.
Don't scaffold a separate "proxy server", new microservice, or new auth
layer. Wire the call into the framework that's already running.
## 4. UI — CASHIER MODAL
Two tabs (Deposit / Withdraw). Place the Cashier entry in the most natural
existing surface (header user menu, sidebar, wallet widget). No floating
buttons unless this repo already uses them.
DEPOSIT
- Phone (KE format) + USD amount with min from /rates
- Live "you'll pay KES X" preview from /rates (debounce 300ms)
- Submit → backend → poll `/transaction/:id` every 5s, max 3 min
- Render terminal state (success / failed / cancelled)
WITHDRAW
- Step 1: phone + USD → "Send verification email" → backend.initiate
- Step 2: 6-digit code → "Withdraw" → backend.confirm → keep polling
- Persist `transactionId` in localStorage so a refresh resumes verify
WITHDRAW EMAIL — TWO MODES:
- Mode A (default, simpler): no Verification URL set on the Deriv app →
email contains a 6-digit code, user pastes it.
- Mode B: Verification URL set → email is a click-through link that
full-page-reloads at `?code=...&loginid=...`. Build a `/redirect` page
that stores those into localStorage (30-min TTL, single-use), then
bounces back to the cashier modal which auto-fills the code on mount.
ASK the user which mode. Default to Mode A if they don't know.
## 5. DON'TS
- ✗ `DERIPAY_API_KEY` in client code or the JS bundle. Ever.
- ✗ `userToken` in logs.
- ✗ New auth system. New design system. New state library.
- ✗ `.toLowerCase()` / `.toUpperCase()` on the verification code.
- ✗ Using `upstreamTransactionId` — always pass the LOCAL `transactionId`.
- ✗ Treating `deriv_processing` as terminal.
## 6. HAND-OFF (in chat, not a file)
- File paths you touched
- Env var: `DERIPAY_API_KEY=dpk_live_<keyId>:<secret>`
- Test plan: sign in → Cashier → Deposit 2 USD → approve STK → see ✓
- Anything you didn't tackle (be honest)
Full reference + troubleshooting: https://deripay.site/docsWhy this works better than docs alone
- Codebase-aware. The AI reads your actual files — framework, auth pattern, state management, styling — and matches them instead of generating a generic snippet.
- Token-cheap.The prompt is intentionally terse and imperative. No long phase preambles, no nested "stop and re-evaluate" gates — the AI moves through scan → contract → implement → verify in one pass instead of burning tokens deliberating.
- Forces a security model.A short Don'ts section locks the API key out of the browser, blocks logging the userToken, and bans new auth/state libraries — even if the developer doesn't fully understand why.
- Resumes correctly on the verify step. Withdrawals fail badly when the user closes the modal mid-flow, so the prompt requires
transactionIdpersistence inlocalStorageas a hard rule.
Prerequisites
- A registered Deripay developer account. Create oneif you don't have one.
- An API key issued in the portal, bound to your Deriv
app_idAND your production domain. The domain is set at key-creation time and is locked thereafter — to change domains, rotate the key. Open your dashboard. - A token-issuing path on your Deriv app that includes the
paymentsscope (DevHub-side allowed scopes for OAuth, or the Payments checkbox for manual tokens). Without it, neither deposits nor withdrawals will work — see troubleshooting.
After the AI is done
The assistant will end with a hand-off block telling you exactly which files it touched, the env var to set, and how to test a real transaction. If anything looks off:
- Spot check that
DERIPAY_API_KEYonly appears in server-side code paths (route handlers, server actions, API endpoints) and never in a client component or the bundled JS. - Run
grep -r "dpk_" src/— the full key should not appear anywhere user-facing. It belongs in your.envfile and your hosting provider's secret manager, not in source. - See the API reference for complete request/response shapes if you need to debug a specific endpoint.
Going further
Once the basic deposit/withdraw flow works, ask your AI to add webhook receivers so your backend gets notified the moment a transaction settles — no more polling. The webhook signature verification snippet is in the webhooks doc.