Sandbox on Solana devnet. No real funds move here. Use sk_test_ keys and a wallet set to devnet. Get devnet SOL from the Solana faucet and devnet USDC from the Circle faucet.

What Gateway does

Add a crypto payment gateway to your app on the Solana blockchain. Accept USDC, USDT, SOL, or another token of the SPL Token program (Token-2022 mints are not supported), send customers Telegram updates through @solknife_sandbox_bot, and let your backend receive signed payment callbacks.

You receive the full payment

Your business wallet receives the full customer payment in the token you choose. SolKnife takes a separate fixed SOL fee.

Verified on Solana

Gateway checks the Solana payment details before marking an order as paid, so your app does not rely on browser claims.

Simple SaaS onboarding

Start with USDC, USDT, SOL, or another token of the SPL Token program. Token-2022 mints are not supported. Connect your wallet, callback URL, and Telegram chat id.

Telegram notifications

Customers add @solknife_sandbox_bot and share a chat id, then receive payment status updates in Telegram.

App-ready callbacks

Signed callbacks let your backend update orders, subscriptions, or credits after Gateway confirms payment.

Payment flow

Create checkout. Customer pays in crypto. Your app gets the result. Your backend creates the intent after collecting the customer's Telegram chat id. The customer pays with a Solana wallet. Gateway verifies the payment before sending a signed callback to your system and a bot notification to the customer.

Create intent
POST /api/payments
x-gateway-key: sk_live_...

  {
    "checkoutReference": "order-1001",
    "customerTelegramChatId": "123456789",
    "merchantAmountRaw": "250000000",
    "merchantTokenMint": "accepted token address"
  }

Try the payment console

OpenAPI 3.1 document (openapi.json)

  1. Register your business wallet, accepted payment token, callback URL, and Telegram chat id.
  2. Store the API key and callback secret on your backend. The developer console takes the key in the browser for testing only; never ship it in your app's client code.
  3. Ask the customer to add @solknife_sandbox_bot, then create an intent with the chat id they provide.
  4. Send the customer through a Solana payment that includes your business payment and SolKnife's fixed SOL fee.
  5. Gateway finds the payment by its reference, verifies it on Solana, and confirms it. Verify the signed callback before updating app records.

Get started

Register business account
Register business account
POST /api/merchants/register

{
  "displayName": "Acme SaaS",
  "ownerWallet": "business payout wallet",
  "indexTokenMint": "accepted token address",
  "callbackUrl": "https://app.example/callback",
  "telegramChatId": "123456789"
}

Limited to 5 registrations per hour per client IP; over the limit the API returns 429 REGISTRATION_RATE_LIMITED.

One-off payments

Create hosted checkout
Create hosted checkout
POST /api/payments
x-gateway-key: sk_live_...

{
  "checkoutReference": "order-1001",
  "customerTelegramChatId": "123456789",
  "merchantAmountRaw": "250000000",
  "merchantTokenMint": "accepted token address"
}

Response:
{
  "merchantAmountRaw": "250000000",
  "gatewayFeeLamports": "1200000",
  "checkoutUrl": "https://sandbox.gate.solknife.xyz/checkout/..."
}

Send the customer to checkoutUrl. Gateway watches Solana for the transaction that carries the payment reference, verifies it at finalized commitment, marks the payment CONFIRMED, and sends the signed payment.confirmed callback. No confirm call is needed.
Checkout status
Checkout status
GET /api/checkout/{paymentId}?reference=...

Public checkout status for the hosted checkout page. Needs no API key; the reference from checkoutUrl is the access key. status moves from PENDING to CONFIRMED once Gateway finds and verifies the payment, usually within 30 seconds of the customer sending it.
Confirm payment
Confirm payment
POST /api/payments/{paymentId}/confirm
x-gateway-key: sk_live_...

{
  "signature": "solana transaction signature"
}

Gateway confirms hosted checkout payments on its own, so this call is only needed when your app sends the customer's transaction itself and wants the result right away. Verifies the transaction at finalized commitment, about 13 seconds after it is sent. Before that the request fails with PAYMENT_NOT_FOUND_ONCHAIN; retry it.

Callbacks and reporting

Callback verification
Callback verification
x-solknife-event: payment.confirmed | subscription_plan.confirmed | subscription_plan.updated_onchain | subscription.subscribe | subscription.collect | subscription.cancel | subscription.resume | subscription.past_due | subscription.expired | gateway.test
x-solknife-delivery-id: 5f0c2a8e-3b1d-4c6f-9a7e-2d4b8c1e6f30
x-solknife-timestamp: 1800000000
x-solknife-signature: hex(hmac_sha256(webhook_secret, timestamp + "." + raw_body))

{
  "eventType": "payment.confirmed",
  "customerTelegramChatId": "123456789",
  "merchantAmountRaw": "250000000",
  "gatewayFeeLamports": "1200000",
  "gatewayFeeChargedLamports": "1200000",
  "status": "CONFIRMED"
}

Subscription callbacks use eventType subscription_plan.confirmed, subscription_plan.updated_onchain, subscription.subscribe, subscription.collect, subscription.cancel, subscription.resume, subscription.past_due, or subscription.expired and include the customer reference, plan id, billing period, status, configured gateway fee, and gateway fee charged for that action.

Verify every callback before you act on it:
1. Compute the hex HMAC-SHA256 of "<x-solknife-timestamp>.<raw body>" with your webhook secret and compare it to x-solknife-signature in constant time.
2. Reject the callback when x-solknife-timestamp is more than 5 minutes (300 seconds) away from your clock.
3. Store each x-solknife-delivery-id you accept for at least 10 minutes and drop any callback whose delivery id you already processed. A manual retry from the dashboard is a new delivery with a new delivery id, so also make your handler idempotent on the payment or subscription id.

Node.js verifier:
import { createHmac, timingSafeEqual } from "node:crypto";

const TOLERANCE_SECONDS = 300;

export const verifySolknifeCallback = (secret, rawBody, headers, nowSeconds = Math.floor(Date.now() / 1000)) => {
  const timestamp = headers["x-solknife-timestamp"] ?? "";
  const signature = headers["x-solknife-signature"] ?? "";
  if (!/^\d+$/.test(timestamp)) return false;
  if (Math.abs(nowSeconds - Number(timestamp)) > TOLERANCE_SECONDS) return false;
  const expected = Buffer.from(createHmac("sha256", secret).update(`${timestamp}.${rawBody}`).digest("hex"), "hex");
  const received = Buffer.from(signature, "hex");
  return received.length === expected.length && timingSafeEqual(received, expected);
};
Payment analytics summary
Payment analytics summary
GET /api/analytics/summary
x-gateway-key: sk_live_...

Returns payment counts, confirmed gateway fee lamports including subscription collect fees, callback health, and indexed token count.
Callback delivery history
Callback delivery history
GET /api/webhooks
x-gateway-key: sk_live_...

Returns the latest callback attempts with event type, status, HTTP code, and target URL.
Retry callback delivery
Retry callback delivery
POST /api/webhooks/{deliveryId}/retry
x-gateway-key: sk_live_...

Creates a fresh callback delivery attempt for payment.confirmed and stored subscription callback events.
Retries and test callbacks share a limit of 10 per minute per merchant; over the limit the API returns 429 WEBHOOK_RATE_LIMITED.

Subscription plans

Create subscription plan
Create subscription plan
POST /api/subscription-plans
x-gateway-key: sk_live_...

{
  "planReference": "starter-monthly",
  "displayName": "Starter monthly",
  "amountRaw": "49000000",
  "periodSeconds": 2592000,
  "tokenMint": "accepted token address",
  "pullerWallet": "optional recurring collection wallet",
  "metadataUri": "https://app.example/plan.json"
}
Publish subscription plan transaction
Publish subscription plan transaction
POST /api/subscription-plans/{planId}/transactions/create-plan
x-gateway-key: sk_live_...

{
  "account": "business payout wallet"
}

Returns an unsigned base64 transaction for the business wallet to publish the Solana subscription plan.
Confirm subscription plan
Confirm subscription plan
POST /api/subscription-plans/{planId}/confirm
x-gateway-key: sk_live_...

{
  "signature": "solana transaction signature"
}

Verifies the create-plan transaction, marks the plan ACTIVE, and sends a signed subscription_plan.confirmed callback. Gateway reads the transaction at finalized commitment, about 13 seconds after it is sent; before that the request fails with a not-found error and should be retried.
Update on-chain plan transaction
Update on-chain plan transaction
POST /api/subscription-plans/{planId}/transactions/update-plan
x-gateway-key: sk_live_...

{
  "account": "business payout wallet",
  "onchainStatus": "sunset",
  "endTs": "1782000000"
}

Returns an unsigned base64 transaction for the business wallet to restore an on-chain plan or sunset it from new subscribers. Use "active" without endTs to restore the on-chain plan.
Use Gateway pause, resume, and archive endpoints to control whether the SaaS app offers the plan to new customers.
Confirm on-chain plan update
Confirm on-chain plan update
POST /api/subscription-plans/{planId}/confirm
x-gateway-key: sk_live_...

{
  "action": "update-plan",
  "signature": "solana transaction signature",
  "onchainStatus": "sunset",
  "endTs": "1782000000"
}

Verifies the update-plan transaction, records the signature, and sends a signed subscription_plan.updated_onchain callback. Use active without endTs to confirm an on-chain restore. Gateway reads the transaction at finalized commitment, about 13 seconds after it is sent; before that the request fails with a not-found error and should be retried.
The Gateway plan status is still controlled by pause, resume, and archive endpoints.
Pause subscription plan
Pause subscription plan
POST /api/subscription-plans/{planId}/pause
x-gateway-key: sk_live_...

Pauses an ACTIVE subscription plan. New customer subscriptions and collection workers should stop using a paused plan until it is resumed. Existing customer records remain stored in Gateway.
Resume subscription plan
Resume subscription plan
POST /api/subscription-plans/{planId}/resume
x-gateway-key: sk_live_...

Resumes a paused subscription plan so new customer subscriptions and due collection workers can use it again.
Archive subscription plan
Archive subscription plan
POST /api/subscription-plans/{planId}/archive
x-gateway-key: sk_live_...

Archives a subscription plan when the offer should no longer be sold. Archived plans stay available in records and reports, but new customer subscriptions and collection workers should stop using them.

Hosted subscription checkout

Create customer subscription
Create customer subscription
POST /api/subscriptions
x-gateway-key: sk_live_...

{
  "planId": "subscription plan id",
  "customerReference": "cus_1001",
  "customerTelegramChatId": "123456789",
  "subscriberWallet": "customer Solana wallet"
}

Requires an ACTIVE subscription plan. Publish and confirm the plan before opening customer subscriptions.
customerReference is idempotent per plan, so the same SaaS customer can hold separate subscriptions for different plans or add-ons.
The customer wallet is required because Gateway derives the on-chain subscription account before activation.
Hosted subscription checkout
Hosted subscription checkout
Response:
{
  "checkoutUrl": "https://sandbox.gate.solknife.xyz/subscription-checkout/..."
}
Hosted wallet setup transaction
Hosted wallet setup transaction
POST /api/subscription-checkout/{subscriptionId}/transactions/init-authority?reference=cus_1001

{
  "account": "customer Solana wallet"
}

Hosted checkout route. Returns an unsigned base64 wallet setup transaction without requiring the merchant Gateway API key.
Hosted subscribe transaction
Hosted subscribe transaction
POST /api/subscription-checkout/{subscriptionId}/transactions/subscribe?reference=cus_1001

{
  "account": "customer Solana wallet",
  "expectedSubscriptionAuthorityInitId": "1"
}

Hosted checkout route. Returns an unsigned base64 subscribe transaction scoped to the customer reference on the checkout URL.
Hosted cancel transaction
Hosted cancel transaction
POST /api/subscription-checkout/{subscriptionId}/transactions/cancel?reference=cus_1001

{
  "account": "customer Solana wallet"
}

Hosted checkout route. Returns an unsigned base64 cancel transaction for the customer wallet without requiring the merchant Gateway API key.
Hosted resume transaction
Hosted resume transaction
POST /api/subscription-checkout/{subscriptionId}/transactions/resume?reference=cus_1001

{
  "account": "customer Solana wallet"
}

Hosted checkout route. Returns an unsigned base64 resume transaction for a canceled subscription before the current billing period ends.
Hosted subscription confirmation
Hosted subscription confirmation
POST /api/subscription-checkout/{subscriptionId}/confirm?reference=cus_1001

{
  "action": "subscribe | cancel | resume",
  "signature": "solana transaction signature"
}

Verifies the customer subscribe, cancel, or resume signature, updates the subscription, sends the signed callback, and notifies the customer chat in Telegram. Gateway reads the transaction at finalized commitment, about 13 seconds after it is sent; before that the request fails with a not-found error and should be retried.

Customer subscriptions from your backend

Prepare customer wallet transaction
Prepare customer wallet transaction
POST /api/subscriptions/{subscriptionId}/transactions/init-authority
x-gateway-key: sk_live_...

{
  "account": "customer Solana wallet"
}

Returns an unsigned base64 transaction that prepares the customer's wallet for recurring Solana payments.
Create customer subscribe transaction
Create customer subscribe transaction
POST /api/subscriptions/{subscriptionId}/transactions/subscribe
x-gateway-key: sk_live_...

{
  "account": "customer Solana wallet",
  "expectedSubscriptionAuthorityInitId": "1"
}

Returns an unsigned base64 transaction for the customer wallet to subscribe to the plan.
expectedSubscriptionAuthorityInitId is optional. Leave it out to let Gateway read the customer's SubscriptionAuthority from Solana.
Cancel customer subscription transaction
Cancel customer subscription transaction
POST /api/subscriptions/{subscriptionId}/transactions/cancel
x-gateway-key: sk_live_...

{
  "account": "customer Solana wallet"
}

Returns an unsigned base64 transaction that lets the customer cancel the subscription on Solana.
Customers can still cancel subscriptions on paused or archived plans, so businesses can retire offers without trapping existing customers.
Resume customer subscription transaction
Resume customer subscription transaction
POST /api/subscriptions/{subscriptionId}/transactions/resume
x-gateway-key: sk_live_...

{
  "account": "customer Solana wallet"
}

Returns an unsigned base64 transaction that lets the customer resume a canceled subscription on Solana before the current period ends. Gateway keeps the existing billing window instead of restarting billing.
Confirm subscription action
Confirm subscription action
POST /api/subscriptions/{subscriptionId}/confirm
x-gateway-key: sk_live_...

{
  "action": "subscribe | collect | cancel | resume",
  "signature": "solana transaction signature"
}

Verifies the matching subscription transaction, updates the customer subscription status or next billing date, sends a signed subscription callback, and notifies the customer chat in Telegram. Gateway reads the transaction at finalized commitment, about 13 seconds after it is sent; before that the request fails with a not-found error and should be retried.
Expire canceled subscription
Expire canceled subscription
POST /api/subscriptions/{subscriptionId}/expire
x-gateway-key: sk_live_...

Expires a canceled customer subscription after the current period ends. This sends a subscription.expired callback and Telegram notification, but does not build a Solana transaction or charge a gateway fee. Retries for an already EXPIRED subscription return the stored subscription without sending another subscription.expired callback or Telegram message.

Collecting subscription payments

List due subscriptions
List due subscriptions
GET /api/subscriptions/due
x-gateway-key: sk_live_...

Returns active or past due customer subscriptions whose active plan is ready for collection. Use each id to build a collect transaction from your backend worker.
Collection worker queue
Collection worker queue
GET /api/subscriptions/due/queue
x-gateway-key: sk_live_...

Returns due collection worker items with subscription, plan, pullerWallet, collectTransactionPath, confirmPath, and pastDuePath. For each item, build the collect transaction with the returned pullerWallet, send it on Solana, then confirm the signature through confirmPath. Use pastDuePath when your worker cannot collect after the billing date.
Collect subscription payment transaction
Collect subscription payment transaction
POST /api/subscriptions/{subscriptionId}/transactions/collect
x-gateway-key: sk_live_...

{
  "account": "subscription puller wallet"
}

Returns an unsigned base64 transaction that collects the next due subscription payment: the merchant receives the full subscription token amount, and the plan's puller wallet pays SolKnife 1,200,000 lamports. The signer must be the plan's puller wallet, which is the merchant wallet by default. Gateway confirms a collect only when it carries that fee.
Past due customer subscriptions use the same collect action. After the collect signature is confirmed, Gateway marks the customer subscription ACTIVE again and advances the next billing date.
Mark subscription past due
Mark subscription past due
POST /api/subscriptions/{subscriptionId}/past-due
x-gateway-key: sk_live_...

Marks an active customer subscription PAST_DUE after the next billing date when your backend worker could not collect the payment. Use this only for subscriptions on active plans. This sends a subscription.past_due callback and Telegram notification, but does not build a Solana transaction or charge a gateway fee. Retries for an already PAST_DUE subscription return the stored subscription without sending another callback or Telegram message.

Subscription status

Gateway now stores Solana subscription plans, customer subscription records, and an unsigned transaction flow for publishing plans, preparing a customer wallet, subscribing, collecting each due payment, canceling, resuming, and updating on-chain plan status. Confirm the signed Solana customer transactions through Gateway so the plan status, customer subscription status, and next billing date stay in sync with the blockchain.

Each collect that Gateway confirms carries the fixed 0.0012 SOL gateway fee. The puller wallet that signs the collect pays it, and the puller is your business wallet by default. The customer pays only the subscription amount.

Test in the sandbox

The sandbox at https://sandbox.gate.solknife.xyz runs the same Gateway on Solana devnet. No real funds move there. Sandbox accounts are separate from production accounts, so register your business there first.

  1. Register on the sandbox. Its API keys start with sk_test_. The sandbox rejects sk_live_ keys, and production rejects sk_test_ keys.
  2. Set the paying wallet to devnet. Get devnet SOL from the Solana faucet and devnet USDC from the Circle faucet.
  3. Create payments and subscription plans as you would on production. Checkouts, confirmations, and signed callbacks work the same way.
  4. To go live, register again on https://gate.solknife.xyz, then change the base URL and the API key in your backend. Your sk_live_ key and its callback secret replace the sandbox ones.

About Gateway

What Gateway does, who it is for, and how it turns Solana payments into backend events.

Security model

How direct wallet settlement, server-side API keys, and signed callbacks protect your flow.

Disclaimer

Clear boundaries for custody, refunds, compliance, availability, and payment finality.