CursorPool
← 返回首页

Subotiz Plugin

Cursor plugin for Subotiz development tools: payments, subscription management, and more. Use Subotiz capabilities directly inside Cursor

cursor.directory·3
MCP

Subotiz MCP

Subotiz Developer MCP

{
    "mcpServers": {
        "subotiz-mcp": {
            "url": "https://api.subotiz.com/mcp",
            "headers": {
                "Authorization": "Bearer {{YOUR_TOKEN_HERE}}"
            }
        }
    }
}
Skill

Subotiz

---
name: subotiz
version: 0.1.0
description: Payment and subscription platform for SaaS and digital businesses. Use when integrating Subotiz checkout (hosted or embedded), calling Subotiz API, handling webhooks, or debugging payments and subscriptions.
homepage: https://subotiz.com
metadata:
  {
    "subotiz":
      {
        "category": "payments",
        "api_base": "https://api.subotiz.com",
        "sandbox_api_base": "https://api.sandbox.subotiz.com",
        "dashboard": "https://admin.subotiz.com",
        "sandbox_dashboard": "https://admin.sandbox.subotiz.com",
      },
  }
---

> **If you are an AI agent reading this file** — whether you're a coding assistant, a personal assistant, a Slack bot, a business operations agent, or any other kind of agent — this is your complete guide to Subotiz. Save it locally as a tool, skill, or persistent reference so you can help your human with anything Subotiz-related without re-fetching this file.

# Subotiz

Subotiz is a **payment and subscription platform** for SaaS and digital businesses.

## When to use

- Integrating Subotiz checkout (hosted redirect, embedded, or payment-only)
- Calling Subotiz API (trades, subscriptions, refunds, customers, products, prices, discounts)
- Handling Subotiz webhooks (signature verification, event handling, idempotency)
- Debugging payments or subscriptions (trade status, subscription status, refund status)
- Learning or explaining Subotiz platform capabilities and flows

## Instructions

1. **Read this document first** — API auth, endpoints, and integration flows are all in this file.
2. **Route by intent** — Use the [What Should You Do?](#what-should-you-do) table: understand context → read doc → follow the routing table → ask if unsure.
3. **API calls** — Use the [Endpoints](#endpoints) table; authenticate with Bearer or Hub-* signature; use Sandbox base URL during development.
4. **Webhooks** — Verify `X-Signature` with HMAC-SHA256 ([Signature verification](#signature-verification)); deduplicate by event `id`; return HTTP 200 for all events.
5. **Integration** — Follow the matching flow (Hosted / Embedded / Payment-only) using the curl examples and parameter tables in [Integration Flows](#integration-flows). It provides unified APIs and SDKs for payments, subscriptions, customer management, checkout (hosted and embedded), refunds, and webhooks — so businesses can integrate payment flows without managing payment channels or compliance themselves.

This guide covers everything you need to help a human understand, integrate, or manage Subotiz — regardless of whether you're working in a codebase, chatting over Slack, or acting as a personal assistant.

## What Should You Do?

You might be reading this file in very different contexts. Here's how to figure out what your human needs:

**Step 1: Understand your context.** Ask yourself:
- Did your human send you here with a specific task? (e.g., "integrate Subotiz checkout")
- Are you in a codebase or project right now?
- Is your human exploring Subotiz for the first time?
- Do they already have a Subotiz merchant account and need API/webhook help?

**Step 2: Read this entire file first.** No matter what your human needs — integration, debugging, or just learning — **read through this whole document before diving into a specific path.** Understanding the full Subotiz context (API auth, checkout flows, webhooks, subscription lifecycle) will make you genuinely helpful. This is not a file to skim — it's your foundation for being a competent Subotiz assistant.

**Step 3: Route to the right workflow.**

| If your human wants to...              | Do this |
|----------------------------------------|---------|
| **Understand what Subotiz is**        | Start with [Platform Overview](#platform-overview) and [Features](#features). |
| **Integrate payments/checkout**        | Walk through [Integration Flows](#integration-flows) and [SDK](#sdk). Ask: Hosted, Embedded, or Payment-only? |
| **Call the API**                       | Use [API Overview](#api-overview) for auth, base URLs, and endpoint list. |
| **Handle webhooks**                    | Follow [Webhooks](#webhooks) — includes event table, signature verification code, and payload examples. |
| **Debug a payment or subscription**    | Use API to look up trades, subscriptions, refunds; check webhook events; see [Status Enumerations](#status-enumerations). |
| **Just learn and explore**            | Walk through this doc section by section. Let them ask questions. |

**Step 4: Ask questions when you're unsure.** Good questions:
- "Do you already have a Subotiz merchant account, or are you exploring for the first time?"
- "Are you integrating Hosted Checkout, Embedded Checkout, or Payment-only (API/SDK)?"
- "Do you need to create checkout sessions from your backend, or only handle webhooks?"

### Example prompts humans might give you

| What the human says | What they likely need |
|---------------------|------------------------|
| "Help me integrate Subotiz checkout" | Go to [Integration Flows](#integration-flows). Ask Hosted vs Embedded vs Payment. |
| "Help me understand what Subotiz does" | Start with [Platform Overview](#platform-overview). Keep it conversational. |
| "Help me with Subotiz API / webhooks" | [API Overview](#api-overview) + [Webhooks](#webhooks). |
| "Debug my Subotiz payment" | Ask for trade_id or order_id. Use [Get Trade](#endpoints) API. Check [Status Enumerations](#status-enumerations). |

---

## Reference

| Resource            | URL |
|---------------------|-----|
| Developer Center    | <https://developer.subotiz.com> |
| API Reference (v1.0) | <https://developer.subotiz.com/v1.0-en-us/reference/overview-1> |
| Introduction (API)  | <https://developer.subotiz.com/reference/introduction-1> |
| Authentication (Bearer) | <https://developer.subotiz.com/reference/authentication-1> |
| Authentication (Signature) | <https://developer.subotiz.com/reference/authentication-2> |
| Webhooks            | <https://developer.subotiz.com/reference/introduction-2> |
| Subotiz SDK         | <https://developer.subotiz.com/reference/subotiz-sdk> |
| Quick Start         | <https://developer.subotiz.com/reference/quick-start> |
| Hosted Checkout     | <https://developer.subotiz.com/reference/hosted> |
| Embedded Checkout   | <https://developer.subotiz.com/reference/embedded-form> |
| Embedded Payment    | <https://developer.subotiz.com/reference/embedded-form-payment> |
| Dashboard (Production) | <https://admin.subotiz.com> |
| Dashboard (Sandbox) | <https://admin.sandbox.subotiz.com> |

---

## Platform Overview

### What Subotiz handles

- **Payments** — Credit/debit cards, Google Pay, Apple Pay, PayPal via hosted or embedded checkout, or payment-only API.
- **Checkout** — Hosted (redirect) or Embedded (iframe/component) checkout; create session via API, then redirect or mount SDK.
- **Subscriptions** — Multi-plan pricing, trials, discounts, usage-based billing, invoices, automatic renewals.
- **Customers & Trades** — Customer profiles auto-synced from checkout, trade orders, refunds.
- **Webhooks** — Real-time events for subscription lifecycle, trade status, invoices, refunds.
- **Fraud & Compliance** — PCI DSS Level 1, TLS 1.2+, GDPR/CCPA ready.

### Features

| Feature           | Description |
|-------------------|-------------|
| Hosted Checkout   | Redirect to Subotiz payment page; minimal front-end work. |
| Embedded Checkout | Full SaaS checkout (product, price, payment) embedded in your site via SDK. |
| Payment mode      | Only payment engine; you control UI and call API/SDK. |
| Subscription API  | Plans, trials, renewals, cancel, pause, resume, usage-based billing. |
| Customer & Trade  | Customer CRUD, trade list/get, refund create/list. |
| Webhooks          | Subscription, invoice, trade, refund events with HMAC-SHA256 signature verification. |
| Customer portal   | Self-service billing portal for customers. |
| Discount codes    | Create and apply discounts to checkout sessions. |

---

## Environments

| Environment | Dashboard | API Base URL | Purpose |
|-------------|-----------|-------------|---------|
| **Production** | `https://admin.subotiz.com` | `https://api.subotiz.com` | Live transactions, real money |
| **Sandbox** | `https://admin.sandbox.subotiz.com` | `https://api.sandbox.subotiz.com` | Development & testing, no real money |

**Always start with Sandbox.** Test and production data are completely isolated. Use the sandbox API base URL during development, then switch to production when ready to go live.

For SDK: use `environment: 'SANDBOX'` or `environment: 'PRODUCTION'`.

---

## API Overview

### Authentication (two options)

#### Option 1 — Bearer API Key (OpenAPI)

Get your API key from the merchant dashboard: **Settings > Developer Settings**.

```bash
curl -X GET "https://api.subotiz.com/openapi/v1/orders" \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxx"
```

- Key rotation supported with configurable grace period (default 3 minutes; both old and new keys valid during grace).
- Auth failure returns HTTP `401`:

```json
{
  "code": "unauthorizedError",
  "message": "ApiKey authentication is required"
}
```

#### Option 2 — API Signature (Hub-* headers)

Required headers: `Hub-Access-No`, `Hub-Timestamp`, `Hub-Signature`, `Content-Type`, `Request-Id`.

**Signature construction:**

1. Build signature string: `"METHOD\nPATH+QUERY\nTIMESTAMP\nBODY\n"` (each part ends with `\n`, including after BODY)
2. Sign with HMAC-SHA256 using `access_secret` as key

**Go example:**

```go
func CalcSignature(secret string) string {
    str := "GET\n/api/v1/payment/query?out_trans_id=2024123232323\n1754562236502\n\n"
    mac := hmac.New(sha256.New, []byte(secret))
    mac.Write([]byte(str))
    return hex.EncodeToString(mac.Sum(nil))
}
```

**Python example:**

```python
import hmac
import hashlib

def calc_signature(secret: str, signature_string: str) -> str:
    mac = hmac.new(
        key=secret.encode('utf-8'),
        msg=signature_string.encode('utf-8'),
        digestmod=hashlib.sha256
    )
    return mac.hexdigest()

# Usage
signature_string = "GET\n/api/v1/payment/query?out_trans_id=2024123232323\n1754562236502\n\n"
result = calc_signature("your_access_secret", signature_string)
```

### Common request rules

- All API requests must use **HTTPS**.
- All requests must be **authenticated** (Bearer or Signature).
- Request and response format: **JSON**.
- **Prices are strings with two decimal places** (e.g. `"30.00"` = $30.00), NOT in cents.

### Endpoints

| Method | Path | Description | Docs |
|--------|------|-------------|------|
| `POST` | `/api/v1/session` | Create Checkout Session | [Link](https://developer.subotiz.com/reference/v1-checkout-session-create-checkout-session) |
| `POST` | `/api/v1/trade` | Create Trade | [Link](https://developer.subotiz.com/reference/v1-trade-create-trade) |
| `GET` | `/api/v1/trade/{trade_id}` | Get Trade | [Link](https://developer.subotiz.com/reference/v1-trade-get-trade) |
| `GET` | `/api/v1/trades` | List Trades | [Link](https://developer.subotiz.com/reference/v1-trade-list-trade) |
| `GET` | `/api/v1/subscription/{id}` | Get Subscription | [Link](https://developer.subotiz.com/reference/v1-subscription-get-subscription) |
| `POST` | `/api/v1/subscription/{id}/cancel` | Cancel Subscription | [Link](https://developer.subotiz.com/reference/v1-subscription-cancel-subscription) |
| `POST` | `/api/v1/subscription/{id}/resume` | Resume Subscription | [Link](https://developer.subotiz.com/reference/v1-subscription-resume-subscription) |
| `POST` | `/api/v1/subscription/{id}/renewal` | Renewal Subscription | [Link](https://developer.subotiz.com/reference/v1-subscription-renewal-subscription) |
| `POST` | `/api/v1/subscription/{id}/revoke-cancel` | Revoke Cancel | [Link](https://developer.subotiz.com/reference/v1-subscription-revoke-cancel-subscription) |
| `GET` | `/api/v1/subscription/{id}/usage` | Get Usage | [Link](https://developer.subotiz.com/reference/v1-subscription-get-subscription-usage) |
| `POST` | `/api/v1/subscription/{id}/usage` | Record Usage | [Link](https://developer.subotiz.com/reference/v1-subscription-record-subscription-usage) |
| `POST` | `/api/v1/refund` | Create Refund | [Link](https://developer.subotiz.com/reference/v1-refund-create-refund) |
| `GET` | `/api/v1/refund/{refund_id}` | Get Refund | [Link](https://developer.subotiz.com/reference/v1-refund-get-refund) |
| `GET` | `/api/v1/refunds` | List Refunds | [Link](https://developer.subotiz.com/reference/v1-refund-list-refund) |
| `GET` | `/api/v1/customer/{id}` | Get Customer | [Link](https://developer.subotiz.com/reference/v1-customer-get-customer) |
| `GET` | `/api/v1/customers` | List Customers | [Link](https://developer.subotiz.com/reference/v1-customer-list-customer) |
| `PUT` | `/api/v1/customer/{id}` | Update Customer | [Link](https://developer.subotiz.com/reference/v1-customer-update-customer) |
| `DELETE` | `/api/v1/customer/{id}` | Delete Customer | [Link](https://developer.subotiz.com/reference/v1-customer-delete-customer) |
| `GET` | `/api/v1/products` | List Products | [Link](https://developer.subotiz.com/reference/v1-product-list-product) |
| `GET` | `/api/v1/product/{id}/versions` | List Product Versions | [Link](https://developer.subotiz.com/reference/v1-product-list-product-version) |
| `POST` | `/api/v1/product/{id}/status` | Change Product Status | [Link](https://developer.subotiz.com/reference/v1-product-change-product-status) |
| `GET` | `/api/v1/prices` | List Prices | [Link](https://developer.subotiz.com/reference/v1-price-list-price) |
| `GET` | `/api/v1/price/{id}/versions` | List Price Versions | [Link](https://developer.subotiz.com/reference/v1-price-list-price-version) |
| `GET` | `/api/v1/discounts` | List Discounts | [Link](https://developer.subotiz.com/reference/v1-discount-list-discount) |
| `GET` | `/api/v1/discount/{id}` | Get Discount | [Link](https://developer.subotiz.com/reference/v1-discount-get-discount) |
| `POST` | `/api/v1/discount/{id}/end` | End Discount | [Link](https://developer.subotiz.com/reference/v1-discount-end-discount) |
| `GET` | `/api/v1/invoice/{id}` | Get Invoice | [Link](https://developer.subotiz.com/reference/v1-invoice-get-invoice) |
| `POST` | `/api/v1/customer-portal/auth` | Customer Portal Auth | [Link](https://developer.subotiz.com/reference/v1-customer-portal-api-auth) |
| `GET` | `/api/v1/webhooks/endpoints` | List Webhook Endpoints | [Link](https://developer.subotiz.com/reference/v1-webhook-list-endpoint) |
| `GET` | `/api/v1/webhooks/events` | List Webhook Events | [Link](https://developer.subotiz.com/reference/v1-webhook-list-webhook-event) |

---

## Integration Flows

### Flow 1: Hosted Checkout (redirect)

The simplest integration — redirect customers to a Subotiz-hosted payment page.

**Step 1** — Create products and pricing in the Subotiz dashboard.

**Step 2** — Create a Checkout Session from your server:

```bash
curl --location 'https://api.subotiz.com/api/v1/session' \
  --header 'Content-Type: application/json' \
  --header 'Hub-Timestamp: 1756513740897' \
  --header 'Hub-Access-No: 77d52a21dc032b4' \
  --header 'Request-Id: 9913dca8-90f8-4e20-98bc-565f0222ffa8' \
  --header 'Hub-Signature: 75c8bfd1cac3c68d2bcf05bc36c913e36577d8d97bc08fba9ce67551808480eb' \
  --data-raw '{
    "access_no":       "77d52a21dc032b4",
    "sub_merchant_id": "2816433",
    "order_id":        "123e4567-zzzaa20daw11a",
    "payer_id":        "customer_id_0012",
    "line_items": [
      {
        "price_id": "543321366326164797",
        "quantity": "1"
      }
    ],
    "email":           "user@example.com",
    "integration_method": "hosted",
    "cancel_url": "https://yourapp.com/cancel",
    "return_url": "https://yourapp.com/success"
  }'
```

**Checkout Session key parameters:**

| Parameter | Required | Description |
|-----------|----------|-------------|
| `access_no` | Yes | Your platform's access number |
| `sub_merchant_id` | Yes | Merchant ID |
| `order_id` | Yes | Your platform's order ID (for webhook correlation) |
| `line_items` | Yes | Array of `{ price_id, quantity }` |
| `email` | No | Pre-fill customer email |
| `payer_id` | No | Your platform's customer ID |
| `integration_method` | Yes | `"hosted"` or `"embedded"` |
| `mode` | No | `"checkout"` (with products) or `"payment"` (amount only) |
| `return_url` | Yes | Redirect after successful payment |
| `cancel_url` | Yes (hosted) | Redirect if customer cancels |
| `redirect_on_completion` | No | `"always"` (default) or `"if_required"` (for embedded) |
| `metadata` | No | Key-value pairs (key ≤ 40 bytes, value ≤ 500 bytes, total JSON ≤ 1024 bytes) |

**Step 3** — Redirect customer to the session URL returned by the API.

**Step 4** — Handle `v2.trades.succeeded` webhook to activate access or update order status.

### Flow 2: Embedded Checkout (SDK)

Embed the full checkout experience in your site.

**Step 1** — Create products and pricing in the dashboard.

**Step 2** — Create Checkout Session from your server (same API as hosted, but `integration_method: "embedded"`):

```bash
curl --location 'https://api.subotiz.com/api/v1/session' \
  --header 'Content-Type: application/json' \
  --header 'Hub-Timestamp: 1755695704350' \
  --header 'Hub-Access-No: 77d52a21dc032b4' \
  --header 'Request-Id: dd7fb126-be31-4144-a1af-e4bf4203eb92' \
  --header 'Hub-Signature: 4830f629ff065be043c4f4b2f908ef6418d18e4ef9d6a288313ded21f1b0ec13' \
  --data-raw '{
    "access_no":       "77d52a21dc032b4",
    "sub_merchant_id": "2816433",
    "order_id":        "123e4567-e89b-12-a456-426622201a",
    "payer_id":        "customer_id_001",
    "email":           "user@example.com",
    "line_items": [
      {
        "price_id": "543321366326164797",
        "quantity": "1"
      }
    ],
    "return_url":   "https://yourapp.com/success",
    "cancel_url":   "https://yourapp.com/cancel",
    "mode": "checkout",
    "integration_method": "embedded",
    "redirect_on_completion": "if_required"
  }'
```

**Step 3** — Load SDK and mount checkout on your page:

```html
<script src="https://checkout.subotiz.com/static/subotiz/v0/subotiz.js"></script>
<div id="checkout-container"></div>
```

```javascript
const subotiz = window.Subotiz();

const checkout = await subotiz.initEmbeddedCheckout({
    fetchSessionUrl: async () => {
        const response = await fetch('/api/session');
        const data = await response.json();
        return data.sessionUrl;
    },
    environment: 'SANDBOX', // 'SANDBOX' | 'PRODUCTION'
    onComplete: () => {
        console.log('Payment completed!');
    }
});

checkout.mount('#checkout-container');
```

SDK parameters:

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `fetchSessionId` | `() => Promise<string>` | One of two | Returns Checkout Session ID |
| `fetchSessionUrl` | `() => Promise<string>` | One of two | Returns Checkout Session URL |
| `environment` | `'SANDBOX' \| 'PRODUCTION'` | No | Default: `'SANDBOX'` |
| `onComplete` | `() => void` | No | Fires when payment completes (only if `redirect_on_completion` was `"if_required"`) |

Unmount: `checkout.unmount()`

**Step 4** — Handle webhook (`v2.trades.succeeded`) with `order_id` to sync your system.

### Flow 3: Payment-only (API / SDK)

You control the entire UI; use Subotiz only as a payment engine. Set `mode: "payment"` in the session and skip `line_items`. See: [Embedded Payment](https://developer.subotiz.com/reference/embedded-form-payment).

### Flow 4: Subscriptions and renewals

1. Create subscription products and pricing in the dashboard.
2. Customer pays via checkout — initial payment with `payment_mode: "subscription"`.
3. On `v2.trades.succeeded`, save the `payment_token` from the event data.
4. For renewals: use [Create Trade](https://developer.subotiz.com/reference/v1-trade-create-trade) API with `payment_token` and `payment_mode: "recurring_payment"`.
5. Handle subscription lifecycle events (see [Webhooks](#webhooks)).

### Flow 5: Customer support (lookup trades, refunds, subscriptions)

```bash
# Get a trade by ID
curl -X GET "https://api.subotiz.com/api/v1/trade/{trade_id}" \
  -H "Authorization: Bearer sk_live_xxx"

# List trades
curl -X GET "https://api.subotiz.com/api/v1/trades" \
  -H "Authorization: Bearer sk_live_xxx"

# Create a refund
curl -X POST "https://api.subotiz.com/api/v1/refund" \
  -H "Authorization: Bearer sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"trade_id": "572677233903157186", "amount": "15.57", "reason": "Customer request"}'

# Get subscription
curl -X GET "https://api.subotiz.com/api/v1/subscription/{id}" \
  -H "Authorization: Bearer sk_live_xxx"

# Cancel subscription
curl -X POST "https://api.subotiz.com/api/v1/subscription/{id}/cancel" \
  -H "Authorization: Bearer sk_live_xxx"

# Customer portal auth (generates portal URL)
curl -X POST "https://api.subotiz.com/api/v1/customer-portal/auth" \
  -H "Authorization: Bearer sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"customer_id": "547766341013094363"}'
```

---

## Status Enumerations

### Trade statuses

| Status | Description |
|--------|-------------|
| `requires_payment_method` | Initial state — customer has not completed payment |
| `processing` | Payment is being processed asynchronously |
| `payment_failed` | Payment declined (insufficient funds, card verification failed, etc.) — customer can retry |
| `succeeded` | Payment successful |
| `closed` | Closed — trade order will not change (e.g., renewal failed after retries, or no payment for 7+ days) |

### Trade refund statuses

| Status | Description |
|--------|-------------|
| `no_refund` | No refunds issued |
| `partially_refunded` | Partially refunded |
| `refunded` | Fully refunded |

### Subscription statuses

| Status | Description |
|--------|-------------|
| `init` | Pending activation |
| `trial` | Trial period |
| `active` | Active |
| `paused` | Paused |
| `past_due` | Payment overdue, retrying |
| `unpaid` | Unpaid after max retries |
| `canceled` | Terminated |
| `incomplete` | Incomplete |

### Invoice statuses

| Status | Description |
|--------|-------------|
| `open` | Initiated/Open |
| `success` | Paid |
| `failed` | Payment failed |
| `refunded` | Fully refunded |
| `partially_refunded` | Partially refunded |

### Invoice types

| Type | Description |
|------|-------------|
| `initial` | Initial payment |
| `trial` | Trial period |
| `renewal` | Renewal |
| `refund` | Refund |
| `upgrade` | Subscription upgrade |

### Refund statuses

| Status | Description |
|--------|-------------|
| `pending` | Processing |
| `succeeded` | Refund succeeded |
| `failed` | Refund failed |

---

## Webhooks

Subotiz sends HTTPS POST requests with JSON event payloads to your configured endpoint. Use webhooks to keep your system in sync with payment status, subscription lifecycle, invoices, and refunds.

### Webhook event list (v2)

| Event Name | Event Type | Trigger Condition | Access Impact |
|------------|------------|-------------------|---------------|
| Trial Period Expiring Soon | `v2.subscription.trial_period_expiring` | Trial expires in 3 days | Send reminder |
| First Subscription Activated | `v2.subscription.first` | Subscription enters trial/active for the first time | **Grant access** |
| Subscription Canceled | `v2.subscription.canceled` | Subscription terminated | **Revoke access** |
| Subscription Changed | `v2.subscription.price_changed` | Subscription upgraded/downgraded | Update plan |
| Subscription Paused | `v2.subscription.paused` | Subscription paused | **Revoke access** |
| Subscription Resumed | `v2.subscription.resumed` | Subscription resumed | **Grant access** |
| Subscription Past Due | `v2.subscription.past_due` | Payment overdue, retrying | Send payment reminder |
| Subscription Unpaid | `v2.subscription.unpaid` | Unpaid after max retries | **Revoke access** |
| Cancellation Revoked | `v2.subscription.cancellation_revoked` | Cancellation revoked | **Grant access** |
| Cancellation Requested | `v2.subscription.cancellation_requested` | Cancellation requested | Retention opportunity |
| Invoice Paid | `v2.invoice.paid` | Invoice paid successfully | Sync invoice status |
| Invoice Payment Failed | `v2.invoice.payment_failed` | Invoice payment failed (final failure, not per-retry) | Alert customer |
| Invoice Refunded | `v2.invoice.refunded` | Subscription trade refunded | Sync refund status |
| Trade Created | `v2.trades.created` | Trade order created | — |
| Trade Succeeded | `v2.trades.succeeded` | Payment successful | **Grant access / fulfill order** |
| Trade Payment Failed | `v2.trades.payment_failed` | Payment failed | Alert customer |
| Refund Succeeded | `v2.refunds.succeeded` | Refund processed successfully | Sync refund status |
| Refund Failed | `v2.refunds.failed` | Refund attempt failed | Retry or investigate |

### Webhook request headers

| Header | Description |
|--------|-------------|
| `X-Timestamp` | Millisecond timestamp (used in signature) |
| `X-Access-No` | Your `access_no` |
| `X-Signature` | HMAC-SHA256 signature |
| `Content-Type` | `application/json` |

### Webhook payload structure

```json
{
  "id": "572677246926464036",
  "type": "v2.trades.succeeded",
  "created": "2025-10-28T06:54:55Z",
  "data": {
    // event-specific business object
  }
}
```

### Signature verification

Verify the `X-Signature` header against the raw request body before processing any event.

**Signature string format:** `${X-Timestamp}.${raw_body}`

**Go example:**

```go
func CalcWebhookSignature(timestamp int64, body []byte, secret string) string {
    mac := hmac.New(sha256.New, []byte(secret))
    mac.Write([]byte(fmt.Sprintf("%d", timestamp)))
    mac.Write([]byte("."))
    mac.Write(body)
    return hex.EncodeToString(mac.Sum(nil))
}
```

**Python example:**

```python
import hmac
import hashlib

def verify_webhook(timestamp: str, body: bytes, secret: str, signature: str) -> bool:
    message = f"{timestamp}.".encode('utf-8') + body
    computed = hmac.new(secret.encode('utf-8'), message, hashlib.sha256).hexdigest()
    return hmac.compare_digest(computed, signature)
```

**Key rotation:** During rotation grace period, try verifying with old key first, then new key. If both fail, reject.

### Retry behavior

Non-200 responses trigger retries: backoff within 48 hours, up to 16 times. Intervals: 1m, 2m, 4m, 8m, ... up to a max of 4 hours between retries.

### Processing requirements

- **Idempotency**: Deduplicate events by `id`.
- **Event filtering**: Return HTTP 200 for non-relevant event types.
- **Order independence**: Events may arrive out of order. Query the API for latest status if needed.

### Webhook payload examples

**`v2.trades.succeeded`** — Trade payment successful:

```json
{
  "id": "572677246926464036",
  "type": "v2.trades.succeeded",
  "created": "2025-10-28T06:54:55Z",
  "data": {
    "trade_id": "572677233903157186",
    "access_no": "77d52a21dc032b4",
    "merchant_id": "2816433",
    "customer_id": "547766341013094363",
    "order_id": "order_1761634475936438746",
    "amount": "30.00",
    "currency": "USD",
    "trade_status": "succeeded",
    "payment_mode": "subscription",
    "payment_method": "credit_card",
    "payment_channel": "shoplazzapayment",
    "payment_token": "pB_KO6Q***YU",
    "paid_at": "2025-10-28T06:54:55Z",
    "session_id": "572677164911046667",
    "invoice_id": "547766341013094363",
    "refund_status": "no_refund",
    "total_refunded_amount": "0.00",
    "metadata": {},
    "last_payment_error": null
  }
}
```

**`v2.subscription.first`** — First subscription activated:

```json
{
  "id": "572677252513276964",
  "type": "v2.subscription.first",
  "created": "2025-10-28T06:54:56Z",
  "data": {
    "id": "572677251968024511",
    "customer_id": "547766341013094363",
    "sub_merchant_id": "2216433",
    "status": "active",
    "price_id": "572349501902208959",
    "total_cycles": "0",
    "cycle_index": "1",
    "current_period_start": "2025-10-28T06:54:00Z",
    "current_period_end": "2025-10-28T07:25:00Z",
    "next_invoice_date": "2025-10-28T07:26:00Z",
    "order_id": "order_1761634475936438746",
    "source_trade_id": "572677233903157186",
    "cancel_at": null,
    "cancel_reason": "",
    "created_at": "2025-10-28T06:54:56Z",
    "updated_at": "2025-10-28T06:54:56Z"
  }
}
```

**`v2.subscription.canceled`** — Subscription terminated:

```json
{
  "id": "572682701203579940",
  "type": "v2.subscription.canceled",
  "created": "2025-10-28T07:16:35Z",
  "data": {
    "id": "572677251968024511",
    "customer_id": "547766341013094363",
    "sub_merchant_id": "2816433",
    "status": "canceled",
    "price_id": "572349625697058751",
    "cancel_at": "2025-10-28T07:16:00Z",
    "cancel_reason": "cancel",
    "order_id": "order_1761634475936438746",
    "source_trade_id": "572677233903157186"
  }
}
```

**`v2.invoice.paid`** — Invoice paid:

```json
{
  "id": "583564654786128554",
  "type": "v2.invoice.paid",
  "created": "2025-11-27T07:57:35Z",
  "data": {
    "id": "583564651824957126",
    "subscription_id": "583564651824940742",
    "customer_id": "537465921338359803",
    "sub_merchant_id": "100010",
    "trade_id": "583564647529987790",
    "amount": "10",
    "currency": "USD",
    "status": "success",
    "invoice_type": "initial",
    "cycle_index": "1",
    "cycle_start": "2025-11-27T07:57:00Z",
    "cycle_end": "2025-11-27T13:07:00Z",
    "paid_at": "2025-11-27T07:57:34Z",
    "order_id": "order_1764230244388418776"
  }
}
```

**`v2.refunds.succeeded`** — Refund processed:

```json
{
  "id": "572683623191290916",
  "type": "v2.refunds.succeeded",
  "created": "2025-10-28T07:20:15Z",
  "data": {
    "refund_id": "20251028572683602265931714",
    "trade_id": "572679783406649282",
    "access_no": "77d52a21dc032b4",
    "merchant_id": "2816433",
    "refund_amount": "15.57",
    "currency": "USD",
    "refund_status": "succeeded",
    "finished_at": "2025-10-28T07:20:15Z",
    "reason": "",
    "metadata": null
  }
}
```

---

## Going Live

### Prerequisites

1. Register a Subotiz merchant account at [admin.subotiz.com/signup](https://admin.subotiz.com/signup)
2. Complete merchant qualification review
3. Create products and pricing in the production dashboard

### Switch from sandbox to production

1. **API base URL:** Change from `https://api.sandbox.subotiz.com` to `https://api.subotiz.com`
2. **Dashboard:** Switch to `https://admin.subotiz.com`
3. **SDK:** Set `environment: 'PRODUCTION'`
4. **API keys / access_secret:** Use production credentials from the production dashboard

---

## Tips for Agents

### Context awareness
- **Figure out what your human needs first.** Don't assume they want code. They might want an overview, dashboard steps, or API usage.
- **Ask questions when you're unsure.** "Do you already have a Subotiz account?" is always better than guessing.
- **Clarify the integration method.** For "integrate Subotiz," ask: Hosted (redirect), Embedded (full checkout), or Payment-only?

### When working with the API
- **Always use sandbox first.** Mistakes in production affect real customers and real money.
- **Prices are strings with two decimal places** — `"30.00"` means $30.00 (NOT cents like some other platforms).
- **Don't guess IDs.** List resources first, then use actual IDs.
- **Auth:** Confirm whether they use Bearer API key or Hub-* signature; both are valid.
- **Include `order_id` when creating checkout sessions** — it's how you correlate payments back to your internal orders.
- **Save `payment_token`** from `v2.trades.succeeded` events for subscription renewals.

### When handling webhooks
- **Always verify signatures** using HMAC-SHA256 before processing.
- **Implement idempotency** — deduplicate by event `id`.
- **Handle key rotation** — support both old and new keys during grace period.
- **Return HTTP 200** for all events, even ones you don't process.
- **Events may arrive out of order** — query the API if you need the latest state.

### When debugging
- **Check trade_status** — see [Status Enumerations](#status-enumerations) for what each status means.
- **Check `last_payment_error`** in trade webhook data for failure details.
- **For subscription issues**, check the subscription status and `cancel_reason`.
- **Include `trace_id` or error codes** when contacting support.

---

## Links

| Resource          | URL |
|-------------------|-----|
| Subotiz           | <https://subotiz.com> |
| Developer Center  | <https://developer.subotiz.com> |
| API Reference     | <https://developer.subotiz.com/v1.0-en-us/reference/overview-1> |
| Introduction (API)| <https://developer.subotiz.com/reference/introduction-1> |
| Authentication    | [Bearer](https://developer.subotiz.com/reference/authentication-1) · [Signature](https://developer.subotiz.com/reference/authentication-2) |
| Webhooks          | <https://developer.subotiz.com/reference/introduction-2> |
| Subotiz SDK       | <https://developer.subotiz.com/reference/subotiz-sdk> |
| Quick Start       | <https://developer.subotiz.com/reference/quick-start> |
| Hosted Checkout   | <https://developer.subotiz.com/reference/hosted> |
| Embedded Checkout | <https://developer.subotiz.com/reference/embedded-form> |
| Embedded Payment  | <https://developer.subotiz.com/reference/embedded-form-payment> |
| Dashboard (Prod)  | <https://admin.subotiz.com> |
| Dashboard (Sandbox) | <https://admin.sandbox.subotiz.com> |
| Support           | developer@subotiz.com |

来源:https://github.com/subotiz-org/AI/tree/main/plugin/cursor/subotiz-plugin