{"id":50755506,"url":"https://github.com/warjiang/xorpay-sdk","last_synced_at":"2026-06-11T04:30:52.586Z","repository":{"id":355456134,"uuid":"1227672449","full_name":"warjiang/xorpay-sdk","owner":"warjiang","description":null,"archived":false,"fork":false,"pushed_at":"2026-05-03T17:49:15.000Z","size":1817,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-03T19:21:03.421Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/warjiang.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-03T02:16:29.000Z","updated_at":"2026-05-03T17:49:13.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/warjiang/xorpay-sdk","commit_stats":null,"previous_names":["warjiang/xorpay-sdk"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/warjiang/xorpay-sdk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/warjiang%2Fxorpay-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/warjiang%2Fxorpay-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/warjiang%2Fxorpay-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/warjiang%2Fxorpay-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/warjiang","download_url":"https://codeload.github.com/warjiang/xorpay-sdk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/warjiang%2Fxorpay-sdk/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34183109,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-11T02:00:06.485Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-11T04:30:51.648Z","updated_at":"2026-06-11T04:30:52.577Z","avatar_url":"https://github.com/warjiang.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# xorpay-sdk (Go)\n\n[![Go Version](https://img.shields.io/badge/Go-1.25%2B-blue)](https://go.dev)\n[![CI](https://github.com/warjiang/xorpay-sdk/actions/workflows/ci.yml/badge.svg)](https://github.com/warjiang/xorpay-sdk/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n\nGo SDK for [XorPay](https://xorpay.com), aligned with the official Java demo flow and extended to full public API coverage.\n\n- **Zero dependencies** — built entirely on the Go standard library (`net/http`).\n- **Strongly typed** — request/response structs with validation for every endpoint.\n- **Secure by default** — automatic signature generation and callback verification.\n- **Well tested** — comprehensive offline, mock-based unit tests with race detection.\n\n## Table of Contents\n\n- [Features](#features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Supported Payment Types](#supported-payment-types)\n- [Configuration](#configuration)\n- [Examples](#examples)\n- [Notify Verification](#notify-verification)\n- [Error Handling](#error-handling)\n- [Documentation](#documentation)\n- [Development](#development)\n- [License](#license)\n\n## Features\n\n| API | SDK Method | Endpoint |\n|-----|-----------|----------|\n| Native / JSAPI / Mini Program Pay | `CreatePay` | `POST /api/pay/{aid}` |\n| Cashier Pay | `CreateCashier` | `POST /api/cashier/{aid}` |\n| Barcode Pay | `CreateBarcodePay` | `POST /api/barcode_pay/{aid}` |\n| Query by AOID | `QueryByAOID` | `GET /api/query/{aoid}` |\n| Query by Order ID | `QueryByOrderID` | `GET /api/query2/{aid}` |\n| Refund | `Refund` | `POST /api/refund/{aoid}` |\n| Build OpenID URL | `BuildOpenIDURL` | `/api/openid/{aid}` |\n| Build QR URL | `BuildQRURL` | `/qr?data=...` |\n| Notify Verification | `VerifyNotify` | — |\n\n## Installation\n\nRequires **Go 1.25** or later.\n\n```bash\ngo get github.com/warjiang/xorpay-sdk\n```\n\n## Quick Start\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"fmt\"\n\n    \"github.com/warjiang/xorpay-sdk\"\n)\n\nfunc main() {\n    client, err := xorpay.NewClient(xorpay.ConfigFromEnv())\n    if err != nil {\n        panic(err)\n    }\n\n    resp, err := client.CreatePay(context.Background(), xorpay.PayRequest{\n        Name:      \"内容订阅一年期\",\n        PayType:   \"native\",\n        Price:     \"50.00\",\n        OrderID:   \"demo-0001\",\n        NotifyURL: \"https://merchant.example.com/xorpay_notify\",\n    })\n    if err != nil {\n        panic(err)\n    }\n\n    fmt.Println(resp.Status, resp.AOID, string(resp.Info))\n}\n```\n\nOr pass credentials explicitly:\n\n```go\nclient, err := xorpay.NewClient(xorpay.Config{\n    AppID:     \"mock_appid\",\n    AppSecret: \"mock_secret\",\n})\n```\n\n## Supported Payment Types\n\n| `PayType` | Description | SDK Method | Notes |\n|-----------|-------------|-----------|-------|\n| `native` | Native / QR code payment | `CreatePay` | Returns a payment URL or QR data |\n| `cashier` | Cashier page redirect | `CreateCashier` | Use for web checkout pages |\n| `jsapi` | WeChat JSAPI | `CreatePay` | Requires `OpenID` |\n| `barcode` | Barcode / scan-to-pay | `CreateBarcodePay` | Requires `Barcode` |\n| `miniprogram` | WeChat Mini Program | `CreatePay` | Set `IsMini: true` and provide `AppID` |\n\n## Configuration\n\nLoad from environment variables:\n\n```go\ncfg := xorpay.ConfigFromEnv()\nclient, err := xorpay.NewClient(cfg)\n```\n\nOr build `Config` explicitly:\n\n| Field | Required | Env Var Fallback | Description |\n|-------|----------|------------------|-------------|\n| `AppID` | yes | `XORPAY_APP_ID` | Your XorPay `aid` |\n| `AppSecret` | yes | `XORPAY_APP_SECRET` | Your app secret |\n| `BaseURL` | no | — | API base URL (default: `https://xorpay.com`) |\n| `NotifyURL` | no | `XORPAY_NOTIFY_URL` | Default notify URL for payment APIs |\n| `ReturnURL` | no | `XORPAY_RETURN_URL` | Default return URL for cashier / jsapi |\n\nClient options:\n\n```go\nclient, err := xorpay.NewClient(cfg,\n    xorpay.WithBaseURL(\"https://xorpay.com\"),\n    xorpay.WithHTTPClient(customHTTPClient),\n    xorpay.WithUserAgent(\"my-app/1.0\"),\n)\n```\n\n## Examples\n\nSet environment variables first:\n\n```bash\nexport XORPAY_APP_ID=mock_appid\nexport XORPAY_APP_SECRET=mock_secret\nexport XORPAY_NOTIFY_URL=https://merchant.example.com/xorpay_notify\nexport XORPAY_RETURN_URL=https://merchant.example.com/xorpay_return\n```\n\nRun standalone examples:\n\n```bash\ngo run ./examples/pay_native\ngo run ./examples/pay_cashier\ngo run ./examples/pay_jsapi\ngo run ./examples/pay_barcode\ngo run ./examples/query\ngo run ./examples/refund\ngo run ./examples/notify_verify\ngo run ./examples/internalcfg\n```\n\n### Full Gin Demo\n\nA complete web demo with order state management is available under `examples/gin_app`:\n\n```bash\ncd examples/gin_app\ngo run .\n```\n\nEnvironment variables for the Gin demo:\n\n| Variable | Required | Default |\n|----------|----------|---------|\n| `XORPAY_APP_ID` | yes | — |\n| `XORPAY_APP_SECRET` | yes | — |\n| `XORPAY_NOTIFY_URL` | yes | — |\n| `XORPAY_RETURN_URL` | no | — |\n| `XORPAY_BASE_URL` | no | `https://xorpay.com` |\n| `GIN_ADDR` | no | `:8080` |\n\n### Multi-language Demo Inputs\n\n- Java: `./demos/java-demo.zip`\n- Python: `./demos/native.py.zip`\n- Node.js: `./demos/native.js.zip`\n- H5: `./demos/h5.zip`\n- H5 Cashier: `./demos/h5-cashier.zip`\n\n## Notify Verification\n\nAlways verify the callback signature **before** processing business logic:\n\n```go\nfunc notifyHandler(w http.ResponseWriter, r *http.Request) {\n    _ = r.ParseForm()\n    payload := xorpay.NotifyPayloadFromValues(r.Form)\n\n    if err := client.VerifyNotify(payload); err != nil {\n        http.Error(w, \"bad sign\", http.StatusBadRequest)\n        return\n    }\n\n    // Production checklist:\n    // 1. Query the database by payload.OrderID (or payload.AOID).\n    // 2. If the order is already marked as paid, return \"ok\" immediately (idempotency).\n    // 3. Otherwise, update the order status in a transaction and return \"ok\" only on success.\n    // 4. Do NOT process business logic before signature verification.\n\n    _, _ = w.Write([]byte(\"ok\"))\n}\n```\n\nSignature rules used by the SDK (consistent with XorPay official docs):\n\n| API | Signature Formula |\n|-----|-------------------|\n| Pay / Cashier | `name + pay_type + price + order_id + notify_url + app_secret` |\n| Barcode Pay | `name + pay_type + price + order_id + notify_url + barcode + app_secret` |\n| Query by Order ID | `order_id + app_secret` |\n| Refund | `price + app_secret` |\n| Notify Verify | `aoid + order_id + pay_price + pay_time + app_secret` |\n\nAll signatures are lowercase MD5 over plain concatenated values.\n\n## Error Handling\n\nBusiness-level non-success responses return `*xorpay.APIError`:\n\n```go\nresp, err := client.CreatePay(ctx, req)\nif err != nil {\n    if xorpay.IsStatus(err, \"sign_error\") {\n        // handle sign mismatch\n    }\n\n    var apiErr *xorpay.APIError\n    if errors.As(err, \u0026apiErr) {\n        fmt.Println(apiErr.Endpoint, apiErr.Status, apiErr.Message)\n    }\n}\n```\n\nHTTP errors (status \u003e= 400) are also wrapped as `*APIError` with `HTTPStatus` and `RawBody` populated.\n\n## Documentation\n\n- [Getting Started](docs/getting-started.md) — client setup, typical flow, and best practices\n- [API Reference](docs/api-reference.md) — detailed method signatures and field descriptions\n- [Gin Integration](docs/gin-integration.md) — full web integration guide\n\n## Development\n\n```bash\n# Run tests with race detection and coverage\ngo test -race -coverprofile=coverage.out ./...\n\n# Static analysis\ngo vet ./...\n\n# Format code\ngofmt -w .\n```\n\nCI is configured via [GitHub Actions](.github/workflows/ci.yml) and runs on every push to `main` and on pull requests.\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwarjiang%2Fxorpay-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwarjiang%2Fxorpay-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwarjiang%2Fxorpay-sdk/lists"}