{"id":39297701,"url":"https://github.com/scanpay/go-scanpay","last_synced_at":"2026-01-18T01:27:26.808Z","repository":{"id":39902439,"uuid":"83565053","full_name":"scanpay/go-scanpay","owner":"scanpay","description":"Scanpay Go client library","archived":false,"fork":false,"pushed_at":"2022-05-22T16:27:32.000Z","size":29,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-06-21T12:54:47.882Z","etag":null,"topics":["go","golang","payments","scanpay"],"latest_commit_sha":null,"homepage":"https://docs.scanpay.dev","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/scanpay.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}},"created_at":"2017-03-01T14:42:57.000Z","updated_at":"2023-07-12T10:04:52.000Z","dependencies_parsed_at":"2022-09-21T12:50:47.151Z","dependency_job_id":null,"html_url":"https://github.com/scanpay/go-scanpay","commit_stats":null,"previous_names":["scanpaydk/go-scanpay"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/scanpay/go-scanpay","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scanpay%2Fgo-scanpay","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scanpay%2Fgo-scanpay/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scanpay%2Fgo-scanpay/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scanpay%2Fgo-scanpay/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/scanpay","download_url":"https://codeload.github.com/scanpay/go-scanpay/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scanpay%2Fgo-scanpay/sbom","scorecard":{"id":803448,"data":{"date":"2025-08-11","repo":{"name":"github.com/scanpay/go-scanpay","commit":"c811abcb8d1a08cc8b349d80929dd4354fc8d74d"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/27 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 4 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-23T11:07:54.957Z","repository_id":39902439,"created_at":"2025-08-23T11:07:54.957Z","updated_at":"2025-08-23T11:07:54.957Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28526456,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-18T00:39:45.795Z","status":"ssl_error","status_checked_at":"2026-01-18T00:39:39.467Z","response_time":85,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["go","golang","payments","scanpay"],"created_at":"2026-01-18T01:27:26.738Z","updated_at":"2026-01-18T01:27:26.797Z","avatar_url":"https://github.com/scanpay.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Scanpay Go client\n\nThe official Go client library for the Scanpay API ([docs](https://docs.scanpay.dk)). You can always e-mail us at [help@scanpay.dk](mailto:help@scanpay.dk), or chat with us on IRC at libera.chat #scanpay\n\n## Installation\n```bash\ngo get github.com/scanpay/go-scanpay\n```\n\n## Usage\nCreate a Scanpay client to start using this library:\n\n```go\nvar client = scanpay.Client{\n    APIKey: \" APIKEY \",\n}\n```\n\n### Payment Link\n\n\n#### func (cl \\*Client) NewURL(req \\*NewURLReq) error\nUse NewURL to create a payment link:\n\n```go\npackage main\nimport(\n    \"..\"\n    \"fmt\"\n)\n\nvar client = scanpay.Client{\n    APIKey: \"1153:YHZIUGQw6NkCIYa3mG6CWcgShnl13xuI7ODFUYuMy0j790Q6ThwBEjxfWFXwJZ0W\",\n    Host: \"api.test.scanpay.dk\",\n}\n\nfunc main() {\n    req := scanpay.NewURLReq {\n        OrderId: \"a766409\",\n        Language: \"da\",\n        SuccessURL: \"https://insertyoursuccesspage.dk\",\n        Items: []scanpay.Item {\n            {\n                Name:    \"Pink Floyd: The Dark Side Of The Moon\",\n                Quantity: 2,\n                Total:   \"199.98 DKK\",\n                SKU:     \"fadf23\",\n            },\n            {\n                Name:    \"巨人宏偉的帽子\",\n                Quantity: 2,\n                Total:   \"840 DKK\",\n                SKU:     \"124\",\n            },\n        },\n        Billing: scanpay.Billing{\n            Name:    \"John Doe\",\n            Company: \"The Shop A/S\",\n            Email:   \"john@doe.com\",\n            Phone:   \"+4512345678\",\n            Address: []string{\"Langgade 23, 2. th\"},\n            City:    \"Havneby\",\n            Zip:     \"1234\",\n            State:   \"\",\n            Country: \"DK\",\n            VATIN:   \"35413308\",\n            GLN:     \"7495563456235\",\n        },\n        Shipping: scanpay.Shipping{\n            Name: \"Jan Dåh\",\n            Company: \"The Choppa A/S\",\n            Email: \"jan@doh.com\",\n            Phone: \"+4587654321\",\n            Address: []string{\"Langgade 23, 1. th\", \"C/O The Choppa\"},\n            City: \"Haveby\",\n            Zip: \"1235\",\n            State: \"\",\n            Country: \"DK\",\n        },\n        Options: \u0026scanpay.Options{\n            Headers: map[string]string{\n                \"X-Cardholder-Ip\": \"111.222.111.222\",\n            },\n        },\n    }\n    url, err := client.NewURL(\u0026req)\n    if err != nil {\n        fmt.Println(\"Error:\", err)\n        return\n    }\n    fmt.Println(url)\n}\n}\n```\n### Synchronization\nTo know when transactions, charges, subscribers and subscriber renewal succeeds, you need to use the synchronization API. It consists of pings which notify you of changes, and the seq request which allows you to pull changes.\n\n#### func (cl \\*Client) HandlePing(r \\*http.Request) error\n\nWhen changes happen, a **ping** request will be sent to the **ping URL** specified in the Scanpay dashboard.\nUse HandlePing to parse the ping request:\n```go\npackage main\nimport(\n    \"..\"\n    \"fmt\"\n    \"net/http\"\n    \"os\"\n)\n\nvar client = scanpay.Client{\n    APIKey: \"1153:YHZIUGQw6NkCIYa3mG6CWcgShnl13xuI7ODFUYuMy0j790Q6ThwBEjxfWFXwJZ0W\",\n    Host: \"api.test.scanpay.dk\",\n}\n\nfunc ping(w http.ResponseWriter, r *http.Request) {\n    pingData, err := client.HandlePing(r)\n    if err != nil {\n        fmt.Println(\"invalid ping: \", err)\n        http.Error(w, \"\", http.StatusBadRequest)\n    } else {\n        fmt.Println(\"Received ping:\", pingData)\n    }\n    os.Exit(0)\n}\n\nfunc main() {\n    http.HandleFunc(\"/ping\", ping)\n    if err := http.ListenAndServe(\"localhost:8080\", nil); err != nil {\n        fmt.Println(\"http.ListenAndServe failed:\", err)\n    }\n}\n```\n\n#### func (cl \\*Client) Seq(req \\*scanpay.SeqReq) error\n\nTo pull changes since last update, use the Seq() call after receiving a ping.\nStore the returned seq-value in a database and use it for the next Seq() call.\n\n```go\npackage main\nimport(\n    \"..\"\n    \"fmt\"\n)\n\nvar client = scanpay.Client{\n    APIKey: \"1153:YHZIUGQw6NkCIYa3mG6CWcgShnl13xuI7ODFUYuMy0j790Q6ThwBEjxfWFXwJZ0W\",\n    Host: \"api.test.scanpay.dk\",\n}\nvar mySeq = uint64(300)\n\ntype Acts []scanpay.Act\n\nfunc seq(pingSeq uint64) {\n    for mySeq \u003c pingSeq {\n        seqRes, err := client.Seq(\u0026scanpay.SeqReq{ Seq: mySeq })\n        if err != nil {\n            fmt.Println(\"Error:\", err)\n            return\n        }\n        for _, change := range seqRes.Changes {\n            switch change.Type {\n            case \"transaction\", \"charge\":\n                fmt.Printf(\"Order %s change\\n\" +\n                           \"Transaction id: %d\\n\" +\n                           \"Revision: %d\\n\" +\n                           \"Acts: %#v\\n\\n\",\n                           change.OrderId, change.Id, change.Rev, change.Acts)\n            case \"subscriber\":\n                fmt.Printf(\"Subscriber %s change\\n\" +\n                           \"Subscriber id: %d\\n\" +\n                           \"Revision: %d\\n\" +\n                           \"Acts %#v\\n\\n\",\n                           change.Ref, change.Id, change.Rev, change.Acts)\n            }\n        }\n        mySeq = seqRes.Seq\n        if len(seqRes.Changes) == 0 {\n            break\n        }\n    }\n    fmt.Println(\"final mySeq =\", mySeq)\n}\n\nfunc main() {\n    pingSeq := uint64(400)\n    seq(pingSeq)\n}\n```\n### Transaction Actions\n\n#### func (cl \\*Client) Capture(req \\*CaptureReq) error\nUse Capture to capture a transaction.\n```go\npackage main\nimport(\n    \"fmt\"\n    \"github.com/scanpay/go-scanpay\"\n)\n\nvar client = scanpay.Client{\n    APIKey: \"1153:YHZIUGQw6NkCIYa3mG6CWcgShnl13xuI7ODFUYuMy0j790Q6ThwBEjxfWFXwJZ0W\",\n    Host: \"api.test.scanpay.dk\",\n}\n\nfunc main() {\n    req := scanpay.CaptureReq{\n        TransactionId: uint64(750),\n        Total: \"123 DKK\",\n        Index: 0,\n    }\n    if err := client.Capture(\u0026req); err != nil {\n        fmt.Println(\"Capture failed:\", err)\n    } else {\n        fmt.Println(\"Capture succeeded\")\n    }\n}\n```\n#### func (cl \\*Client) Refund(req \\*RefundReq) error\nUse Refund to refund a captured transaction.\n```go\npackage main\nimport(\n    \"..\"\n    \"fmt\"\n)\n\nvar client = scanpay.Client{\n    APIKey: \"1153:YHZIUGQw6NkCIYa3mG6CWcgShnl13xuI7ODFUYuMy0j790Q6ThwBEjxfWFXwJZ0W\",\n    Host: \"api.test.scanpay.dk\",\n}\n\nfunc main() {\n    req := scanpay.RefundReq{\n        TransactionId: uint64(750),\n        Total: \"123 DKK\",\n        Index: 1,\n    }\n    if err := client.Refund(\u0026req); err != nil {\n        fmt.Println(\"Refund failed:\", err)\n    } else {\n        fmt.Println(\"Refund succeeded\")\n    }\n}\n```\n#### func (cl \\*Client) Void(req \\*VoidReq) error\nUse Void to void the amount authorized by the transaction.\n```go\npackage main\nimport(\n    \"fmt\"\n    \"github.com/scanpay/go-scanpay\"\n)\n\nvar client = scanpay.Client{\n    APIKey: \"1153:YHZIUGQw6NkCIYa3mG6CWcgShnl13xuI7ODFUYuMy0j790Q6ThwBEjxfWFXwJZ0W\",\n    Host: \"api.test.scanpay.dk\",\n}\n\nfunc main() {\n    req := scanpay.VoidReq{\n        TransactionId: uint64(750),\n        Index: 0,\n    }\n    if err := client.Void(\u0026req); err != nil {\n        fmt.Println(\"Void failed:\", err)\n    } else {\n        fmt.Println(\"Void succeeded\")\n    }\n}\n```\n### Subscriptions\nCreate a subscriber by using NewURL with a Subscriber parameter.\n```go\npackage main\nimport(\n    \"..\"\n    \"fmt\"\n)\n\nvar client = scanpay.Client{\n    APIKey: \"1153:YHZIUGQw6NkCIYa3mG6CWcgShnl13xuI7ODFUYuMy0j790Q6ThwBEjxfWFXwJZ0W\",\n    Host: \"api.test.scanpay.dk\",\n}\n\nfunc main() {\n    req := scanpay.NewURLReq {\n        Subscriber: \u0026scanpay.Subscriber{\n            Ref: \"99\",\n        },\n        Options: \u0026scanpay.Options{\n            Headers: map[string]string{\n                \"X-Cardholder-Ip\": \"111.222.111.222\",\n            },\n        },\n    }\n    url, err := client.NewURL(\u0026req)\n    if err != nil {\n        fmt.Println(\"NewURL error:\", err)\n        return\n    }\n    fmt.Println(url)\n}\n```\n\n#### func (cl \\*Client) Charge(req \\*ChargeReq) error\nUse Charge to charge a subscriber. The subscriber id is obtained with seq.\n```go\npackage main\nimport(\n    \"fmt\"\n    \"..\"\n)\n\nvar client = scanpay.Client{\n    APIKey: \"1153:YHZIUGQw6NkCIYa3mG6CWcgShnl13xuI7ODFUYuMy0j790Q6ThwBEjxfWFXwJZ0W\",\n    Host: \"api.test.scanpay.dk\",\n}\n\nfunc main() {\n    req := scanpay.ChargeReq{\n        SubscriberId: 30,\n        Items: []scanpay.Item{\n            {\n                Name:\"some item\",\n                Total: \"123 DKK\",\n            },\n        },\n    }\n    if res, err := client.Charge(\u0026req); err != nil {\n        fmt.Println(\"Charge failed:\", err)\n    } else {\n        fmt.Println(\"Charge succeeded\", res)\n    }\n}\n```\n#### func (cl \\*Client) Renew(req \\*RenewReq) error\nUse Renew to renew a subscriber, i.e. to attach a new card, if it has expired.\n```go\npackage main\nimport(\n    \"..\"\n    \"fmt\"\n    \"time\"\n)\n\nvar client = scanpay.Client{\n    APIKey: \"1153:YHZIUGQw6NkCIYa3mG6CWcgShnl13xuI7ODFUYuMy0j790Q6ThwBEjxfWFXwJZ0W\",\n    Host: \"api.test.scanpay.dk\",\n}\n\nfunc main() {\n    req := scanpay.RenewReq {\n        SubscriberId: 30,\n        Language: \"da\",\n        SuccessURL: \"https://scanpay.dk\",\n        Lifetime: 24 * time.Hour,\n    }\n\n    if url, err := client.Renew(\u0026req); err != nil {\n        fmt.Println(\"Renew failed:\", err)\n    } else {\n        fmt.Println(\"Renew URL:\", url)\n    }\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fscanpay%2Fgo-scanpay","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fscanpay%2Fgo-scanpay","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fscanpay%2Fgo-scanpay/lists"}