Documentation Index
Fetch the complete documentation index at: https://stablex.cash/docs/llms.txt
Use this file to discover all available pages before exploring further.
StableX Complete API Reference
Use the On this page menu on the right to jump to any section.
1. API Overview
1.1 GraphQL Endpoint
POST https://your-domain.com/graphql
Content-Type: application/json
Authorization: Bearer <access_token> (for authenticated requests)
{
"query": "mutation { ... }",
"variables": { ... }
}
2. Authentication
2.1 Unified Login (Recommended)
Automatically detects if user is a Merchant or Staff member.
Permissions: None (public)
Request:
mutation Login($email: String!, $password: String!) {
login(email: $email, password: $password) {
access_token
refresh_token
expires_in
user_type
}
}
Variables:
{
"email": "merchant@example.com",
"password": "SecurePass123!"
}
Response (Merchant):
{
"data": {
"login": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": null,
"expires_in": 3600,
"user_type": "merchant"
}
}
}
Response (Staff):
{
"data": {
"login": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "def502004a3f5e...",
"expires_in": 3600,
"user_type": "staff"
}
}
}
2.2 Merchant Login (Legacy)
Permissions: None (public)
Request:
mutation MerchantLogin($email: String!, $password: String!) {
merchantLogin(email: $email, password: $password) {
access_token
token_type
}
}
Variables:
{
"email": "merchant@example.com",
"password": "SecurePass123!"
}
Response:
{
"data": {
"merchantLogin": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer"
}
}
}
2.3 Staff Login (Legacy)
Permissions: None (public)
Request:
mutation StaffLogin($email: String!, $password: String!) {
staffLogin(email: $email, password: $password) {
access_token
refresh_token
token_type
expires_in
}
}
Variables:
{
"email": "staff@example.com",
"password": "SecurePass123!"
}
Response:
{
"data": {
"staffLogin": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "def502004a3f5e...",
"token_type": "Bearer",
"expires_in": 3600
}
}
}
2.4 Refresh Token
Get a new access token without re-entering credentials.
Permissions: None (public, but requires valid refresh token)
Request:
mutation RefreshToken($refreshToken: String!) {
refreshToken(refreshToken: $refreshToken) {
access_token
refresh_token
token_type
expires_in
}
}
Variables:
{
"refreshToken": "def502004a3f5e..."
}
Response:
{
"data": {
"refreshToken": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "abc123004b4g6f...",
"token_type": "Bearer",
"expires_in": 3600
}
}
}
2.5 Request Password Reset
Permissions: None (public)
Request:
mutation RequestPasswordReset($email: String!) {
requestPasswordReset(email: $email)
}
Variables:
{
"email": "user@example.com"
}
Response:
{
"data": {
"requestPasswordReset": true
}
}
2.6 Reset Password
Permissions: None (public, but requires valid token)
Request:
mutation ResetPassword($token: String!, $newPassword: String!) {
resetPassword(token: $token, newPassword: $newPassword)
}
Variables:
{
"token": "abc123def456...",
"newPassword": "NewSecurePass123!"
}
Response:
{
"data": {
"resetPassword": true
}
}
2.7 Get Current User (Me)
Permissions: Requires authentication
Request:
query Me {
me {
... on Merchant {
id
accountNumber
email
name
merchant_category
wallets {
id
address
blockchain
nickname
}
}
... on Staff {
id
email
display_name
roles
is_active
merchant {
id
name
}
}
}
}
Response (Merchant):
{
"data": {
"me": {
"id": "1",
"accountNumber": "9891123456789012",
"email": "merchant@example.com",
"name": "Coffee Shop",
"merchant_category": "Food & Beverage",
"wallets": [
{
"id": "1",
"address": "DYw8jCTfwHNRJhhmFcbXvVDTqWMEVFBX6ZKUmG5CNSKK",
"blockchain": "solana-devnet",
"nickname": "Main Wallet"
}
]
}
}
}
Response (Staff):
{
"data": {
"me": {
"id": "5",
"email": "cashier@example.com",
"display_name": "John Doe",
"roles": ["Cashier"],
"is_active": true,
"merchant": {
"id": "1",
"name": "Coffee Shop"
}
}
}
}
3. Merchant Operations
3.1 Create Merchant (Sign Up)
Permissions: None (public)
Request:
mutation CreateMerchant($name: String!, $email: String!, $password: String!) {
createMerchant(name: $name, email: $email, password: $password) {
id
accountNumber
name
email
}
}
Variables:
{
"name": "My Coffee Shop",
"email": "owner@coffeeshop.com",
"password": "SecurePass123!"
}
Response:
{
"data": {
"createMerchant": {
"id": "1",
"accountNumber": "9891123456789012",
"name": "My Coffee Shop",
"email": "owner@coffeeshop.com"
}
}
}
3.2 Update Merchant Profile
Permissions: merchant.profile.manage (Merchant only)
Request:
mutation UpdateMerchantProfile($profile: MerchantProfileInput!) {
updateMerchantProfile(profile: $profile) {
id
accountNumber
name
email
tax_percentage
merchant_category
address {
address_line
city
state
country
}
}
}
Variables:
{
"profile": {
"name": "Updated Coffee Shop",
"tax_percentage": 8.5,
"merchant_category": "Food & Beverage",
"address": {
"address_line": "123 Main St",
"city": "San Francisco",
"state": "CA",
"country": "USA"
},
"pricing_model_id": 2
}
}
Response:
{
"data": {
"updateMerchantProfile": {
"id": "1",
"accountNumber": "9891123456789012",
"name": "Updated Coffee Shop",
"email": "owner@coffeeshop.com",
"tax_percentage": 8.5,
"merchant_category": "Food & Beverage",
"address": {
"address_line": "123 Main St",
"city": "San Francisco",
"state": "CA",
"country": "USA"
}
}
}
}
3.3 Merchant Account Number
Every merchant is automatically assigned a unique 16-digit account number upon creation.
Format: 9891 + 12 random digits
Example: 9891123456789012
Features:
- Automatically Generated: Created when a merchant signs up
- Unique: Enforced by database constraint
- Immutable: Cannot be changed after creation
- Format Validation: Checked via database constraint (
^9891[0-9]{12}$)
Use Cases:
- Merchant identification
- Account reconciliation
- Integration with external systems
- Customer invoicing
Querying Account Number:
query Me {
me {
... on Merchant {
id
accountNumber
name
email
}
}
}
Response:
{
"data": {
"me": {
"id": "1",
"accountNumber": "9891123456789012",
"name": "My Coffee Shop",
"email": "owner@coffeeshop.com"
}
}
}
4. Staff Management
4.1 Create Staff
Permissions: staff.manage (Merchant or Manager with staff.manage permission)
Request:
mutation CreateStaff(
$merchantId: ID
$email: String!
$password: String!
$displayName: String
$roles: [String!]!
) {
createStaff(
merchantId: $merchantId
email: $email
password: $password
displayName: $displayName
roles: $roles
) {
id
email
display_name
roles
is_active
}
}
Variables:
{
"merchantId": "1",
"email": "cashier@coffeeshop.com",
"password": "SecurePass123!",
"displayName": "Jane Smith",
"roles": ["Cashier"]
}
Response:
{
"data": {
"createStaff": {
"id": "5",
"email": "cashier@coffeeshop.com",
"display_name": "Jane Smith",
"roles": ["Cashier"],
"is_active": true
}
}
}
Note: The merchantId parameter is optional:
- If omitted, the merchant ID is automatically inferred from the authenticated user (works for both Merchant and Staff users)
- If provided, it must match the authenticated user’s merchant ID (staff cannot create users for other merchants)
- Can be passed as either a string (
"1") or number (1) - both are accepted
4.2 List Staff
Permissions: staff.list
Request:
query StaffList($merchantId: ID!) {
staffList(merchantId: $merchantId) {
id
email
display_name
roles
is_active
}
}
Variables:
Response:
{
"data": {
"staffList": [
{
"id": "5",
"email": "cashier@coffeeshop.com",
"display_name": "Jane Smith",
"roles": ["Cashier"],
"is_active": true
},
{
"id": "6",
"email": "manager@coffeeshop.com",
"display_name": "Bob Johnson",
"roles": ["Manager"],
"is_active": true
}
]
}
}
4.3 Update Staff
Permissions: staff.manage
Request:
mutation UpdateStaff(
$id: ID!
$displayName: String
$roles: [String!]
$isActive: Boolean
) {
updateStaff(
id: $id
displayName: $displayName
roles: $roles
isActive: $isActive
) {
id
email
display_name
roles
is_active
}
}
Variables:
{
"id": "5",
"displayName": "Jane Doe",
"roles": ["Manager"],
"isActive": true
}
Response:
{
"data": {
"updateStaff": {
"id": "5",
"email": "cashier@coffeeshop.com",
"display_name": "Jane Doe",
"roles": ["Manager"],
"is_active": true
}
}
}
4.4 Deactivate Staff
Permissions: staff.manage
Request:
mutation DeactivateStaff($id: ID!) {
deactivateStaff(id: $id)
}
Variables:
Response:
{
"data": {
"deactivateStaff": true
}
}
4.5 Assign Role to Staff
Permissions: staff.manage
Request:
mutation AssignRoleToStaff($staffId: ID!, $roleName: String!) {
assignRoleToStaff(staffId: $staffId, roleName: $roleName) {
id
email
roles
}
}
Variables:
{
"staffId": "5",
"roleName": "Manager"
}
Response:
{
"data": {
"assignRoleToStaff": {
"id": "5",
"email": "cashier@coffeeshop.com",
"roles": ["Manager", "Cashier"]
}
}
}
4.6 Get Merchant Info for Staff
Permissions: Requires authentication
Request:
query GetMerchantInfoForStaff($staffEmail: String!) {
getMerchantInfoForStaff(staffEmail: $staffEmail) {
merchantId
accountNumber
}
}
Variables:
{
"staffEmail": "cashier@coffeeshop.com"
}
Response:
{
"data": {
"getMerchantInfoForStaff": {
"merchantId": "1",
"accountNumber": "9891123456789012"
}
}
}
5. Payment Operations
5.1 Create Payment
Permissions: payment.create
Request:
mutation CreatePayment(
$amount: Decimal!
$tipAmount: Decimal
$blockchain: String!
$tokenSymbol: String!
) {
createPayment(
amount: $amount
tipAmount: $tipAmount
blockchain: $blockchain
tokenSymbol: $tokenSymbol
) {
url
qr_code
transaction {
id
reference
amount
tip_amount
status
timestamp
tokenSymbol
}
}
}
Variables:
{
"amount": "25.50",
"blockchain": "solana-devnet",
"tokenSymbol": "USDC"
}
Response:
{
"data": {
"createPayment": {
"url": "solana:DYw8jCTfwHNRJhhmFcbXvVDTqWMEVFBX6ZKUmG5CNSKK?amount=25.50&spl-token=4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU&reference=abc123...",
"qr_code": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...",
"transaction": {
"id": "42",
"reference": "abc123def456...",
"amount": "25.50",
"status": "pending",
"timestamp": "2024-01-15T10:30:00Z",
"tokenSymbol": "USDC"
}
}
}
}
5.2 Regenerate Payment
Permissions: payment.create
Request:
mutation RegeneratePayment($reference: String!) {
regeneratePayment(reference: $reference) {
url
qr_code
transaction {
id
reference
amount
status
}
}
}
Variables:
{
"reference": "abc123def456..."
}
Response:
{
"data": {
"regeneratePayment": {
"url": "solana:DYw8jCTfwHNRJhhmFcbXvVDTqWMEVFBX6ZKUmG5CNSKK?amount=25.50...",
"qr_code": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...",
"transaction": {
"id": "42",
"reference": "abc123def456...",
"amount": "25.50",
"status": "pending"
}
}
}
}
5.3 Create Payment Link
Creates a shareable payment link: a pending transaction, invoice, and a unique slug. The returned url is the public checkout URL (e.g. https://your-domain.com/pay/<slug>). No authentication is required for customers to open that URL and pay.
Permissions: payment.create
Request:
mutation CreatePaymentLink(
$amount: Decimal!
$tokenSymbol: String!
$blockchain: String!
$tipAmount: Decimal
$description: String
$expiresInHours: Int
) {
createPaymentLink(
amount: $amount
tokenSymbol: $tokenSymbol
blockchain: $blockchain
tipAmount: $tipAmount
description: $description
expiresInHours: $expiresInHours
) {
url
slug
transaction {
id
reference
amount
tip_amount
status
tokenSymbol
}
}
}
Variables:
{
"amount": "25.50",
"tokenSymbol": "USDC",
"blockchain": "solana-devnet",
"tipAmount": "2.00",
"description": "Order #1234",
"expiresInHours": 24
}
Response:
{
"data": {
"createPaymentLink": {
"url": "https://your-domain.com/pay/a1b2c3d4e5f6",
"slug": "a1b2c3d4e5f6",
"transaction": {
"id": "101",
"reference": "8Kj3mNxPq7Rs...",
"amount": "25.50",
"tip_amount": "2.00",
"status": "pending",
"tokenSymbol": "USDC"
}
}
}
}
- url: Public URL to share with the customer. Opening it returns checkout JSON (see 5.4).
- slug: Unique identifier for the link (also used in
url).
- expiresInHours: Optional. If set, the link is considered expired after that many hours.
5.4 Get Payment Link Checkout (Public)
Authentication: None (public endpoint for customers).
Returns JSON for the checkout UI: merchant name, amount, token, network, payment URL (for QR / Solana Pay), and transaction reference. Used when a customer opens a payment link (e.g. https://your-domain.com/pay/<slug>).
Endpoint:
GET https://your-domain.com/pay/{slug}
Example:
curl https://your-domain.com/pay/a1b2c3d4e5f6
Response (200 OK):
{
"merchant_name": "Acme Coffee",
"amount": "25.50",
"tip_amount": "2.00",
"token_symbol": "USDC",
"network": "solana-devnet",
"payment_url": "solana:DYw8jCTfwHNRJhhmFcbXvVDTqWMEVFBX6ZKUmG5CNSKK?amount=27.50&...",
"transaction_reference": "8Kj3mNxPq7Rs...",
"slug": "a1b2c3d4e5f6"
}
- payment_url: Use this for QR code or “Pay with Solana” / wallet deep link.
- transaction_reference: Use with
transactionStatus(reference: ...) to poll for confirmation.
Errors:
- 404: Payment link not found, expired, or already used (transaction confirmed).
6. Transaction & Reporting
6.1 List Transactions
Permissions: transaction.view
Request:
query Transactions($limit: Int, $offset: Int) {
transactions(limit: $limit, offset: $offset) {
transactions {
id
reference
amount
status
timestamp
tokenSymbol
transaction_hash
}
totalCount
}
}
Variables:
{
"limit": 10,
"offset": 0
}
Response:
{
"data": {
"transactions": {
"transactions": [
{
"id": "42",
"reference": "abc123def456...",
"amount": "25.50",
"status": "confirmed",
"timestamp": "2024-01-15T10:30:00Z",
"tokenSymbol": "USDC",
"transaction_hash": "5g4h8j9k2l3m4n5o6p7q8r9s0t1u2v3w..."
}
],
"totalCount": 42
}
}
}
6.2 Transaction Status
Permissions: transaction.view
Request:
query TransactionStatus($reference: String!) {
transactionStatus(reference: $reference) {
id
reference
amount
status
timestamp
transaction_hash
}
}
Variables:
{
"reference": "abc123def456..."
}
Response:
{
"data": {
"transactionStatus": {
"id": "42",
"reference": "abc123def456...",
"amount": "25.50",
"status": "confirmed",
"timestamp": "2024-01-15T10:30:00Z",
"transaction_hash": "5g4h8j9k2l3m4n5o6p7q8r9s0t1u2v3w..."
}
}
}
6.3 Daily Summary
Permissions: report.view
Request:
query DailySummary($timeframe: ReportTimeframe) {
dailySummary(timeframe: $timeframe) {
date
totalSales
transactionCount
averageTransactionValue
}
}
Variables:
Response:
{
"data": {
"dailySummary": [
{
"date": "2024-01-15",
"totalSales": "1250.00",
"transactionCount": 42,
"averageTransactionValue": "29.76"
}
]
}
}
6.4 Sales Summary Report
Permissions: report.view
Request:
query SalesSummaryReport(
$timeframe: ReportTimeframe!
$startDate: String
$endDate: String
) {
salesSummaryReport(
timeframe: $timeframe
startDate: $startDate
endDate: $endDate
) {
totalSales
transactionCount
averageTransactionValue
reportPeriod
}
}
Variables:
{
"timeframe": "MONTHLY",
"startDate": "2024-01-01",
"endDate": "2024-01-31"
}
Response:
{
"data": {
"salesSummaryReport": {
"totalSales": "12500.00",
"transactionCount": 420,
"averageTransactionValue": "29.76",
"reportPeriod": "2024-01 (Monthly)"
}
}
}
6.5 Sales Analytics
Permissions: report.view
Request:
query SalesAnalytics($timeframe: String!) {
salesAnalytics(timeframe: $timeframe) {
date
totalSales
}
}
Variables:
{
"timeframe": "weekly"
}
Response:
{
"data": {
"salesAnalytics": [
{
"date": "2024-01-15",
"totalSales": "1250.00"
},
{
"date": "2024-01-16",
"totalSales": "1580.50"
}
]
}
}
6.6 Sales By Hour
Permissions: report.view
Request:
query SalesByHour {
salesByHour {
hour
totalSales
}
}
Response:
{
"data": {
"salesByHour": [
{
"hour": 9,
"totalSales": "150.00"
},
{
"hour": 10,
"totalSales": "320.50"
}
]
}
}
6.7 PDF Downloads (Invoices & Receipts)
StableX provides two types of PDF documents:
- Invoices: For pending/unpaid transactions (blue header, red “PAYMENT PENDING” stamp)
- Receipts: For confirmed/paid transactions (green header, green “PAID” stamp)
6.7.1 Get Invoice Info (GraphQL)
Get the download URL and QR code for an invoice PDF.
Permissions: Authenticated (merchant or staff)
Request:
query GetInvoiceInfo($reference: String!) {
getInvoiceInfo(reference: $reference) {
url
qr_code
}
}
Variables:
{
"reference": "abc123def456..."
}
Response:
{
"data": {
"getInvoiceInfo": {
"url": "https://your-domain.com/invoices/abc123def456.../download",
"qr_code": "iVBORw0KGgoAAAANSUhEUgAA..."
}
}
}
6.7.2 Get Receipt Info (GraphQL)
Get the download URL and QR code for a receipt PDF.
Permissions: Authenticated (merchant or staff)
Request:
query GetReceiptInfo($reference: String!) {
getReceiptInfo(reference: $reference) {
url
qr_code
}
}
Variables:
{
"reference": "abc123def456..."
}
Response:
{
"data": {
"getReceiptInfo": {
"url": "https://your-domain.com/receipts/abc123def456.../download",
"qr_code": "iVBORw0KGgoAAAANSUhEUgAA..."
}
}
}
6.7.3 Download Invoice PDF (REST API)
Download the invoice PDF directly.
Endpoint: GET /invoices/{transaction_reference}/download
Authentication: Bearer token required
Request:
curl -X GET https://your-domain.com/invoices/abc123def456.../download \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
-o invoice.pdf
Response: PDF file (application/pdf)
Status Codes:
200 OK: PDF generated successfully
404 Not Found: Transaction not found
401 Unauthorized: Invalid or missing token
500 Internal Server Error: PDF generation failed
6.7.4 Download Receipt PDF (REST API)
Download the receipt PDF directly (only for confirmed transactions).
Endpoint: GET /receipts/{transaction_reference}/download
Authentication: Bearer token required
Request:
curl -X GET https://your-domain.com/receipts/abc123def456.../download \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
-o receipt.pdf
Response: PDF file (application/pdf)
Status Codes:
200 OK: PDF generated successfully
404 Not Found: Transaction not found or not confirmed
401 Unauthorized: Invalid or missing token
500 Internal Server Error: PDF generation failed
Note: Receipts can only be downloaded for transactions with status confirmed. For pending transactions, use the invoice endpoint instead.
6.7.5 Invoice Query with Transaction Reference
When querying invoices, include the transaction relationship to get the reference needed for PDF downloads. Invoices can be in lifecycle states: draft, sent, pending, paid, overdue, or void. Draft and sent invoices may have transaction_id: null until the customer pays.
Request:
query GetInvoices($limit: Int, $offset: Int) {
invoices(limit: $limit, offset: $offset) {
invoices {
id
amount
tax_amount
status
creation_date
invoice_number
due_date
customer_email
sent_at
last_reminder_at
transaction_id
transaction {
reference
}
line_items {
id
description
quantity
unit_amount
amount
}
}
totalCount
}
}
Response:
{
"data": {
"invoices": {
"invoices": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"amount": "100.00",
"tax_amount": "10.00",
"status": "draft",
"creation_date": "2024-01-15T10:30:00Z",
"invoice_number": "INV-0001",
"due_date": "2024-02-01T00:00:00Z",
"customer_email": "customer@example.com",
"sent_at": null,
"last_reminder_at": null,
"transaction_id": null,
"transaction": null,
"line_items": [
{
"id": "1",
"description": "Item A",
"quantity": "2",
"unit_amount": "25.00",
"amount": "50.00"
}
]
}
],
"totalCount": 1
}
}
}
Usage: For paid (or sent) invoices with a transaction, use transaction.reference to construct the download URL:
/invoices/{transaction.reference}/download
6.8 Invoice Lifecycle (Draft, Send, Remind)
Invoices support a full lifecycle: create as draft, send to the customer (email + payment link), then paid when the customer pays. Optional overdue status and reminders are supported.
Invoice statuses: draft | sent | pending | paid | overdue | void
- draft: Created without a transaction; can be updated.
- sent: Payment link created and (optionally) email sent;
transaction_id and sent_at set.
- pending: Legacy: invoice tied to a transaction not yet confirmed.
- paid: Payment confirmed;
payment_date set.
- overdue:
due_date has passed and status was sent.
- void: Cancelled.
6.8.1 Create Invoice (Draft)
Create an invoice in draft state with no transaction. Optionally include line items, due date, and customer email (required later for sending).
Permissions: Authenticated (merchant or staff)
Request:
mutation CreateInvoice(
$amount: Decimal!
$taxAmount: Decimal!
$description: String
$dueDate: String
$customerEmail: String
$lineItems: [InvoiceLineItemInput!]
) {
createInvoice(
amount: $amount
taxAmount: $taxAmount
description: $description
dueDate: $dueDate
customerEmail: $customerEmail
lineItems: $lineItems
) {
id
status
amount
tax_amount
invoice_number
due_date
customer_email
transaction_id
line_items {
id
description
quantity
unit_amount
amount
}
}
}
Variables:
{
"amount": "150.00",
"taxAmount": "15.00",
"description": "Consulting services",
"dueDate": "2025-03-15T00:00:00Z",
"customerEmail": "client@example.com",
"lineItems": [
{
"description": "Hourly consulting",
"quantity": "10",
"unit_amount": "15.00",
"amount": "150.00"
}
]
}
Response:
{
"data": {
"createInvoice": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "draft",
"amount": "150.00",
"tax_amount": "15.00",
"invoice_number": "INV-0001",
"due_date": "2025-03-15T00:00:00Z",
"customer_email": "client@example.com",
"transaction_id": null,
"line_items": [
{
"id": "1",
"description": "Hourly consulting",
"quantity": "10",
"unit_amount": "15.00",
"amount": "150.00"
}
]
}
}
}
Input type InvoiceLineItemInput:
| Field | Type | Required | Description |
|---|
| description | String! | Yes | Line item description |
| quantity | Decimal! | Yes | Quantity |
| unit_amount | Decimal! | Yes | Price per unit |
| amount | Decimal! | Yes | Total (e.g. quantity × unit) |
| productId | ID | No | Optional link to product |
6.8.2 Update Invoice (Draft Only)
Update a draft invoice: amount, tax, description, due date, customer email, and/or line items. Replacing lineItems overwrites all existing line items.
Permissions: Authenticated (merchant or staff)
Request:
mutation UpdateInvoice(
$invoiceId: ID!
$amount: Decimal
$taxAmount: Decimal
$description: String
$dueDate: String
$customerEmail: String
$lineItems: [InvoiceLineItemInput!]
) {
updateInvoice(
invoiceId: $invoiceId
amount: $amount
taxAmount: $taxAmount
description: $description
dueDate: $dueDate
customerEmail: $customerEmail
lineItems: $lineItems
) {
id
status
amount
description
due_date
customer_email
line_items { id description quantity unit_amount amount }
}
}
Variables (example: update amount and due date only):
{
"invoiceId": "550e8400-e29b-41d4-a716-446655440000",
"amount": "200.00",
"dueDate": "2025-03-20T00:00:00Z"
}
Response: Returns the updated Invoice object. If the invoice is not in draft status, an error is returned.
6.8.3 Send Invoice
Moves an invoice from draft to sent: creates a pending transaction and payment link, sets sent_at, and optionally sends an email to customer_email with the payment URL. The customer can open the link to pay; when payment is confirmed, the invoice is marked paid.
Permissions: Authenticated (merchant or staff)
Requirements: Invoice must be draft and have customer_email set. You must have a wallet for the given blockchain.
Request:
mutation SendInvoice(
$invoiceId: ID!
$blockchain: String!
$tokenSymbol: String!
) {
sendInvoice(
invoiceId: $invoiceId
blockchain: $blockchain
tokenSymbol: $tokenSymbol
) {
success
message
url
invoice {
id
status
sent_at
transaction_id
}
}
}
Variables:
{
"invoiceId": "550e8400-e29b-41d4-a716-446655440000",
"blockchain": "solana-devnet",
"tokenSymbol": "USDC"
}
Response:
{
"data": {
"sendInvoice": {
"success": true,
"message": "Invoice sent",
"url": "https://your-domain.com/pay/a1b2c3d4e5f6",
"invoice": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "sent",
"sent_at": "2025-02-11T14:30:00Z",
"transaction_id": "42"
}
}
}
}
Notes:
url is the public payment link; share it or rely on the email sent to customer_email.
- If the email fails, the invoice is still marked sent and the mutation succeeds; the
url can be shared manually.
6.8.4 Send Invoice Reminder
Sends a reminder email for an invoice in sent or overdue status and sets last_reminder_at. The email includes the same payment link as when the invoice was sent.
Permissions: Authenticated (merchant or staff)
Request:
mutation SendInvoiceReminder($invoiceId: ID!) {
sendInvoiceReminder(invoiceId: $invoiceId) {
id
status
last_reminder_at
}
}
Variables:
{
"invoiceId": "550e8400-e29b-41d4-a716-446655440000"
}
Response:
{
"data": {
"sendInvoiceReminder": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "overdue",
"last_reminder_at": "2025-02-11T15:00:00Z"
}
}
}
Errors: Invoice must be in sent or overdue and have customer_email; the invoice must have an associated payment link (transaction).
6.8.5 Sync Invoice Status
Manually sync an invoice’s status with its linked transaction (e.g. after payment confirmation). Useful if automatic status updates did not run. The invoice must already have a transaction_id (e.g. created via sendInvoice or a payment link).
Permissions: Authenticated (merchant or staff)
Request:
mutation SyncInvoiceStatus($invoiceId: ID!) {
syncInvoiceStatus(invoiceId: $invoiceId) {
id
status
payment_date
transaction_id
}
}
Variables:
{
"invoiceId": "550e8400-e29b-41d4-a716-446655440000"
}
Response: Returns the updated Invoice. If the linked transaction is confirmed on-chain, the invoice is updated to paid and payment_date is set.
7. Wallet Management
7.1 Add or Update Wallet
Permissions: wallet.manage
Request:
mutation AddOrUpdateWallet(
$address: String!
$blockchain: String!
$nickname: String
) {
addOrUpdateWallet(
address: $address
blockchain: $blockchain
nickname: $nickname
) {
id
address
blockchain
nickname
}
}
Variables:
{
"address": "DYw8jCTfwHNRJhhmFcbXvVDTqWMEVFBX6ZKUmG5CNSKK",
"blockchain": "solana-devnet",
"nickname": "Main Solana Wallet"
}
Response:
{
"data": {
"addOrUpdateWallet": {
"id": "1",
"address": "DYw8jCTfwHNRJhhmFcbXvVDTqWMEVFBX6ZKUmG5CNSKK",
"blockchain": "solana-devnet",
"nickname": "Main Solana Wallet"
}
}
}
7.2 Remove Wallet
Permissions: wallet.manage
Request:
mutation RemoveWallet($walletId: ID!) {
removeWallet(walletId: $walletId)
}
Variables:
Response:
{
"data": {
"removeWallet": true
}
}
7.3 Wallet Balances
Permissions: wallet.view
Request:
query WalletBalances {
walletBalances {
address
blockchain
nickname
totalBalance
breakdown {
USDC
USDT
}
}
}
Response:
{
"data": {
"walletBalances": [
{
"address": "DYw8jCTfwHNRJhhmFcbXvVDTqWMEVFBX6ZKUmG5CNSKK",
"blockchain": "solana-devnet",
"nickname": "Main Wallet",
"totalBalance": "1250.50",
"breakdown": {
"USDC": "850.00",
"USDT": "400.50"
}
}
]
}
}
7.4 Token Balances
Permissions: wallet.view
Request:
query TokenBalances(
$blockchain: String!
$walletAddress: String!
$tokenSymbols: [String!]!
) {
tokenBalances(
blockchain: $blockchain
walletAddress: $walletAddress
tokenSymbols: $tokenSymbols
) {
tokenSymbol
balance
}
}
Variables:
{
"blockchain": "solana-devnet",
"walletAddress": "DYw8jCTfwHNRJhhmFcbXvVDTqWMEVFBX6ZKUmG5CNSKK",
"tokenSymbols": ["USDC", "USDT"]
}
Response:
{
"data": {
"tokenBalances": [
{
"tokenSymbol": "USDC",
"balance": "850.00"
},
{
"tokenSymbol": "USDT",
"balance": "400.50"
}
]
}
}
8. Customer Management
8.1 List Customers
Permissions: customer.view
Request:
query Customers {
customers {
id
wallet_address
name
email
phone_number
}
}
Response:
{
"data": {
"customers": [
{
"id": "10",
"wallet_address": "7xKs9mPqR8TuV3Wy0Zd5AcYb2MeFiHgF7Vj6Pu9Xq1Rs4",
"name": "John Doe",
"email": "john@example.com",
"phone_number": "+1234567890"
}
]
}
}
8.2 Upsert Customer
Permissions: customer.manage
Request:
mutation UpsertCustomer(
$wallet_address: String!
$details: CustomerUpdate!
) {
upsertCustomer(
wallet_address: $wallet_address
details: $details
) {
id
wallet_address
name
email
phone_number
}
}
Variables:
{
"wallet_address": "7xKs9mPqR8TuV3Wy0Zd5AcYb2MeFiHgF7Vj6Pu9Xq1Rs4",
"details": {
"name": "Jane Doe",
"email": "jane@example.com",
"phone_number": "+1987654321"
}
}
Response:
{
"data": {
"upsertCustomer": {
"id": "11",
"wallet_address": "7xKs9mPqR8TuV3Wy0Zd5AcYb2MeFiHgF7Vj6Pu9Xq1Rs4",
"name": "Jane Doe",
"email": "jane@example.com",
"phone_number": "+1987654321"
}
}
}
9. Error Handling
{
"errors": [
{
"message": "Access denied. Required permission: payment.create",
"extensions": {
"code": "PERMISSION_DENIED",
"details": {
"required_permission": "payment.create"
}
}
}
]
}
9.2 Standard Error Codes
| Code | HTTP Status | Description | Action |
|---|
NOT_AUTHENTICATED | 401 | Missing or invalid token | Redirect to login |
PERMISSION_DENIED | 403 | User lacks required permission | Show access denied message |
INVALID_CREDENTIALS | 401 | Wrong email/password | Show login error |
TOKEN_EXPIRED | 401 | Access token expired | Call refreshToken |
TOKEN_REVOKED | 401 | Refresh token revoked | Redirect to login |
RECORD_NOT_FOUND | 404 | Resource doesn’t exist | Show 404 state |
VALIDATION_ERROR | 400 | Invalid input data | Show validation errors |
INTERNAL_ERROR | 500 | Server error | Show generic error |
9.3 Common Error Scenarios
1. Expired Token
{
"errors": [{
"message": "Not authenticated",
"extensions": { "code": "NOT_AUTHENTICATED" }
}]
}
Solution: Call refreshToken mutation or redirect to login
2. Permission Denied
{
"errors": [{
"message": "Access denied. Required permission: staff.manage",
"extensions": {
"code": "PERMISSION_DENIED",
"details": { "required_permission": "staff.manage" }
}
}]
}
Solution: Show user-friendly “You don’t have permission” message
3. Validation Error
{
"errors": [{
"message": "Email already registered",
"extensions": {
"code": "VALIDATION_ERROR",
"details": { "field": "email" }
}
}]
}
Solution: Highlight the email field and show error
10. Refund Operations
10.1 Create Refund Request
Permissions: refund.create (Staff Manager)
Request:
mutation CreateRefund($transactionReference: String!, $refundAmount: Decimal!, $reason: String!) {
createRefundRequest(
transactionReference: $transactionReference
refundAmount: $refundAmount
reason: $reason
) {
id
refundReference
status
}
}
Variables:
{
"transactionReference": "TX_FULL_REFUND_UNIQUE_123",
"refundAmount": "50.00",
"reason": "Test reason"
}
Response:
{
"data": {
"createRefundRequest": {
"id": "1",
"refundReference": "REF123",
"status": "pending"
}
}
}
10.2 Approve Refund
Permissions: refund.approve (Staff Manager)
Request:
mutation ApproveRefund($refundReference: String!) {
approveRefund(refundReference: $refundReference) {
id
status
}
}
Variables:
{
"refundReference": "REF_TEST_APPROVE"
}
Response:
{
"data": {
"approveRefund": {
"id": "1",
"status": "approved"
}
}
}
10.3 Reject Refund
Permissions: refund.reject (Staff Manager)
Request:
mutation RejectRefund($refundReference: String!, $rejectionReason: String!) {
rejectRefund(refundReference: $refundReference, rejectionReason: $rejectionReason) {
id
status
}
}
Variables:
{
"refundReference": "REF-123",
"rejectionReason": "Invalid request"
}
Response:
{
"data": {
"rejectRefund": {
"id": "1",
"status": "rejected"
}
}
}
10.4 Complete Refund
Permissions: refund.complete (Merchant)
Request:
mutation CompleteRefund($refundReference: String!, $transactionHash: String) {
completeRefund(refundReference: $refundReference, transactionHash: $transactionHash) {
id
status
refundTransactionHash
}
}
Variables:
{
"refundReference": "REF_COMPLETE_TEST",
"transactionHash": "tx_hash_123"
}
Response:
{
"data": {
"completeRefund": {
"id": "1",
"status": "completed",
"refundTransactionHash": "tx_hash_123"
}
}
}
10.5 List Refunds
Permissions: refund.view (Staff Manager)
Request:
query Refunds($status: String) {
refunds(status: $status) {
refunds {
id
refundReference
refundAmount
status
}
totalCount
}
}
Variables (optional):
Response:
{
"data": {
"refunds": {
"refunds": [
{
"id": "6",
"refundReference": "REF_FILTER_2",
"refundAmount": "20.00",
"status": "approved"
}
],
"totalCount": 1
}
}
}
10.6 Get Refund by Reference
Permissions: refund.view (Staff Manager)
Request:
query RefundByReference($reference: String!) {
refundByReference(refundReference: $reference) {
id
refundReference
status
}
}
Variables:
{
"reference": "REF_BY_REFERENCE"
}
Response:
{
"data": {
"refundByReference": {
"id": "100",
"refundReference": "REF_BY_REFERENCE",
"status": "pending"
}
}
}
10.7 Get Refund Summary
Permissions: refund.view (Staff Manager)
Request:
query RefundSummary {
refundSummary {
totalRefunded
refundCount
completedRefunds
}
}
Response:
{
"data": {
"refundSummary": {
"totalRefunded": "50.00",
"refundCount": 1,
"completedRefunds": 1
}
}
}
11. Product & Price Management
11.1 List Products
Permissions: product.view
Request:
query GetProducts($active: Boolean, $category: String, $limit: Int, $offset: Int) {
products(active: $active, category: $category, limit: $limit, offset: $offset) {
products {
id
name
description
active
sku
productCode
category
tags
archivedAt
images
createdAt
}
totalCount
}
}
Variables:
{
"active": true,
"category": "Electronics",
"limit": 10,
"offset": 0
}
Response:
{
"data": {
"products": {
"products": [
{
"id": "1",
"name": "Premium Coffee Beans",
"description": "High-quality arabica coffee beans",
"active": true,
"sku": "COFFEE-001",
"productCode": "PC-001",
"category": "Beverages",
"tags": ["coffee", "premium", "arabica"],
"archivedAt": null,
"images": ["https://example.com/coffee.jpg"],
"createdAt": "2024-01-15T10:30:00Z"
}
],
"totalCount": 25
}
}
}
Note: The active filter can be used to show only active or inactive products. The category filter allows filtering by product category. Pagination is supported via limit and offset parameters.
11.2 Get Product by ID
Permissions: product.view
Request:
query GetProduct($id: ID!) {
product(id: $id) {
id
merchantId
name
description
active
sku
productCode
category
tags
archivedAt
images
metadata
prices {
id
amount
currency
type
active
}
createdAt
updatedAt
}
}
Variables:
Response:
{
"data": {
"product": {
"id": "1",
"merchantId": "1",
"name": "Premium Coffee Beans",
"description": "High-quality arabica coffee beans",
"active": true,
"sku": "COFFEE-001",
"productCode": "PC-001",
"category": "Beverages",
"tags": ["coffee", "premium", "arabica"],
"archivedAt": null,
"images": ["https://example.com/coffee.jpg"],
"metadata": {
"origin": "Colombia",
"roast": "Medium"
},
"prices": [
{
"id": "1",
"amount": "29.99",
"currency": "USD",
"type": "ONE_TIME",
"active": true
}
],
"createdAt": "2024-01-15T10:30:00Z",
"updatedAt": "2024-01-15T10:30:00Z"
}
}
}
11.3 Get Product by SKU
Permissions: product.view
Request:
query GetProductBySku($sku: String!) {
productBySku(sku: $sku) {
id
name
description
active
sku
productCode
category
tags
archivedAt
}
}
Variables:
Response:
{
"data": {
"productBySku": {
"id": "1",
"name": "Premium Coffee Beans",
"description": "High-quality arabica coffee beans",
"active": true,
"sku": "COFFEE-001",
"productCode": "PC-001",
"category": "Beverages",
"tags": ["coffee", "premium", "arabica"],
"archivedAt": null
}
}
}
Note: SKU must be unique per merchant. If a product with the given SKU is not found, an error will be returned.
11.4 Get Product Prices
Permissions: product.view
Request:
query GetProductPrices($productId: ID!) {
productPrices(productId: $productId) {
id
amount
currency
type
billingPeriod
active
nickname
description
pricingType
minAmount
maxAmount
trialPeriodDays
usageType
unitLabel
billingScheme
taxBehavior
taxCode
createdAt
}
}
Variables:
Response:
{
"data": {
"productPrices": [
{
"id": "1",
"amount": "29.99",
"currency": "USD",
"type": "ONE_TIME",
"billingPeriod": null,
"active": true,
"nickname": "Standard Price",
"description": "One-time purchase price",
"pricingType": "FIXED",
"minAmount": null,
"maxAmount": null,
"trialPeriodDays": null,
"usageType": null,
"unitLabel": null,
"billingScheme": null,
"taxBehavior": "EXCLUSIVE",
"taxCode": null,
"createdAt": "2024-01-15T10:30:00Z"
},
{
"id": "2",
"amount": "9.99",
"currency": "USD",
"type": "RECURRING",
"billingPeriod": "month",
"active": true,
"nickname": "Monthly Subscription",
"description": "Monthly recurring subscription",
"pricingType": "FIXED",
"minAmount": null,
"maxAmount": null,
"trialPeriodDays": 7,
"usageType": null,
"unitLabel": null,
"billingScheme": null,
"taxBehavior": "EXCLUSIVE",
"taxCode": null,
"createdAt": "2024-01-15T10:30:00Z"
}
]
}
}
11.5 Create Product
Permissions: product.manage
Request:
mutation CreateProduct(
$name: String!
$description: String
$active: Boolean
$metadata: JSON
$images: [String!]
$sku: String
$productCode: String
$category: String
$tags: [String!]
) {
createProduct(
name: $name
description: $description
active: $active
metadata: $metadata
images: $images
sku: $sku
productCode: $productCode
category: $category
tags: $tags
) {
id
name
description
active
sku
productCode
category
tags
images
createdAt
}
}
Variables:
{
"name": "Premium Coffee Beans",
"description": "High-quality arabica coffee beans from Colombia",
"active": true,
"sku": "COFFEE-001",
"productCode": "PC-001",
"category": "Beverages",
"tags": ["coffee", "premium", "arabica"],
"images": ["https://example.com/coffee.jpg"],
"metadata": {
"origin": "Colombia",
"roast": "Medium"
}
}
Response:
{
"data": {
"createProduct": {
"id": "1",
"name": "Premium Coffee Beans",
"description": "High-quality arabica coffee beans from Colombia",
"active": true,
"sku": "COFFEE-001",
"productCode": "PC-001",
"category": "Beverages",
"tags": ["coffee", "premium", "arabica"],
"images": ["https://example.com/coffee.jpg"],
"createdAt": "2024-01-15T10:30:00Z"
}
}
}
Note: The name field is required. All other fields are optional. The sku must be unique per merchant. If a product with the same SKU already exists, an error will be returned.
11.6 Update Product
Permissions: product.manage
Request:
mutation UpdateProduct(
$id: ID!
$name: String
$description: String
$active: Boolean
$metadata: JSON
$images: [String!]
$sku: String
$productCode: String
$category: String
$tags: [String!]
) {
updateProduct(
id: $id
name: $name
description: $description
active: $active
metadata: $metadata
images: $images
sku: $sku
productCode: $productCode
category: $category
tags: $tags
) {
id
name
description
active
sku
productCode
category
tags
updatedAt
}
}
Variables:
{
"id": "1",
"name": "Updated Coffee Beans",
"description": "Updated description",
"category": "Premium Beverages",
"tags": ["coffee", "premium", "arabica", "organic"]
}
Response:
{
"data": {
"updateProduct": {
"id": "1",
"name": "Updated Coffee Beans",
"description": "Updated description",
"active": true,
"sku": "COFFEE-001",
"productCode": "PC-001",
"category": "Premium Beverages",
"tags": ["coffee", "premium", "arabica", "organic"],
"updatedAt": "2024-01-16T14:20:00Z"
}
}
}
Note: Only the id field is required. All other fields are optional and will only be updated if provided. If updating the sku, it must remain unique per merchant.
11.7 Delete Product
Permissions: product.manage
Request:
mutation DeleteProduct($id: ID!) {
deleteProduct(id: $id)
}
Variables:
Response:
{
"data": {
"deleteProduct": true
}
}
Note: This performs a soft delete by setting active=false. The product record remains in the database but is marked as inactive.
11.8 Archive Product
Permissions: product.manage
Request:
mutation ArchiveProduct($id: ID!) {
archiveProduct(id: $id) {
id
name
archivedAt
}
}
Variables:
Response:
{
"data": {
"archiveProduct": {
"id": "1",
"name": "Premium Coffee Beans",
"archivedAt": "2024-01-16T14:20:00Z"
}
}
}
Note: Archiving a product sets the archivedAt timestamp. Archived products can be filtered out in queries and can be unarchived later.
11.9 Unarchive Product
Permissions: product.manage
Request:
mutation UnarchiveProduct($id: ID!) {
unarchiveProduct(id: $id) {
id
name
archivedAt
}
}
Variables:
Response:
{
"data": {
"unarchiveProduct": {
"id": "1",
"name": "Premium Coffee Beans",
"archivedAt": null
}
}
}
Note: Unarchiving a product clears the archivedAt timestamp, making the product available again.
11.10 Create Price
Permissions: product.manage
Request:
mutation CreatePrice(
$productId: ID!
$amount: Decimal!
$currency: String!
$type: PriceType!
$billingPeriod: String
$active: Boolean
$metadata: JSON
$nickname: String
$description: String
$pricingType: PricingType
$minAmount: Decimal
$maxAmount: Decimal
$trialPeriodDays: Int
$usageType: UsageType
$unitLabel: String
$billingScheme: BillingScheme
$taxBehavior: TaxBehavior
$taxCode: String
) {
createPrice(
productId: $productId
amount: $amount
currency: $currency
type: $type
billingPeriod: $billingPeriod
active: $active
metadata: $metadata
nickname: $nickname
description: $description
pricingType: $pricingType
minAmount: $minAmount
maxAmount: $maxAmount
trialPeriodDays: $trialPeriodDays
usageType: $usageType
unitLabel: $unitLabel
billingScheme: $billingScheme
taxBehavior: $taxBehavior
taxCode: $taxCode
) {
id
amount
currency
type
billingPeriod
active
nickname
description
pricingType
minAmount
maxAmount
trialPeriodDays
usageType
unitLabel
billingScheme
taxBehavior
taxCode
createdAt
}
}
Variables (One-time price):
{
"productId": "1",
"amount": "29.99",
"currency": "USD",
"type": "ONE_TIME",
"active": true,
"nickname": "Standard Price",
"description": "One-time purchase price",
"pricingType": "FIXED",
"taxBehavior": "EXCLUSIVE"
}
Variables (Recurring price with trial):
{
"productId": "1",
"amount": "9.99",
"currency": "USD",
"type": "RECURRING",
"billingPeriod": "month",
"active": true,
"nickname": "Monthly Subscription",
"description": "Monthly recurring subscription",
"pricingType": "FIXED",
"trialPeriodDays": 7,
"taxBehavior": "EXCLUSIVE"
}
Variables (Pay-What-You-Want price):
{
"productId": "1",
"amount": "20.00",
"currency": "USD",
"type": "ONE_TIME",
"active": true,
"nickname": "PWYW Price",
"description": "Customer chooses their price",
"pricingType": "PAY_WHAT_YOU_WANT",
"minAmount": "10.00",
"maxAmount": "50.00",
"taxBehavior": "EXCLUSIVE"
}
Variables (Usage-based pricing):
{
"productId": "1",
"amount": "0.01",
"currency": "USD",
"type": "RECURRING",
"billingPeriod": "month",
"active": true,
"nickname": "Per API Call",
"description": "Charged per API call",
"pricingType": "FIXED",
"usageType": "METERED",
"unitLabel": "API calls",
"billingScheme": "PER_UNIT",
"taxBehavior": "EXCLUSIVE"
}
Response:
{
"data": {
"createPrice": {
"id": "1",
"amount": "29.99",
"currency": "USD",
"type": "ONE_TIME",
"billingPeriod": null,
"active": true,
"nickname": "Standard Price",
"description": "One-time purchase price",
"pricingType": "FIXED",
"minAmount": null,
"maxAmount": null,
"trialPeriodDays": null,
"usageType": null,
"unitLabel": null,
"billingScheme": null,
"taxBehavior": "EXCLUSIVE",
"taxCode": null,
"createdAt": "2024-01-15T10:30:00Z"
}
}
}
Note:
- Required fields:
productId, amount, currency, type
- For
RECURRING prices, billingPeriod is required (e.g., “month”, “year”)
- For
PAY_WHAT_YOU_WANT pricing, minAmount and/or maxAmount must be provided
trialPeriodDays is only allowed for RECURRING prices
- For usage-based pricing (
usageType: METERED), unitLabel is required
amount must be greater than 0
currency must be a 3-character code (e.g., “USD”, “EUR”)
11.11 Update Price
Permissions: product.manage
Request:
mutation UpdatePrice(
$id: ID!
$amount: Decimal
$currency: String
$active: Boolean
$metadata: JSON
$nickname: String
$description: String
$pricingType: PricingType
$minAmount: Decimal
$maxAmount: Decimal
$trialPeriodDays: Int
$usageType: UsageType
$unitLabel: String
$billingScheme: BillingScheme
$taxBehavior: TaxBehavior
$taxCode: String
) {
updatePrice(
id: $id
amount: $amount
currency: $currency
active: $active
metadata: $metadata
nickname: $nickname
description: $description
pricingType: $pricingType
minAmount: $minAmount
maxAmount: $maxAmount
trialPeriodDays: $trialPeriodDays
usageType: $usageType
unitLabel: $unitLabel
billingScheme: $billingScheme
taxBehavior: $taxBehavior
taxCode: $taxCode
) {
id
amount
currency
active
nickname
description
pricingType
minAmount
maxAmount
updatedAt
}
}
Variables:
{
"id": "1",
"amount": "39.99",
"nickname": "Updated Price",
"active": false
}
Response:
{
"data": {
"updatePrice": {
"id": "1",
"amount": "39.99",
"currency": "USD",
"active": false,
"nickname": "Updated Price",
"description": "One-time purchase price",
"pricingType": "FIXED",
"minAmount": null,
"maxAmount": null,
"updatedAt": "2024-01-16T14:20:00Z"
}
}
}
Note: Only the id field is required. All other fields are optional and will only be updated if provided. The same validation rules apply as for creating prices (e.g., trial period only for recurring prices).
11.12 Delete Price
Permissions: product.manage
Request:
mutation DeletePrice($id: ID!) {
deletePrice(id: $id)
}
Variables:
Response:
{
"data": {
"deletePrice": true
}
}
Note: This performs a hard delete, permanently removing the price from the database.
Permission Matrix
| Endpoint | Merchant | Manager (Staff) | Cashier (Staff) |
|---|
login | ✅ | ✅ | ✅ |
createMerchant | ✅ | ❌ | ❌ |
createPayment | ✅ | ✅ | ✅ |
transactions | ✅ | ✅ | ✅ |
salesSummaryReport | ✅ | ✅ | ❌ |
addOrUpdateWallet | ✅ | ❌ | ❌ |
createStaff | ✅ | ❌ | ❌ |
customers | ✅ | ✅ | ❌ |
upsertCustomer | ✅ | ✅ | ❌ |
createRefundRequest | ❌ | ✅ | ❌ |
approveRefund | ❌ | ✅ | ❌ |
rejectRefund | ❌ | ✅ | ❌ |
completeRefund | ✅ | ❌ | ❌ |
refunds | ❌ | ✅ | ❌ |
refundByReference | ❌ | ✅ | ❌ |
refundSummary | ❌ | ✅ | ❌ |
products | ✅ | ✅ | ✅ |
product | ✅ | ✅ | ✅ |
productBySku | ✅ | ✅ | ✅ |
productPrices | ✅ | ✅ | ✅ |
createProduct | ✅ | ❌ | ❌ |
updateProduct | ✅ | ❌ | ❌ |
deleteProduct | ✅ | ❌ | ❌ |
archiveProduct | ✅ | ❌ | ❌ |
unarchiveProduct | ✅ | ❌ | ❌ |
createPrice | ✅ | ❌ | ❌ |
updatePrice | ✅ | ❌ | ❌ |
deletePrice | ✅ | ❌ | ❌ |
Quick Start Example (cURL)
# 1. Login
curl -X POST https://your-domain.com/graphql \
-H "Content-Type: application/json" \
-d '{
"query": "mutation { login(email: \"merchant@example.com\", password: \"SecurePass123!\") { access_token user_type } }"
}'
# 2. Create Payment (with token)
curl -X POST https://your-domain.com/graphql \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
-d '{
"query": "mutation { createPayment(amount: \"25.50\", blockchain: \"solana-devnet\", tokenSymbol: \"USDC\") { url qr_code } }"
}'
This API reference covers all available endpoints in the StableX platform. For any questions or issues, please contact the development team.