{"id":18603056,"url":"https://github.com/devlooped/sponsorlink","last_synced_at":"2026-03-13T07:02:13.124Z","repository":{"id":65423527,"uuid":"592112421","full_name":"devlooped/SponsorLink","owner":"devlooped","description":"SponsorLink: an attempt at OSS sustainability","archived":false,"fork":false,"pushed_at":"2026-03-09T20:12:07.000Z","size":3189,"stargazers_count":42,"open_issues_count":10,"forks_count":4,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-10T01:42:56.215Z","etag":null,"topics":["oss","sponsors","sponsorships","sustainability"],"latest_commit_sha":null,"homepage":"https://www.devlooped.com/SponsorLink","language":"C#","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/devlooped.png","metadata":{"files":{"readme":"readme.md","changelog":"changelog.md","contributing":null,"funding":null,"license":"license.txt","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},"funding":{"github":"devlooped"}},"created_at":"2023-01-22T23:47:49.000Z","updated_at":"2026-03-09T20:12:11.000Z","dependencies_parsed_at":"2024-03-12T19:50:26.778Z","dependency_job_id":"3ea91690-618d-40af-a707-47acade69454","html_url":"https://github.com/devlooped/SponsorLink","commit_stats":{"total_commits":64,"total_committers":4,"mean_commits":16.0,"dds":0.234375,"last_synced_commit":"83faa4281edf4f4bcdcf16cb813281810b11bacc"},"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/devlooped/SponsorLink","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devlooped%2FSponsorLink","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devlooped%2FSponsorLink/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devlooped%2FSponsorLink/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devlooped%2FSponsorLink/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/devlooped","download_url":"https://codeload.github.com/devlooped/SponsorLink/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devlooped%2FSponsorLink/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30460818,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-13T06:34:02.089Z","status":"ssl_error","status_checked_at":"2026-03-13T06:33:49.182Z","response_time":60,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5: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":["oss","sponsors","sponsorships","sustainability"],"created_at":"2024-11-07T02:13:22.760Z","updated_at":"2026-03-13T07:02:13.118Z","avatar_url":"https://github.com/devlooped.png","language":"C#","funding_links":["https://github.com/sponsors/devlooped","https://github.com/sponsors","https://github.com/sponsors/"],"categories":[],"sub_categories":[],"readme":"# ![](https://github.com/devlooped/SponsorLink/raw/main/assets/img/sponsorlink-32.png) SponsorLink \n\nCore specification and reference implementation for integrating GitHub Sponsors into \nlibraries and tools.\n\n[![Spec](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fwww.devlooped.com%2FSponsorLink%2Fspec%2Fversion.json\u0026query=%24.version\u0026label=spec\u0026labelColor=EA4AAA\u0026color=black\n)](https://www.devlooped.com/SponsorLink/spec/)\n[![Version](https://img.shields.io/nuget/v/dotnet-sponsor.svg?color=royalblue)](https://www.nuget.org/packages/dotnet-sponsor) \n[![Downloads](https://img.shields.io/nuget/dt/dotnet-sponsor.svg?color=green)](https://www.nuget.org/packages/dotnet-sponsor) \n\nIntegrate [GitHub Sponsors](https://github.com/sponsors) into your libraries so that \nusers can be properly linked to their sponsorship to unlock features or simply get \nthe recognition they deserve for supporting your project. \n\nSponsorLink supports two scenarios:\n\n1. Open source project developers or maintainers who are looking to incentivize \n   sponsors to contribute to the project, to ensure ongoing and recurring income \n   that can help ensure proper maintenance and further feature work.\n\n2. Open source project consumers, who want to ensure their dependencies have \n   an active team that can provide support, bug fixes and add new features.\n\n[Explore the documentation site](https://www.devlooped.com/SponsorLink).\n\n## Why GitHub sponsors?\n\n![Octocat lifted by a sponsors heart-shaped globe](assets/img/sponsors-mona.png)\n\n[GitHub Sponsors](https://github.com/sponsors/) is a great way to support open \nsource projects, and it's available throughout most of the world. \n\nThat is not to say that there aren't other mechanisms that can provide similar \nfunctionality and support. At this point, however, the tooling, API access and \nvery low barrier to entry make it a great initial choice for SponsorLink.\n\nThat said, the reference implementation is not deeply tied to GitHub Sponsors, \nand the specification is entirely agnostic to the sponsorship platform. \n\nThe value SponsorLink brings is in providing the \"missing\" link between a user's \nsponsorship and the libraries they use, in an easy to check, secure and offline \nway.\n\n\u003c!-- #package --\u003e\n## How it works\n\nRoughly, the reference implementation works as follows:\n\n1. A library/tool author adds a check (i.e. on usage, build, etc.) for a \n   [sponsor manifest](https://www.devlooped.com/SponsorLink/spec/#sponsor-manifest) \n   at a well-known location in the local machine (i.e. `~/.sponsorlink/github/devlooped.jwt.`). If not found, the library/tool issues a notice to the user, typically stating \n   that they are seeking funding, how to fund the project and how to sync their status, \n   which is unknown at this point.\n2. User decides to sponsor the project, does so on github.com\n3. User installs the suggested [dotnet sponsor global tool](https://www.nuget.org/packages/dotnet-sponsor) and runs `sponsor sync [account]` to sync their sponsorships.\n   * On first run, user accepts usage terms and conditions.\n4. The tool fetches the author's [sponsorable manifest](https://www.devlooped.com/SponsorLink/spec/#sponsorable-manifest) from their community files repo \n   at `https://github.com/[account]/.github/blob/[default_branch]/sponsorlink.jwt` and \n   uses its information to authenticate the user on github.com with an OAuth app belonging \n   to the author, using device flow.\n5. The resulting authentication token is used to invoke the author's backend (\"issuer\") \n   API to retrieve the user's sponsor manifest (if any) and persist it at the well-known location \n   mentioned in step 1. This manifest is signed, has an expiration date and can be \n   verified by the library/tool without any network access.\n\nNotes:\n* Sponsor manifest expires monthly (like GitHub sponsorships themselves) and is signed \n   with a private key only the author has access to. Its corresponding public key is \n   public and accessible on the sponsorable manifest.\n* Users can optionally turn on/off auto-sync, so that after the first sync, the author can \n   automatically refresh the manifest on the user's behalf by re-running the sync command \n   unattended.\n* Users can have the following role claims:\n   * `user`: the user is direct sponsor of the author.\n   * `org`: the user is a member of an organization that sponsors the author.\n   * `contrib`: the user is a contributor to the author's project(s).\n   * `team`: the user is team a member of the author's organization.\n   * `oss`: the user is an author or contributor to an active open-source nuget package.\n     Elegibility can be checked at [OSS Authors](https://www.devlooped.com/SponsorLink/github/oss/)\n* Typically, an autor would consider any of the above roles to qualify as an active \n   sponsor (direct, indirect and implicit, respectively), but the actual behavior is up to the library/tool author.\n\n[Explore the documentation site](https://www.devlooped.com/SponsorLink) to learn more, \nand make sure to check the [privacy statement](https://www.devlooped.com/SponsorLink/privacy/).\n\n\u003c!-- \n## Stats\n\nActive SponsorLink sync usage by sponsorship kind:\n\n![User](https://img.shields.io/endpoint?color=ea4aaa\u0026url=https%3A%2F%2Fsponsorlink.devlooped.com%2Fbadge%3Fuser)\n![Organization](https://img.shields.io/endpoint?color=yellow\u0026url=https%3A%2F%2Fsponsorlink.devlooped.com%2Fbadge%3Forg)\n![Team](https://img.shields.io/endpoint?color=8A2BE2\u0026url=https%3A%2F%2Fsponsorlink.devlooped.com%2Fbadge%3Fteam)\n![Contributor](https://img.shields.io/endpoint?color=blue\u0026url=https%3A%2F%2Fsponsorlink.devlooped.com%2Fbadge%3Fcontrib)\n![OSS](https://img.shields.io/endpoint?color=green\u0026url=https%3A%2F%2Fsponsorlink.devlooped.com%2Fbadge%3Foss)\n--\u003e\n\n## Integrating via NuGet for .NET\n\nThe reference implementation .NET global tool, `dotnet-sponsor`, provides generic \nmanifest discovery and sync capabilities, but the actual check from within a library \nor tool is left to the author.\n\n\u003e [!NOTE]\n\u003e For now, the tool works only with GitHub sponsors as a funding platform.\n\nSince the sponsor manifest is a standard JWT token, it can be verified by any JWT\nlibrary in any language and at any point in the library/tool usage (at installation \ntime, run-time, build-time, etc.).\n\nIf you are looking for inspiration on how to do this for .NET with NuGet and C#, \ncheck the [the analyzer sample](samples/dotnet).\n\n## Release Announcements on X\n\nWhen a GitHub release is published, SponsorLink can automatically post a threaded \nannouncement to X (formerly Twitter). The release body is summarized by the \n[Grok](https://x.ai) AI model into a ranked list of emoji-prefixed highlights, \nformatted into a reply chain of up to 280-character posts.\n\n### Announcement Conditions\n\nAn announcement is posted when **all** of the following are true:\n\n- The release is not a draft.\n- The release body is not empty.\n- The release body contains at least one recognized section title (see below), \n  **or** the [force-announce marker](#html-comment-markers) is present.\n- The release body does not contain the [skip-announce marker](#html-comment-markers).\n- All required [configuration settings](#configuration) are present.\n\nDeduplication is enforced via Azure Table Storage: a release that has already been \nannounced is skipped even if the webhook fires again.\n\n#### Release Section Titles\n\nThe announcement is gated on the presence of at least one of the category headings \ndefined in [`.github/release.yml`](.github/release.yml), which is synchronized from \n[devlooped/oss](https://github.com/devlooped/oss/blob/main/.github/release.yml).\n\n### HTML Comment Markers\n\nTwo special HTML comment markers can be placed anywhere in the release body:\n\n| Marker | Effect |\n|---|---|\n| `\u003c!-- !x --\u003e` | **Skip** � suppresses the announcement for this release, even if it would otherwise qualify. |\n| `\u003c!-- x --\u003e` | **Force** � publishes the announcement regardless of whether the release was just published or was edited after the fact. Useful for announcing an edited release that was initially skipped. |\n\nMarkers are case-insensitive (`\u003c!-- !X --\u003e` and `\u003c!-- X --\u003e` are equivalent) and \ntolerate surrounding whitespace inside the comment.\n\n### Configuration\n\nAll settings are read from application configuration (environment variables, \nAzure Key Vault, or `appsettings.json`).\n\n#### X / Twitter (OAuth 1.0a)\n\n| Setting | Description |\n|---|---|\n| `X:ConsumerKey` | OAuth consumer key (API key) for the X app. |\n| `X:ConsumerSecret` | OAuth consumer secret for the X app. |\n| `X:AccessToken` | Access token for the X account that will post. |\n| `X:AccessTokenSecret` | Access token secret for the X account that will post. |\n\n#### AI Summarization (Grok)\n\n| Setting | Description | Default |\n|---|---|---|\n| `AI:Clients:Grok:Endpoint` | xAI API base URL. | `https://api.x.ai/v1` |\n| `AI:Clients:Grok:ModelId` | Model to use for summarization. | `grok-4-1-fast-non-reasoning` |\n| `AI:Clients:Grok:ApiKey` | xAI API key (secret). | � |\n\nWhen `AI:Clients:Grok:ApiKey` is absent the summarizer is disabled and no \nannouncements are posted.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevlooped%2Fsponsorlink","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevlooped%2Fsponsorlink","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevlooped%2Fsponsorlink/lists"}