Seev Business API

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):

  1. Merchant backend initializes a widget session (POST /api/v1/widget/session)
  2. Merchant backend authenticates with the anchor via SEP-10
  3. Merchant backend requests a SEP-24 withdraw interactive URL with merchant session fields
  4. Customer is redirected to the interactive URL in an iframe/popup
  5. Customer completes KYC and enters Mobile Money payout details
  6. Customer sends USDC to the anchor's Stellar address with the provided memo
  7. SeevCash receives USDC → disburses GHS to customer's MoMo (1–5 minutes)
  8. 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:

FieldMeaning
idYour unique merchant ID
status: "pending"Becomes active after KYB verification
tier: "starter"Determines your volume limits
fee_base_bps: 100Your base fee (100 bps = 1%)
stellar_public_keyAuto-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_token is a JWT valid for 24 hours. Use it as Authorization: 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 key field is only shown once. Store it securely.

Key types:

TypeUse ForSecurity
publicFrontend widget script (data-api-key)Domain-restricted
secretServer-to-server API callsIP-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-sdk

Full 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)

FieldTypeDescription
merchant_idstringYour merchant ID from registration
session_idstringFrom widget session initialization
session_tokenstringFrom widget session initialization
api_keystringYour public API key
user_idstringYour 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"
}
FieldDescription
typeAlways interactive_customer_info_needed
urlOpen in iframe/popup for customer to complete KYC and payment
idTransaction 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

StepWhoWhat
1Merchant backendInitialize widget session → get session_id, session_token
2Merchant backendSEP-10 authenticate with Stellar keypair
3Merchant backendCall SEP-24 withdraw with extraFields
4Merchant frontendOpen returned url in iframe/popup
5CustomerCompletes KYC + enters Mobile Money details
6CustomerSends USDC to anchor's Stellar address with memo
7SeevCashReceives USDC → disburses GHS to customer's MoMo
8MerchantReceives webhook notification on completion

Network Configuration

EnvironmentDomainNetwork
Productionanchor-prod.seevcash.comStellar Mainnet
Testnetanchor.seevcash.comStellar 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

EndpointMethodDescription
/api/v1/merchant/profileGETView your merchant profile
/api/v1/merchant/apikeys/:idDELETERevoke an API key
/api/v1/merchant/kyb/submitPOSTSubmit KYB (Know Your Business) documents
/api/v1/merchant/kyb/statusGETCheck KYB verification status

All require Authorization: Bearer <access_token>.


Required Headers

HeaderUsed InDescription
X-API-KeyWidget endpointsYour merchant API key
X-Session-IdSession-protected endpointsFrom /widget/session response
X-Session-TokenSession-protected endpointsFrom /widget/session response
X-Idempotency-KeyOrder creationUnique UUID to prevent duplicates
AuthorizationDashboard endpointsBearer <access_token> from login
Content-TypeAll POST/PUTapplication/json

Error Responses

All errors follow this format:

{
    "error": {
        "code": "VALIDATION_ERROR",
        "message": "fiat_amount must be greater than 0"
    }
}
CodeHTTP StatusMeaning
VALIDATION_ERROR400Request body failed validation
MISSING_HEADER400Required header missing (e.g., X-Idempotency-Key)
UNAUTHORIZED401Invalid or expired API key / session / token
FORBIDDEN403Domain not in allowed list
NOT_FOUND404Order or resource not found
DUPLICATE_ORDER409Idempotency key already used
PHONE_NOT_VERIFIED422Phone number hasn't been OTP-verified
QUOTE_EXPIRED422Quote expired, request a new one
RATE_LIMITED429Too many requests
INTERNAL_ERROR500Something went wrong on our end

Transaction Statuses

StatusMeaning
pending_user_transfer_startWaiting for customer to complete payment
pending_anchorFiat received, crypto delivery in progress
pending_stellarCrypto sent, awaiting blockchain confirmation
pending_externalCrypto received, fiat payout initiated
pending_payout_confirmationFiat payout in progress
completedTransaction finished successfully
failedSomething went wrong
expiredCustomer 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:

HeaderDescription
X-Webhook-SignatureHMAC-SHA256 signature of the payload body
X-Webhook-TimestampUnix timestamp when sent

Verify using your webhook secret (found in dashboard).

Events:

EventDescription
order.completedCrypto delivered (onramp) or fiat paid out (offramp)
order.failedPayment failed or declined
order.expiredPayment window timed out

Retry Policy:

If your endpoint returns non-2xx, we retry:

  1. Immediate → 2. 10 seconds → 3. 1 minute → 4. 1 hour → 5. 4 hours

After 5 failed attempts, delivery is marked exhausted.


Supported Payment Methods

MethodBuySellSpeed
MTN Mobile Money1–4 min
Vodafone Cash1–4 min
AirtelTigo Money1–4 min
Bank Transfer🚧🚧Coming Soon

Supported Assets

AssetNetworkDescription
USDCStellarUS Dollar-pegged stablecoin (1 USDC ≈ $1)

Fees

Fee TypeDescription
Platform feePercentage of transaction (your fee_base_bps + fee_markup_bps)
Network feeStellar transaction fee (fractions of a cent)
Exchange spreadBuilt 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 public keys for frontend widget, secret keys for server-to-server
  • Restrict keys to your allowed domains and IPs
  • Never expose secret keys 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


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 🚀

On this page