{"id":50558893,"url":"https://github.com/byte-power/primer","last_synced_at":"2026-06-04T10:02:00.669Z","repository":{"id":354331185,"uuid":"1213109814","full_name":"byte-power/primer","owner":"byte-power","description":null,"archived":false,"fork":false,"pushed_at":"2026-04-28T04:28:48.000Z","size":31,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-28T06:27:52.802Z","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":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/byte-power.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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-04-17T03:48:40.000Z","updated_at":"2026-04-28T04:28:16.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/byte-power/primer","commit_stats":null,"previous_names":["byte-power/primer"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/byte-power/primer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/byte-power%2Fprimer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/byte-power%2Fprimer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/byte-power%2Fprimer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/byte-power%2Fprimer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/byte-power","download_url":"https://codeload.github.com/byte-power/primer/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/byte-power%2Fprimer/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33899697,"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-04T02:00:06.755Z","response_time":64,"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-04T10:01:59.798Z","updated_at":"2026-06-04T10:02:00.662Z","avatar_url":"https://github.com/byte-power.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Primer Go SDK\n\n[Primer](https://primer.io) API v2.4 的 Go SDK，覆盖 Client Session、Payments、Payment Methods 全部 API 及 Webhook 解析。\n\n## 安装\n\n```bash\ngo get github.com/byte-power/primer\n```\n\n## 快速开始\n\n### 创建客户端\n\n```go\nimport \"github.com/byte-power/primer\"\n\n// Sandbox 环境（默认）\nclient := primer.NewClient(\"your-api-key\", logger)\n\n// Production 环境\nclient := primer.NewProductionClient(\"your-api-key\", logger)\n\n// 自定义 Base URL\nclient := primer.NewClientWithBaseURL(\"your-api-key\", \"https://custom.url\", logger)\n\n// 自定义 HTTP Client\nclient := primer.NewClientWithHTTPClient(\"your-api-key\", primer.SandboxBaseURL, httpClient, logger)\n```\n\n## Client Session API\n\n管理客户端会话，生成用于初始化 Universal Checkout 的 client token。\n\n### 创建会话\n\n```go\namount := int64(5000)\nsession, err := client.CreateClientSession(\u0026primer.CreateClientSessionRequest{\n    OrderID:      \"order-123\",\n    CurrencyCode: \"EUR\",\n    Amount:       \u0026amount,\n    Customer: \u0026primer.CustomerDetails{\n        EmailAddress: \"john@example.com\",\n        FirstName:    \"John\",\n        LastName:     \"Doe\",\n    },\n})\nif err != nil {\n    log.Fatalf(\"create session failed: %s\", err.Message)\n}\nfmt.Printf(\"Client Token: %s (expires: %s)\\n\", session.ClientToken, session.ClientTokenExpirationDate)\n```\n\n### 更新会话\n\n```go\nnewAmount := int64(6000)\nupdated, err := client.UpdateClientSession(\u0026primer.UpdateClientSessionRequest{\n    ClientToken: session.ClientToken,\n    Amount:      \u0026newAmount,\n})\n```\n\n### 检索会话\n\n```go\nsession, err := client.GetClientSession(\"client-token-xxx\")\n```\n\n## Payments API\n\n完整的支付生命周期管理：创建、授权、捕获、退款、取消。\n\n### 创建支付\n\n```go\npayment, err := client.CreatePayment(\u0026primer.CreatePaymentRequest{\n    PaymentMethodToken: \"pm-token-xxx\",\n    OrderID:            \"order-123\",\n    CurrencyCode:       \"EUR\",\n    Amount:             \u0026amount,\n})\n```\n\n使用幂等键防止重复支付：\n\n```go\npayment, err := client.CreatePaymentWithIdempotencyKey(req, \"unique-idempotency-key\")\n```\n\n### 获取支付详情\n\n```go\npayment, err := client.GetPayment(\"payment-id\")\n```\n\n### 捕获支付\n\n全额捕获（不传 body）：\n\n```go\npayment, err := client.CapturePayment(\"payment-id\", nil)\n```\n\n部分捕获：\n\n```go\ncaptureAmount := int64(3000)\npayment, err := client.CapturePayment(\"payment-id\", \u0026primer.CapturePaymentRequest{\n    Amount: \u0026captureAmount,\n})\n```\n\n### 取消支付\n\n```go\npayment, err := client.CancelPayment(\"payment-id\", \u0026primer.CancelPaymentRequest{\n    Reason: \"customer requested cancellation\",\n})\n```\n\n### 退款\n\n全额退款：\n\n```go\npayment, err := client.RefundPayment(\"payment-id\", nil)\n```\n\n部分退款：\n\n```go\nrefundAmount := int64(1000)\npayment, err := client.RefundPayment(\"payment-id\", \u0026primer.RefundPaymentRequest{\n    Amount:  \u0026refundAmount,\n    OrderID: \"order-123\",\n    Reason:  \"item returned\",\n})\n```\n\n### 恢复支付\n\n当支付被 Workflow 暂停时（如等待 3DS 验证），恢复支付流程：\n\n```go\npayment, err := client.ResumePayment(\"payment-id\", \u0026primer.ResumePaymentRequest{\n    ResumeToken: \"resume-token-xxx\",\n})\n```\n\n### 手动授权支付\n\n```go\npayment, err := client.AuthorizePayment(\"payment-id\", \u0026primer.AuthorizePaymentRequest{\n    Processor: primer.AuthorizeProcessor{\n        ProcessorMerchantID: \"merchant-id-123\",\n        Name:                \"STRIPE\",\n    },\n})\n```\n\n### 调整授权金额\n\n仅在 `authorizationType` 为 `ESTIMATED` 时可用：\n\n```go\npayment, err := client.AdjustAuthorization(\"payment-id\", \u0026primer.AdjustAuthorizationRequest{\n    Amount: 7500,\n})\n```\n\n### 查询支付列表\n\n```go\nlimit := int64(20)\nresult, err := client.ListPayments(\u0026primer.PaymentListParams{\n    Status:       []string{\"AUTHORIZED\", \"SETTLED\"},\n    CurrencyCode: []string{\"EUR\"},\n    FromDate:     \"2025-01-01T00:00:00Z\",\n    Limit:        \u0026limit,\n})\n\nfor _, p := range result.Data {\n    fmt.Printf(\"[%s] %s %d %s\\n\", p.Status, p.ID, p.Amount, p.CurrencyCode)\n}\n\n// 翻页\nif result.NextCursor != \"\" {\n    nextPage, _ := client.ListPayments(\u0026primer.PaymentListParams{\n        Cursor: result.NextCursor,\n    })\n    _ = nextPage\n}\n```\n\n## Payment Methods API\n\n管理客户已保存的支付方式。\n\n### 保存支付方式\n\n将一次性 token 保存为可重复使用的支付方式：\n\n```go\nsaved, err := client.VaultPaymentMethod(\"single-use-token\", \u0026primer.VaultPaymentMethodRequest{\n    CustomerID: \"customer-123\",\n})\n```\n\n### 列表查询已保存的支付方式\n\n```go\nmethods, err := client.ListPaymentMethods(\"customer-123\")\n\nfor _, m := range methods.Data {\n    fmt.Printf(\"[%s] %s (default: %v)\\n\", m.PaymentMethodType, m.Token, m.Default)\n}\n```\n\n### 设置默认支付方式\n\n```go\nupdated, err := client.SetDefaultPaymentMethod(\"payment-method-token\")\n```\n\n### 删除已保存的支付方式\n\n```go\ndeleted, err := client.DeletePaymentMethod(\"payment-method-token\")\n```\n\n## Webhook 解析\n\nSDK 支持解析所有 Primer Webhook 事件，并内置 HMAC-SHA256 签名验证。\n\n### 按事件类型解析\n\n```go\n// PAYMENT.STATUS\nwebhook, err := primer.ParsePaymentStatusWebhookFromRequest(r, signingSecret)\n\n// PAYMENT.REFUND\nwebhook, err := primer.ParsePaymentRefundWebhookFromRequest(r, signingSecret)\n\n// DISPUTE.OPENED\nwebhook, err := primer.ParseDisputeOpenWebhookFromRequest(r, signingSecret)\n\n// DISPUTE.STATUS\nwebhook, err := primer.ParseDisputeStatusWebhookFromRequest(r, signingSecret)\n```\n\n### 通用路由模式\n\n当一个端点需要处理多种 webhook 事件时，使用通用解析器先提取 `eventType`，再按类型路由：\n\n```go\neventType, body, err := primer.ParseWebhookFromRequest(r, signingSecret)\nif err != nil {\n    http.Error(w, \"bad request\", http.StatusBadRequest)\n    return\n}\n\nswitch eventType {\ncase \"PAYMENT.STATUS\":\n    webhook, _ := primer.ParsePaymentStatusWebhook(body)\n    handlePaymentStatus(webhook)\ncase \"PAYMENT.REFUND\":\n    webhook, _ := primer.ParsePaymentRefundWebhook(body)\n    handlePaymentRefund(webhook)\ncase \"DISPUTE.OPENED\":\n    webhook, _ := primer.ParseDisputeOpenWebhook(body)\n    handleDisputeOpen(webhook)\ncase \"DISPUTE.STATUS\":\n    webhook, _ := primer.ParseDisputeStatusWebhook(body)\n    handleDisputeStatus(webhook)\n}\n```\n\n### 从 JSON 字节解析（不验证签名）\n\n```go\nwebhook, err := primer.ParsePaymentStatusWebhook(jsonBytes)\n```\n\n## Debug 日志\n\nSDK 在每次 API 请求和响应时都会输出 debug 日志。只需传入一个实现 `primer.Logger` 接口的实例即可：\n\n```go\ntype Logger interface {\n    Debug(msg string, fields ...Field)\n    Info(msg string, fields ...Field)\n    Error(msg string, fields ...Field)\n}\n```\n\n示例：基于标准库 `log` 的实现：\n\n```go\ntype StdLogger struct{}\n\nfunc (l *StdLogger) Debug(msg string, fields ...primer.Field) {\n    log.Printf(\"[DEBUG] %s %v\", msg, fields)\n}\n\nfunc (l *StdLogger) Info(msg string, fields ...primer.Field) {\n    log.Printf(\"[INFO]  %s %v\", msg, fields)\n}\n\nfunc (l *StdLogger) Error(msg string, fields ...primer.Field) {\n    log.Printf(\"[ERROR] %s %v\", msg, fields)\n}\n```\n\n传入 `nil` 时使用内置的 `NopLogger`（不输出任何日志）。\n\n日志事件说明：\n\n| 事件名 | 级别 | 说明 |\n|--------|------|------|\n| `primer_request` | Debug | API 请求发起，包含 method、url、body |\n| `primer_response` | Debug | API 响应返回，包含 status_code 和 body |\n| `primer_request_error` | Error | HTTP 请求执行失败 |\n| `primer_read_response_error` | Error | 读取响应体失败 |\n| `primer_api_error` | Error | API 返回业务错误，包含 error_id 和 description |\n\n## 错误处理\n\nSDK 返回 `*primer.Error`，包含以下字段：\n\n```go\ntype Error struct {\n    Message    string // 错误描述\n    StatusCode int    // HTTP 状态码（API 错误时）\n    ErrorID    string // Primer API 错误 ID（API 错误时）\n    Err        error  // 底层错误（可用 errors.Unwrap 获取）\n}\n```\n\n示例：\n\n```go\npayment, err := client.GetPayment(\"invalid-id\")\nif err != nil {\n    fmt.Printf(\"Error: %s\\n\", err.Message)\n    fmt.Printf(\"HTTP Status: %d\\n\", err.StatusCode)\n    fmt.Printf(\"Error ID: %s\\n\", err.ErrorID)\n\n    // 根据 HTTP 状态码处理\n    switch err.StatusCode {\n    case 400:\n        // 请求参数错误\n    case 401:\n        // API Key 无效\n    case 404:\n        // 资源不存在\n    case 409:\n        // 状态冲突（如重复捕获）\n    case 422:\n        // 验证错误\n    }\n}\n```\n\n## 示例\n\n完整的可运行示例位于 [`examples/`](./examples/) 目录：\n\n| 示例 | 说明 |\n|------|------|\n| [`examples/client_session/`](./examples/client_session/) | 创建、更新、检索 Client Session |\n| [`examples/payment/`](./examples/payment/) | 完整支付生命周期：创建 → 捕获 → 退款 → 查询 |\n| [`examples/payment_method/`](./examples/payment_method/) | 保存、查询、设置默认、删除支付方式 |\n| [`examples/webhook/`](./examples/webhook/) | 启动 HTTP 服务器，接收并路由所有类型的 Webhook 事件 |\n\n### 运行示例\n\n```bash\ncd examples\n\n# Client Session：创建 + 更新 + 检索\nPRIMER_API_KEY=your-key go run ./client_session/\n\n# 支付生命周期（需要有效的 payment method token）\nPRIMER_API_KEY=your-key PRIMER_PAYMENT_METHOD_TOKEN=pm-xxx go run ./payment/\n\n# 支付方式管理\nPRIMER_API_KEY=your-key PRIMER_CUSTOMER_ID=cust-123 PRIMER_PAYMENT_METHOD_TOKEN=pm-xxx go run ./payment_method/\n\n# Webhook 服务器（监听 :8080）\nPRIMER_WEBHOOK_SECRET=your-secret go run ./webhook/\n```\n\n## API 参考\n\n本 SDK 基于 [Primer API v2.4](https://primer.io/docs/api-reference/get-started/overview) 构建。\n\n### Client Session API\n\n| 方法 | HTTP | 端点 | 说明 |\n|------|------|------|------|\n| `CreateClientSession` | POST | `/client-session` | [创建客户端会话](https://primer.io/docs/api-reference/v2.4/api-reference/client-session-api/create-a-client-session) |\n| `UpdateClientSession` | PATCH | `/client-session` | [更新客户端会话](https://primer.io/docs/api-reference/v2.4/api-reference/client-session-api/update-client-session) |\n| `GetClientSession` | GET | `/client-session` | [检索客户端会话](https://primer.io/docs/api-reference/v2.4/api-reference/client-session-api/retrieve-a-client-session) |\n\n### Payments API\n\n| 方法 | HTTP | 端点 | 说明 |\n|------|------|------|------|\n| `CreatePayment` | POST | `/payments` | [创建支付](https://primer.io/docs/api-reference/v2.4/api-reference/payments-api/create-a-payment) |\n| `GetPayment` | GET | `/payments/{id}` | [获取支付详情](https://primer.io/docs/api-reference/v2.4/api-reference/payments-api/get-a-payment) |\n| `CapturePayment` | POST | `/payments/{id}/capture` | [捕获支付](https://primer.io/docs/api-reference/v2.4/api-reference/payments-api/capture-a-payment) |\n| `CancelPayment` | POST | `/payments/{id}/cancel` | [取消支付](https://primer.io/docs/api-reference/v2.4/api-reference/payments-api/cancel-a-payment) |\n| `RefundPayment` | POST | `/payments/{id}/refund` | [退款](https://primer.io/docs/api-reference/v2.4/api-reference/payments-api/refund-a-payment) |\n| `ResumePayment` | POST | `/payments/{id}/resume` | [恢复支付](https://primer.io/docs/api-reference/v2.4/api-reference/payments-api/resume-a-payment) |\n| `AuthorizePayment` | POST | `/payments/{id}/authorize` | [授权支付](https://primer.io/docs/api-reference/v2.4/api-reference/payments-api/authorize-a-payment) |\n| `AdjustAuthorization` | POST | `/payments/{id}/adjust-authorization` | [调整授权金额](https://primer.io/docs/api-reference/v2.4/api-reference/payments-api/adjust-authorized-amount) |\n| `ListPayments` | GET | `/payments` | [查询支付列表](https://primer.io/docs/api-reference/v2.4/api-reference/payments-api/search-\u0026-list-payments) |\n\n### Payment Methods API\n\n| 方法 | HTTP | 端点 | 说明 |\n|------|------|------|------|\n| `VaultPaymentMethod` | POST | `/payment-instruments/{token}/vault` | [保存支付方式](https://primer.io/docs/api-reference/v2.4/api-reference/payment-methods-api/save-a-payment-method-token) |\n| `ListPaymentMethods` | GET | `/payment-instruments` | [列表查询已保存的支付方式](https://primer.io/docs/api-reference/v2.4/api-reference/payment-methods-api/list-saved-payment-methods) |\n| `DeletePaymentMethod` | DELETE | `/payment-instruments/{token}` | [删除已保存的支付方式](https://primer.io/docs/api-reference/v2.4/api-reference/payment-methods-api/delete-a-saved-payment-method) |\n| `SetDefaultPaymentMethod` | POST | `/payment-instruments/{token}/default` | [设置默认支付方式](https://primer.io/docs/api-reference/v2.4/api-reference/payment-methods-api/update-the-default-saved-payment-method) |\n\n### Webhook 解析\n\n| 函数 | 事件类型 | 说明 |\n|------|----------|------|\n| `ParsePaymentStatusWebhook(FromRequest)` | `PAYMENT.STATUS` | [支付状态更新](https://primer.io/docs/api-reference/endpoints/v2.4/payment-webhooks/payment-status-update) |\n| `ParsePaymentRefundWebhook(FromRequest)` | `PAYMENT.REFUND` | [退款完成](https://primer.io/docs/api-reference/endpoints/v2.4/payment-webhooks/payment-refund) |\n| `ParseDisputeOpenWebhook(FromRequest)` | `DISPUTE.OPENED` | [争议开启](https://primer.io/docs/api-reference/endpoints/v2.4/dispute-\u0026-chargebacks-webhooks/dispute-open) |\n| `ParseDisputeStatusWebhook(FromRequest)` | `DISPUTE.STATUS` | [争议状态更新](https://primer.io/docs/api-reference/endpoints/v2.4/dispute-\u0026-chargebacks-webhooks/dispute-status) |\n| `ParseWebhookFromRequest` | 通用 | 验签 + 提取 eventType，用于路由分发 |\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbyte-power%2Fprimer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbyte-power%2Fprimer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbyte-power%2Fprimer/lists"}