Payment Widget
Everything you need to know to add crypto on/off-ramp payments to your website.
What Is SeevCash?
SeevCash lets your customers buy and sell USDC (a US dollar-pegged cryptocurrency on the Stellar blockchain) using Mobile Money — directly from your website.
- Buy USDC — Customer pays with MTN MoMo, Vodafone Cash, or AirtelTigo Money → receives USDC in their Stellar wallet
- Sell USDC — Customer sends USDC → receives GHS in their Mobile Money wallet
You don't need to handle any blockchain logic. We take care of everything.
How It Works (User Experience)
Sell USDC Flow (Withdraw → Mobile Money Payout):
- Merchant backend initializes a widget session (
POST /api/v1/widget/session) - Merchant backend authenticates with the anchor via SEP-10
- Merchant backend requests a SEP-24 withdraw interactive URL with merchant session fields
- Customer is redirected to the interactive URL in an iframe/popup
- Customer completes KYC and enters Mobile Money payout details
- Customer sends USDC to the anchor's Stellar address with the provided memo
- SeevCash receives USDC → disburses GHS to customer's MoMo (1–5 minutes)
- Merchant receives webhook notification on completion
Quick Start (5 Minutes)
Step 1: Register Your Merchant Account
curl --location 'https://widget-backend.seevcash.com/api/v1/merchant/register' \
--header 'Content-Type: application/json' \
--data-raw '{
"name": "Acme Payments",
"legal_name": "Acme Payments Ltd.",
"email": "admin@acmepay.com",
"password": "MerchantPass123!"
}'Response (201):
{
"data": {
"id": "a227bfda-6a91-4749-a360-bbbd2eeb8eff",
"name": "Acme Payments",
"legal_name": "Acme Payments Ltd.",
"email": "admin@acmepay.com",
"status": "pending",
"tier": "starter",
"fee_base_bps": 100,
"fee_markup_bps": 0,
"monthly_volume_limit": 100000,
"current_month_volume": 0,
"stellar_public_key": "GCGZIEFPQL3L3FDXCQKEY273QIVBNTWNANH6RBHXASVJ7SE423VTIUZL",
"is_test_mode": false,
"created_at": "2026-05-13T12:30:07.592877236Z",
"updated_at": "2026-05-13T12:30:07.592877236Z"
},
"meta": {
"request_id": "ffce4778-f125-4b5c-9ca7-42edfae871cb",
"timestamp": "2026-05-13T12:30:07.720850177Z"
}
}Key fields:
| Field | Meaning |
|---|---|
id | Your unique merchant ID |
status: "pending" | Becomes active after KYB verification |
tier: "starter" | Determines your volume limits |
fee_base_bps: 100 | Your base fee (100 bps = 1%) |
stellar_public_key | Auto-generated, used for blockchain auth behind the scenes |
Step 2: Log In
curl --location 'https://widget-backend.seevcash.com/api/v1/merchant/login' \
--header 'Content-Type: application/json' \
--data-raw '{
"email": "admin@acmepay.com",
"password": "MerchantPass123!"
}'Response (200):
{
"data": {
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJmMjVlM2U1Zi1lODNhLTRlYmEtOTNiOS01MDQ0ZDc2NDU2NzMiLCJleHAiOjE3Nzg3NTQxNzQsImlhdCI6MTc3ODY2Nzc3NH0..."
},
"meta": {
"request_id": "7e5b2ee9-f130-44e0-8487-c9135633fa23",
"timestamp": "2026-05-13T10:22:54.108683834Z"
}
}The
access_tokenis a JWT valid for 24 hours. Use it asAuthorization: Bearer <token>for all merchant dashboard endpoints.
Step 3: Create an API Key
curl --location 'https://widget-backend.seevcash.com/api/v1/merchant/apikeys' \
--header 'Authorization: Bearer <your_access_token>' \
--header 'Content-Type: application/json' \
--data '{
"key_type": "public",
"domains": ["http://localhost:3000", "https://myapp.example.com"]
}'Response (201):
{
"data": {
"api_key": {
"id": "e16c5b6e-2c6e-47ee-98c9-7646f0eaae2f",
"merchant_id": "f25e3e5f-e83a-4eba-93b9-5044d7645673",
"key_type": "public",
"key_prefix": "sv_public_07",
"allowed_domains": [
"http://localhost:3000",
"https://myapp.example.com"
],
"allowed_ips": [],
"permissions": ["onramp", "offramp"],
"rate_limit_rpm": 600,
"is_active": true,
"created_at": "2026-05-13T12:32:30.232150975Z"
},
"key": "sv_public_07386d7477d35f4243fc6b56a5d09aa58a244a742514b270d7ed2a646ca12f15"
},
"meta": {
"request_id": "ad1947d6-1a0d-447f-9b22-b376c5d76beb",
"timestamp": "2026-05-13T12:32:30.241750377Z"
}
}⚠️ The
keyfield is only shown once. Store it securely.
Key types:
| Type | Use For | Security |
|---|---|---|
public | Frontend widget script (data-api-key) | Domain-restricted |
secret | Server-to-server API calls | IP-restricted recommended |
API Reference
Base URL: https://widget-backend.seevcash.com
All responses are wrapped in { "data": {...}, "meta": {...} } format.
Initialize Widget Session
Creates a session for widget API calls. The widget does this automatically, but you can also call it server-side.
POST /api/v1/widget/session
X-API-Key: <your_api_key>
Content-Type: application/json{
"user_id": "your-internal-user-id"
}Response (201):
{
"data": {
"session_id": "2e72ff62-9d3e-4e54-8378-fa3c9e85bd0e",
"session_token": "0c28199e-cd8b-4ea5-8c3b-980c778944e5",
"merchant_id": "f25e3e5f-e83a-4eba-93b9-5044d7645673",
"expires_at": "2026-05-13T11:54:53.289405068Z"
}
}Sessions expire after 30 minutes.
Anchor Integration (Direct SEP-24 Flow)
For merchants who want programmatic control over the payment flow — building custom UIs, triggering withdrawals from their backend, or integrating into existing apps — you can interact directly with the SeevCash Stellar Anchor using the Stellar Wallet SDK.
Install Dependencies
npm install @stellar/typescript-wallet-sdk @stellar/stellar-sdkFull Flow: Authentication → Interactive URL
import {
Wallet,
SigningKeypair,
StellarConfiguration,
} from '@stellar/typescript-wallet-sdk';
const ANCHOR_HOME_DOMAIN = 'anchor-prod.seevcash.com';
async function getWithdrawUrl(
signerSecret: string,
merchantId: string,
sessionId: string,
sessionToken: string,
apiKey: string,
userId: string,
) {
const accountKp = SigningKeypair.fromSecret(signerSecret);
const wallet = new Wallet({
stellarConfiguration: StellarConfiguration.MainNet(),
});
const anchor = wallet.anchor({ homeDomain: ANCHOR_HOME_DOMAIN });
// Step 1: SEP-10 Authentication
const sep10 = await anchor.sep10();
const authToken = await sep10.authenticate({ accountKp });
// Step 2: SEP-24 Withdraw with merchant session
const sep24 = await anchor.sep24();
const { url, id, type } = await sep24.withdraw({
assetCode: 'USDC',
authToken,
extraFields: {
merchant_id: merchantId,
session_id: sessionId,
session_token: sessionToken,
api_key: apiKey,
user_id: userId,
},
});
return { url, id, type };
}Required extraFields (Production)
| Field | Type | Description |
|---|---|---|
merchant_id | string | Your merchant ID from registration |
session_id | string | From widget session initialization |
session_token | string | From widget session initialization |
api_key | string | Your public API key |
user_id | string | Your internal user identifier |
⚠️ All fields are required on mainnet. Requests without them return
400 Bad Request. On testnet (anchor.seevcash.com), these fields are optional for easier development.
Response
{
"type": "interactive_customer_info_needed",
"url": "https://sv-widget.api-service.live/interactive?token=<JWT>",
"id": "822c104f-c1d0-427a-885f-b7c09ebe2991"
}| Field | Description |
|---|---|
type | Always interactive_customer_info_needed |
url | Open in iframe/popup for customer to complete KYC and payment |
id | Transaction ID — use to track status |
Tracking Transaction Status
const tx = await sep24.getTransactionBy({ authToken, id: transactionId });
// Status flow: "incomplete" → "pending_user_transfer_start" → "completed"How It Works End-to-End
| Step | Who | What |
|---|---|---|
| 1 | Merchant backend | Initialize widget session → get session_id, session_token |
| 2 | Merchant backend | SEP-10 authenticate with Stellar keypair |
| 3 | Merchant backend | Call SEP-24 withdraw with extraFields |
| 4 | Merchant frontend | Open returned url in iframe/popup |
| 5 | Customer | Completes KYC + enters Mobile Money details |
| 6 | Customer | Sends USDC to anchor's Stellar address with memo |
| 7 | SeevCash | Receives USDC → disburses GHS to customer's MoMo |
| 8 | Merchant | Receives webhook notification on completion |
Network Configuration
| Environment | Domain | Network |
|---|---|---|
| Production | anchor-prod.seevcash.com | Stellar Mainnet |
| Testnet | anchor.seevcash.com | Stellar Testnet |
Get Widget Config
GET /api/v1/widget/config
X-API-Key: <your_api_key>Response (200):
{
"data": {
"merchant_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"theme": { "primary_color": "#4F46E5", "border_radius": "8px" },
"allowed_coins": ["USDC"],
"redirect_url": "https://mystore.com/payment-complete"
}
}Update Widget Config
PUT /api/v1/merchant/widget-config
Authorization: Bearer <access_token>
Content-Type: application/json{
"theme": { "primary_color": "#10B981", "border_radius": "12px" },
"allowed_coins": ["USDC"],
"redirect_url": "https://mystore.com/thank-you"
}List Merchant Orders
GET /api/v1/merchant/orders?limit=20&cursor=
Authorization: Bearer <access_token>Response (200):
{
"data": [
{
"id": "ord_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "completed",
"fiat_currency": "GHS",
"fiat_amount": 100.0,
"crypto_currency": "USDC",
"crypto_amount": 6.45,
"payment_method": "mobile_money",
"created_at": "2026-05-13T10:30:00Z"
}
],
"next_cursor": "ord_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"has_more": false
}Other Merchant Dashboard Endpoints
| Endpoint | Method | Description |
|---|---|---|
/api/v1/merchant/profile | GET | View your merchant profile |
/api/v1/merchant/apikeys/:id | DELETE | Revoke an API key |
/api/v1/merchant/kyb/submit | POST | Submit KYB (Know Your Business) documents |
/api/v1/merchant/kyb/status | GET | Check KYB verification status |
All require Authorization: Bearer <access_token>.
Required Headers
| Header | Used In | Description |
|---|---|---|
X-API-Key | Widget endpoints | Your merchant API key |
X-Session-Id | Session-protected endpoints | From /widget/session response |
X-Session-Token | Session-protected endpoints | From /widget/session response |
X-Idempotency-Key | Order creation | Unique UUID to prevent duplicates |
Authorization | Dashboard endpoints | Bearer <access_token> from login |
Content-Type | All POST/PUT | application/json |
Error Responses
All errors follow this format:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "fiat_amount must be greater than 0"
}
}| Code | HTTP Status | Meaning |
|---|---|---|
VALIDATION_ERROR | 400 | Request body failed validation |
MISSING_HEADER | 400 | Required header missing (e.g., X-Idempotency-Key) |
UNAUTHORIZED | 401 | Invalid or expired API key / session / token |
FORBIDDEN | 403 | Domain not in allowed list |
NOT_FOUND | 404 | Order or resource not found |
DUPLICATE_ORDER | 409 | Idempotency key already used |
PHONE_NOT_VERIFIED | 422 | Phone number hasn't been OTP-verified |
QUOTE_EXPIRED | 422 | Quote expired, request a new one |
RATE_LIMITED | 429 | Too many requests |
INTERNAL_ERROR | 500 | Something went wrong on our end |
Transaction Statuses
| Status | Meaning |
|---|---|
pending_user_transfer_start | Waiting for customer to complete payment |
pending_anchor | Fiat received, crypto delivery in progress |
pending_stellar | Crypto sent, awaiting blockchain confirmation |
pending_external | Crypto received, fiat payout initiated |
pending_payout_confirmation | Fiat payout in progress |
completed | Transaction finished successfully |
failed | Something went wrong |
expired | Customer didn't complete within the time window |
Webhooks
Configure a webhook URL in your merchant dashboard for server-side notifications.
Payload Example:
{
"event": "order.completed",
"order_id": "ord_abc123",
"type": "onramp",
"fiat_amount": "100.00",
"fiat_currency": "GHS",
"crypto_amount": "6.45",
"crypto_currency": "USDC",
"destination_address": "GABCD...XYZ",
"timestamp": "2026-05-13T10:30:00Z"
}Security Headers:
| Header | Description |
|---|---|
X-Webhook-Signature | HMAC-SHA256 signature of the payload body |
X-Webhook-Timestamp | Unix timestamp when sent |
Verify using your webhook secret (found in dashboard).
Events:
| Event | Description |
|---|---|
order.completed | Crypto delivered (onramp) or fiat paid out (offramp) |
order.failed | Payment failed or declined |
order.expired | Payment window timed out |
Retry Policy:
If your endpoint returns non-2xx, we retry:
- Immediate → 2. 10 seconds → 3. 1 minute → 4. 1 hour → 5. 4 hours
After 5 failed attempts, delivery is marked exhausted.
Supported Payment Methods
| Method | Buy | Sell | Speed |
|---|---|---|---|
| MTN Mobile Money | ✅ | ✅ | 1–4 min |
| Vodafone Cash | ✅ | ✅ | 1–4 min |
| AirtelTigo Money | ✅ | ✅ | 1–4 min |
| Bank Transfer | 🚧 | 🚧 | Coming Soon |
Supported Assets
| Asset | Network | Description |
|---|---|---|
| USDC | Stellar | US Dollar-pegged stablecoin (1 USDC ≈ $1) |
Fees
| Fee Type | Description |
|---|---|
| Platform fee | Percentage of transaction (your fee_base_bps + fee_markup_bps) |
| Network fee | Stellar transaction fee (fractions of a cent) |
| Exchange spread | Built into the quoted rate |
All fees are shown to the customer before they confirm.
Security
- All data in transit uses TLS/HTTPS
- The widget handles all sensitive payment details — nothing touches your servers
- Customer phone numbers are OTP-verified before any payment
- Idempotency keys prevent duplicate charges
- API keys can be scoped to specific domains and IP addresses
- Webhooks are HMAC-SHA256 signed for verification
API Key Best Practices
- Use
publickeys for frontend widget,secretkeys for server-to-server - Restrict keys to your allowed domains and IPs
- Never expose
secretkeys in client-side code - Use separate keys for development and production
- Rotate keys periodically
Testing
Use test mode during development:
- Stellar testnet (no real money moves)
- Mobile Money prompts are simulated
- All flows work identically to production
Switch to your live API key when ready to go live.
FAQ
Q: Do I need to understand blockchain? A: No. Add the script tag, receive webhooks. We handle everything else.
Q: What if a payment fails? A: No crypto is sent, no money deducted. Customer can retry.
Q: How fast are transactions? A: 1–4 minutes for buying, 1–5 minutes for selling.
Q: Can I customize the widget? A: Yes — theme colors, allowed coins, and redirect URLs via the widget config API.
Q: Minimum/maximum amounts? A: Configurable per merchant during onboarding.
Q: What if a customer doesn't have a Stellar wallet? A: They need one to receive USDC. Recommend Lobstr or StellarX.
Support
- Email: merchants@seevcash.com
- Dashboard: dashboard.seevcash.com
- Docs: docs.seevcash.com
Quick Start Checklist
- Register merchant account
- Log in and create API key (store it securely!)
- Add widget script to your dev site
- Test a buy and sell flow
- Configure webhook endpoint
- Verify webhook signatures
- Switch to live API key
- Go live 🚀