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.
⚠️ The
user_idmust be a verified SEP-12 customer ID obtained from either the Widget Customer API or the Anchor SEP-12 flow. See Customer KYC below.
POST /api/v1/widget/session
X-API-Key: <your_api_key>
Content-Type: application/json{
"user_id": "6a3ce6751dbd5c0082a8d1b5"
}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. If the customer's KYC is not
ACCEPTED, you'll receive a403 KYC_NOT_APPROVEDerror.
Customer KYC (Verification)
Before a customer can transact (buy/sell USDC), they must pass KYC verification. SeevCash supports two flows:
| Flow | Best For | Who Handles KYC |
|---|---|---|
| Widget Customer API | Merchants who want a simple REST API | Widget handles everything |
| Anchor SEP-12 Direct | Developers familiar with Stellar anchor protocols | You interact with the anchor directly |
Both flows produce a customer ID that you use as the user_id in all subsequent API calls.
Option A: Widget Customer API (Recommended)
The simplest way to onboard customers. You send customer details to the widget API, and it handles SEP-12 registration with the anchor behind the scenes.
Step 1: Create a Customer
curl --location 'https://widget-backend.seevcash.com/api/v1/widget/customer' \
--header 'X-API-Key: sv_secret_<your_secret_key>' \
--header 'Content-Type: application/json' \
--data-raw '{
"first_name": "Patrick",
"last_name": "Oduro",
"email_address": "patrick@example.com",
"birth_date": "1990-05-15",
"address": "123 Main Street",
"city": "Accra",
"address_country_code": "GHA",
"mobile_number": "+233244123456"
}'Response (201):
{
"data": {
"id": "6a3ce6751dbd5c0082a8d1b5",
"status": "ACCEPTED"
},
"meta": {
"request_id": "ddc93e15-410e-4f68-bc99-43953f951a98",
"timestamp": "2026-06-25T08:27:33.622249018Z"
}
}| Field | Description |
|---|---|
id | The customer ID — use this as user_id in all subsequent calls |
status | ACCEPTED = ready to transact, NEEDS_INFO = more fields required, PROCESSING = under review |
Required fields:
| Field | Type | Description |
|---|---|---|
first_name | string | Customer's given name |
last_name | string | Customer's family name |
email_address | string | Valid email address |
Optional fields (improve approval speed):
| Field | Type | Example |
|---|---|---|
birth_date | string | "1990-05-15" (YYYY-MM-DD) |
address | string | "123 Main Street" |
city | string | "Accra" |
state_or_province | string | "Greater Accra" |
postal_code | string | "00233" |
address_country_code | string | "GHA" (ISO 3166-1 alpha-3) |
mobile_number | string | "+233244123456" (with country code) |
Step 2: Check Customer Status
If the status is PROCESSING or NEEDS_INFO, poll this endpoint:
curl --location 'https://widget-backend.seevcash.com/api/v1/widget/customer/6a3ce6751dbd5c0082a8d1b5' \
--header 'X-API-Key: sv_secret_<your_secret_key>'Response (200):
{
"data": {
"id": "6a3ce6751dbd5c0082a8d1b5",
"status": "ACCEPTED",
"provided_fields": {
"first_name": { "type": "string", "description": "Given or first name", "status": "ACCEPTED" },
"last_name": { "type": "string", "description": "Family or last name", "status": "ACCEPTED" },
"email_address": { "type": "string", "description": "Email address", "status": "ACCEPTED" },
"birth_date": { "type": "date", "description": "Date of birth (YYYY-MM-DD)", "status": "ACCEPTED" }
}
}
}If status is NEEDS_INFO, the response includes a fields object listing what's still required:
{
"data": {
"id": "6a3ce6751dbd5c0082a8d1b5",
"status": "NEEDS_INFO",
"fields": {
"email_address": { "type": "string", "description": "Email address" },
"last_name": { "type": "string", "description": "Family or last name" }
}
}
}To provide the missing fields, call POST /api/v1/widget/customer again with the same data plus the missing fields — the customer record will be updated (idempotent).
Step 3: Delete a Customer
If a customer requests data deletion or you need to remove them:
curl --location --request DELETE 'https://widget-backend.seevcash.com/api/v1/widget/customer/6a3ce6751dbd5c0082a8d1b5' \
--header 'X-API-Key: sv_secret_<your_secret_key>'Response (200):
{
"data": { "deleted": true }
}This removes the customer from both the SeevCash anchor and the widget database. The customer ID can no longer be used.
Step 4: Use the Customer ID
Once your customer has status: "ACCEPTED", use their ID as user_id everywhere:
# Initialize session
curl -X POST 'https://widget-backend.seevcash.com/api/v1/widget/session' \
--header 'X-API-Key: sv_secret_<your_key>' \
--header 'Content-Type: application/json' \
--data '{ "user_id": "6a3ce6751dbd5c0082a8d1b5" }'
# Create orders, interactive flows, etc. — all use the same customer IDOption B: Anchor SEP-12 Direct Flow
For developers who want direct control over the Stellar anchor's KYC protocol. You interact with the anchor at https://anchor-prod.seevcash.com using SEP-10 authentication and SEP-12 customer management.
Prerequisites
- A Stellar keypair (your merchant's keypair from registration, or any funded Stellar account)
- Understanding of SEP-10 (authentication) and SEP-12 (KYC)
Step 1: SEP-10 Authentication
Get a challenge transaction and sign it with your Stellar secret key:
# Get challenge
curl 'https://anchor-prod.seevcash.com/auth?account=GABC...YOUR_STELLAR_PUBLIC_KEY'
# Response: { "transaction": "<XDR_CHALLENGE>", "network_passphrase": "..." }
# Sign the challenge with your secret key and submit:
curl -X POST 'https://anchor-prod.seevcash.com/auth' \
--header 'Content-Type: application/json' \
--data '{ "transaction": "<SIGNED_XDR>" }'
# Response: { "token": "eyJhbG..." }The token is valid for 15 minutes.
Step 2: Create Customer (PUT /customer)
curl --location --request PUT 'https://anchor-prod.seevcash.com/customer' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <SEP-10_JWT>' \
--data-raw '{
"first_name": "Patrick",
"last_name": "Oduro",
"email_address": "patrick@example.com",
"birth_date": "1990-05-15",
"address": "123 Main Street",
"city": "Accra",
"address_country_code": "GHA",
"mobile_number": "+233244123456"
}'Response (202):
{
"id": "6a3ce6751dbd5c0082a8d1b5"
}Per SEP-12,
PUT /customeronly returns the customer ID. Query status withGET /customer.
Step 3: Check Status (GET /customer)
curl 'https://anchor-prod.seevcash.com/customer?id=6a3ce6751dbd5c0082a8d1b5' \
--header 'Authorization: Bearer <SEP-10_JWT>'Response (200):
{
"id": "6a3ce6751dbd5c0082a8d1b5",
"status": "ACCEPTED",
"provided_fields": {
"first_name": { "type": "string", "description": "Given or first name", "status": "ACCEPTED" },
"last_name": { "type": "string", "description": "Family or last name", "status": "ACCEPTED" },
"email_address": { "type": "string", "description": "Email address", "status": "ACCEPTED" }
}
}Step 4: Use the Customer ID in Widget
The customer ID from the anchor can be used directly in the widget APIs:
curl -X POST 'https://widget-backend.seevcash.com/api/v1/widget/session' \
--header 'X-API-Key: sv_secret_<your_key>' \
--header 'Content-Type: application/json' \
--data '{ "user_id": "6a3ce6751dbd5c0082a8d1b5" }'SEP-12 Customer Statuses
| Status | Meaning | Action |
|---|---|---|
ACCEPTED | KYC approved — customer can transact | ✅ Proceed |
PROCESSING | Under review by compliance | ⏳ Poll periodically |
NEEDS_INFO | Missing required information | Submit additional fields via PUT /customer |
REJECTED | KYC permanently denied | ❌ Customer cannot transact |
SEP-12 Field Statuses (per field)
| Status | Meaning |
|---|---|
ACCEPTED | Field verified and approved |
PROCESSING | Field under review |
REJECTED | Field rejected (see error for reason) |
VERIFICATION_REQUIRED | Field needs verification (e.g., OTP for phone) |
Delete Customer (SEP-12)
curl --location --request DELETE 'https://anchor-prod.seevcash.com/customer/6a3ce6751dbd5c0082a8d1b5' \
--header 'Authorization: Bearer <SEP-10_JWT>'Response (200):
{ "message": "customer deleted" }Comparing the Two Flows
| Widget Customer API | Anchor SEP-12 Direct | |
|---|---|---|
| Auth | API Key (X-API-Key) | SEP-10 JWT (Stellar keypair signing) |
| Complexity | Simple REST calls | Requires Stellar SDK & key management |
| Endpoint | widget-backend.seevcash.com | anchor-prod.seevcash.com |
| Customer ID | Same format, interchangeable | Same format, interchangeable |
| Best for | Web/mobile apps, fintech integrations | Stellar wallets, DeFi protocols |
| KYC handled by | Widget (automatic) | You (manual SEP-10 → SEP-12 flow) |
💡 Both flows produce the same customer ID format. A customer created via Option A can be queried via Option B and vice versa.
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.
Deposit & Withdraw (Interactive URLs)
After completing Customer KYC, you can initiate deposit (buy USDC) and withdraw (sell USDC) flows. There are two approaches:
| Approach | Auth | Best For |
|---|---|---|
| Widget API (recommended) | API Key (X-API-Key) | Simple server-to-server integration |
| Anchor SEP-24 Direct | SEP-10 JWT + session fields | Stellar-native wallets, full protocol control |
Both return an interactive URL that you open in an iframe or popup for the customer to complete the payment.
Option A: Widget Interactive API (Recommended)
The widget handles SEP-10 authentication, session management, and anchor communication. You just need your API keys and a verified customer ID.
Prerequisites
| Credential | How to Get | Example |
|---|---|---|
sv_secret_ key | POST /merchant/apikeys with key_type: "secret" | sv_secret_4a95a7cc... |
sv_public_ key | POST /merchant/apikeys with key_type: "public" | sv_public_61f8ac8b... |
| Customer ID | POST /widget/customer (must be ACCEPTED) | 6a3cec4b21ea9c49b5d34534 |
⚠️ The secret key goes in the
X-API-Keyheader (server-to-server). The public key goes in the request bodyapi_keyfield (used to generate the widget token).
Withdraw (Sell USDC → Receive Mobile Money)
Customer sends USDC to the anchor, receives GHS in their Mobile Money wallet.
curl --location 'https://widget-backend.seevcash.com/api/v1/widget/withdraw/interactive' \
--header 'X-API-Key: sv_secret_4a95a7cc50961ec5f0b6329c2b5aefb767a68ee3cf5b5133344a18549cad1d42' \
--header 'Content-Type: application/json' \
--data '{
"asset_code": "USDC",
"user_id": "6a3cec4b21ea9c49b5d34534",
"api_key": "sv_public_61f8ac8b75e8a55a16cdea49d2eff4392cf557b9c22df24ecca0eb07de2cdaba",
"onchain_amount": 1
}'Request fields:
| Field | Type | Required | Description |
|---|---|---|---|
asset_code | string | ✅ | Always "USDC" |
user_id | string | ✅ | SEP-12 customer ID (must be ACCEPTED) |
api_key | string | ✅ | Your public API key (sv_public_...) |
onchain_amount | number | Optional | Amount of USDC to sell. If omitted, customer enters in the interactive UI |
Response (200):
{
"data": {
"url": "https://exchange.seevcash.com/interactive?token=eyJhbG...",
"id": "05c6ce07-18c8-48f8-b7b1-e5d66b735d3d",
"type": "interactive_customer_info_needed"
},
"meta": {
"request_id": "d3fb956f-62d9-4e62-8b59-4c26e48674f6",
"timestamp": "2026-06-25T09:26:16.375369413Z"
}
}Deposit (Buy USDC with Mobile Money)
Customer pays with Mobile Money, receives USDC in their Stellar wallet.
curl --location 'https://widget-backend.seevcash.com/api/v1/widget/deposit/interactive' \
--header 'X-API-Key: sv_secret_4a95a7cc50961ec5f0b6329c2b5aefb767a68ee3cf5b5133344a18549cad1d42' \
--header 'Content-Type: application/json' \
--data '{
"asset_code": "USDC",
"user_id": "6a3cec4b21ea9c49b5d34534",
"api_key": "sv_public_f69d93fb31adcb64d9f85d823be4236048e9bdc37bca4d5950182aa6d9b619fb",
"fiat_amount": 13,
"destination_address": "GCGES3SODXJX6RYF2ATRQIA5GLWDXTEXR6QWX3JERVCDY4EIFEMFB55O"
}'Request fields:
| Field | Type | Required | Description |
|---|---|---|---|
asset_code | string | ✅ | Always "USDC" |
user_id | string | ✅ | SEP-12 customer ID (must be ACCEPTED) |
api_key | string | ✅ | Your public API key (sv_public_...) |
fiat_amount | number | Optional | Amount in GHS to spend. If omitted, customer enters in the interactive UI |
destination_address | string | Optional | Stellar address to receive USDC. If omitted, customer enters in the UI |
Response (200):
{
"data": {
"url": "https://exchange.seevcash.com/interactive?token=eyJhbG...",
"id": "fa80ebf4-b431-42ce-a255-e3680e221e09",
"type": "interactive_customer_info_needed"
},
"meta": {
"request_id": "09193866-b809-4834-a9d8-682bf44be9ac",
"timestamp": "2026-06-25T09:27:03.127272637Z"
}
}Response Fields
| Field | Description |
|---|---|
url | Interactive URL — open in iframe, popup, or redirect the customer here |
id | Transaction ID — use to track status via GET /transaction?id=... |
type | Always "interactive_customer_info_needed" |
What Happens After Getting the URL
- Open the
urlin an iframe, popup, or full-page redirect - Customer selects their Mobile Money provider (MTN, Vodafone, AirtelTigo)
- Customer enters their phone number and confirms payment
- For deposits: Customer approves the MoMo prompt → receives USDC (1–4 min)
- For withdrawals: Customer sees anchor's Stellar address + memo → sends USDC → receives GHS (1–5 min)
- You receive a webhook when the transaction completes
Option B: Anchor SEP-24 Direct Flow
For developers building Stellar-native wallets or who need full protocol control. You interact directly with the anchor at https://anchor-prod.seevcash.com.
💡 We recommend using the Stellar Wallet SDK for SEP-24 integration. It handles SEP-10 authentication, token management, and transaction tracking automatically.
Prerequisites
- A Stellar keypair (your merchant's keypair from registration)
- A widget session (
POST /api/v1/widget/session) - A verified customer ID (SEP-12
ACCEPTED)
Install the Stellar Wallet SDK
npm install @stellar/typescript-wallet-sdk @stellar/stellar-sdkComplete Flow with SDK (Recommended)
import {
Wallet,
SigningKeypair,
StellarConfiguration,
} from '@stellar/typescript-wallet-sdk';
const ANCHOR_HOME_DOMAIN = 'anchor-prod.seevcash.com';
async function initiateWithdraw(
signerSecret: string, // Your merchant's Stellar secret key
merchantId: string, // From merchant registration
sessionId: string, // From POST /widget/session
sessionToken: string, // From POST /widget/session
apiKey: string, // Your public key (sv_public_...)
userId: string, // SEP-12 customer ID (ACCEPTED)
) {
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 (SDK handles challenge signing)
const sep10 = await anchor.sep10();
const authToken = await sep10.authenticate({ accountKp });
// Step 2: SEP-24 Withdraw
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,
},
});
// url → open in iframe/popup for customer
// id → transaction ID for tracking
return { url, id, type };
}
async function initiateDeposit(
signerSecret: string,
merchantId: string,
sessionId: string,
sessionToken: string,
apiKey: string,
userId: string,
stellarAccount: string, // Customer's Stellar address to receive USDC
) {
const accountKp = SigningKeypair.fromSecret(signerSecret);
const wallet = new Wallet({
stellarConfiguration: StellarConfiguration.MainNet(),
});
const anchor = wallet.anchor({ homeDomain: ANCHOR_HOME_DOMAIN });
const sep10 = await anchor.sep10();
const authToken = await sep10.authenticate({ accountKp });
const sep24 = await anchor.sep24();
const { url, id, type } = await sep24.deposit({
assetCode: 'USDC',
authToken,
destinationAccount: stellarAccount,
extraFields: {
merchant_id: merchantId,
session_id: sessionId,
session_token: sessionToken,
api_key: apiKey,
user_id: userId,
},
});
return { url, id, type };
}Track Transaction Status with SDK
async function checkTransaction(signerSecret: string, transactionId: string) {
const accountKp = SigningKeypair.fromSecret(signerSecret);
const wallet = new Wallet({ stellarConfiguration: StellarConfiguration.MainNet() });
const anchor = wallet.anchor({ homeDomain: ANCHOR_HOME_DOMAIN });
const sep10 = await anchor.sep10();
const authToken = await sep10.authenticate({ accountKp });
const sep24 = await anchor.sep24();
const tx = await sep24.getTransactionBy({ authToken, id: transactionId });
console.log(tx.status); // "completed", "pending_user_transfer_start", etc.
return tx;
}Required extraFields
| Field | Type | Description |
|---|---|---|
merchant_id | string | Your merchant ID from registration |
session_id | string | From POST /widget/session response |
session_token | string | From POST /widget/session response |
api_key | string | Your public API key (sv_public_...) |
user_id | string | SEP-12 customer ID (must be ACCEPTED) |
⚠️ 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.
Getting Session Credentials
Before calling the anchor, create a widget session:
curl -X POST 'https://widget-backend.seevcash.com/api/v1/widget/session' \
--header 'X-API-Key: sv_secret_<your_key>' \
--header 'Content-Type: application/json' \
--data '{ "user_id": "6a3cec4b21ea9c49b5d34534" }'
# Response:
# { "data": { "session_id": "...", "session_token": "...", "merchant_id": "...", "expires_at": "..." } }Advanced: Raw HTTP Calls (without SDK)
If you can't use the SDK, here are the raw endpoints. You'll need to handle SEP-10 authentication manually.
SEP-10 Authentication
# 1. Get challenge
curl 'https://anchor-prod.seevcash.com/auth?account=<YOUR_STELLAR_PUBLIC_KEY>'
# Response: { "transaction": "<XDR_CHALLENGE>", "network_passphrase": "..." }
# 2. Sign the XDR with your secret key and submit
curl -X POST 'https://anchor-prod.seevcash.com/auth' \
--header 'Content-Type: application/json' \
--data '{ "transaction": "<SIGNED_XDR>" }'
# Response: { "token": "eyJhbG..." } (valid 15 minutes)Deposit Interactive
curl --location 'https://anchor-prod.seevcash.com/transactions/deposit/interactive' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <SEP-10_JWT>' \
--data-raw '{
"asset_code": "USDC",
"account": "GCGES3SODXJX6RYF2ATRQIA5GLWDXTEXR6QWX3JERVCDY4EIFEMFB55O",
"amount": "13",
"merchant_id": "d92e377f-2456-4186-b6a5-cbce930a6219",
"session_id": "5900c14c-a19f-49df-abbe-666cef7d5593",
"session_token": "d345545a-951d-4ebe-b7e3-d7050a120436",
"api_key": "sv_public_f69d93fb31adcb64d9f85d823be4236048e9bdc37bca4d5950182aa6d9b619fb",
"user_id": "6a3cec4b21ea9c49b5d34534"
}'Withdraw Interactive
curl --location 'https://anchor-prod.seevcash.com/transactions/withdraw/interactive' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <SEP-10_JWT>' \
--data-raw '{
"asset_code": "USDC",
"account": "GA2E5D24D2LCGVA3SVVKDP64OTN2M2NLUWRDYINB352HW35ABZ66MPVR",
"amount": "1",
"merchant_id": "d92e377f-2456-4186-b6a5-cbce930a6219",
"session_id": "e70d3556-4d6b-47fe-8d33-bacd17c9cab1",
"session_token": "cc7fad85-b9ce-48de-bdfb-89d3d87ab9fe",
"api_key": "sv_public_61f8ac8b75e8a55a16cdea49d2eff4392cf557b9c22df24ecca0eb07de2cdaba",
"user_id": "6a3cec4b21ea9c49b5d34534"
}'Request Fields (Both Endpoints)
| Field | Type | Required (Mainnet) | Description |
|---|---|---|---|
asset_code | string | ✅ | "USDC" |
account | string | Optional | Stellar public key. Defaults to JWT's account |
amount | string | Optional | Amount (fiat for deposit, USDC for withdraw) |
merchant_id | string | ✅ | Your merchant ID |
session_id | string | ✅ | From POST /widget/session |
session_token | string | ✅ | From POST /widget/session |
api_key | string | ✅ | Your public API key (sv_public_...) |
user_id | string | ✅ | SEP-12 customer ID (must be ACCEPTED) |
quote_id | string | Optional | From SEP-38 quote (for guaranteed rates) |
lang | string | Optional | Language code (default: "en") |
Response
{
"type": "interactive_customer_info_needed",
"url": "https://exchange.seevcash.com/interactive?token=eyJhbG...",
"id": "05c6ce07-18c8-48f8-b7b1-e5d66b735d3d"
}Track Transaction
curl 'https://anchor-prod.seevcash.com/transaction?id=<TRANSACTION_ID>' \
--header 'Authorization: Bearer <SEP-10_JWT>'Transaction Status Flow
Deposit: incomplete → pending_user_transfer_start → pending_anchor → pending_stellar → completed
Withdraw: incomplete → pending_user_transfer_start → pending_external → pending_payout_confirmation → completed| Status | Meaning | What's Happening |
|---|---|---|
incomplete | Interactive UI not yet completed | Customer hasn't finished the form |
pending_user_transfer_start | Waiting for customer action | Deposit: awaiting MoMo approval. Withdraw: awaiting USDC transfer |
pending_anchor | Anchor processing | Fiat received, preparing crypto delivery |
pending_stellar | Blockchain transaction submitted | USDC sent, awaiting confirmation |
pending_external | Crypto received by anchor | USDC received, initiating fiat payout |
pending_payout_confirmation | Fiat payout in progress | Mobile Money disbursement initiated |
completed | Done ✅ | Transaction finished successfully |
expired | Timed out | Customer didn't complete within window |
error | Failed | See message field for details |
Network Configuration
| Environment | Widget Backend | Anchor Domain | Network |
|---|---|---|---|
| Production | widget-backend.seevcash.com | anchor-prod.seevcash.com | Stellar Mainnet |
| Testnet | widget-backend.seevcash.com | anchor.seevcash.com | Stellar Testnet |
Comparing Widget vs Anchor Direct for Interactive Flows
| Widget API | Anchor SEP-24 (SDK) | |
|---|---|---|
| Endpoint | POST /widget/deposit/interactive | SDK: sep24.deposit() / sep24.withdraw() |
| Auth | X-API-Key: sv_secret_... | SEP-10 (SDK handles automatically) |
| Session mgmt | Automatic | Manual (create session, pass fields) |
| Language | Any (REST API) | TypeScript/JavaScript |
| When to use | Server-to-server, any language | Stellar wallet apps, JS/TS projects |
| Same interactive URL? | ✅ Yes | ✅ Yes |
| Same transaction ID? | ✅ Yes | ✅ Yes |
💡 Both approaches generate the same interactive URL pointing to
exchange.seevcash.com. The customer experience is identical regardless of which method you use.
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!)
- Create a customer via
/widget/customer(KYC verification) - Confirm customer status is
ACCEPTED - Initialize widget session with the customer ID as
user_id - Test a buy and sell flow
- Configure webhook endpoint
- Verify webhook signatures
- Switch to live API key
- Go live 🚀