{"id":43103298,"url":"https://github.com/weld-io/subscription-service","last_synced_at":"2026-01-31T17:48:11.351Z","repository":{"id":22561230,"uuid":"95293601","full_name":"weld-io/subscription-service","owner":"weld-io","description":"REST API service managing subscription pricing, services, consumables, VAT, etc. Built in Node.js.","archived":false,"fork":false,"pushed_at":"2022-12-10T20:29:47.000Z","size":801,"stargazers_count":13,"open_issues_count":18,"forks_count":9,"subscribers_count":8,"default_branch":"master","last_synced_at":"2024-04-14T10:53:32.942Z","etag":null,"topics":["payments","pricing","subscriptions"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","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/weld-io.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-06-24T11:29:20.000Z","updated_at":"2024-01-24T13:25:58.000Z","dependencies_parsed_at":"2023-01-11T21:40:40.862Z","dependency_job_id":null,"html_url":"https://github.com/weld-io/subscription-service","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/weld-io/subscription-service","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/weld-io%2Fsubscription-service","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/weld-io%2Fsubscription-service/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/weld-io%2Fsubscription-service/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/weld-io%2Fsubscription-service/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/weld-io","download_url":"https://codeload.github.com/weld-io/subscription-service/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/weld-io%2Fsubscription-service/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28948697,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-31T14:26:55.697Z","status":"ssl_error","status_checked_at":"2026-01-31T14:26:52.545Z","response_time":128,"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":["payments","pricing","subscriptions"],"created_at":"2026-01-31T17:48:10.840Z","updated_at":"2026-01-31T17:48:11.341Z","avatar_url":"https://github.com/weld-io.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Subscription Service\n\n**Subscription Service** is a REST API service managing subscription pricing, services, consumables, VAT, etc. Built in Node.js.\n\nIt allows you to be more agile with your product offering, pricing, discounts, VAT, etc. Like [Segment](https://segment.com), but for payments.\n\nThis is **not a payment platform** - instead it’s a layer between your app and the payment platform ([Stripe](https://www.stripe.com) being the default).\n\n----------\n\nMade by the team at **Weld** ([www.weld.io](https://www.weld.io?utm_source=github-subscription-service)), the #codefree web/app creation tool:\n\n[![Weld](https://s3-eu-west-1.amazonaws.com/weld-social-and-blog/gif/weld_explained.gif?v2)](https://www.weld.io?utm_source=github-subscription-service)\n\n\n## How to Run\n\nSet JWT auth secret:\n\n\texport JWT_SECRET=...\n\nor no JWT:\n\n\texport DISABLE_JWT=true\n\nOptional:\n\n\texport STRIPE_SECRET_KEY=...\n\texport WEBHOOK_RENEW_SUBSCRIPTION=...\n\n\nThen, just start with:\n\n\tyarn dev  # development, you can also use DISABLE_JWT=true yarn dev\n\nor\n\n\tyarn start # production\n\nServer will default to **http://localhost:3034**\n\n\n## How to Test\n\n\tyarn test\n\n\n## Entities\n\nFor B2C apps, one Account has only one User.\nFor B2B apps, there can be multiple Users on each Account.\n\n- **Accounts**\n\t- name\n\t- reference (slug)\n\t- email\n\t- company\n\t\t- name\n\t\t- vatNumber\n\t- countryCode\n\t- discountCoupon\n\t- metadata (free form data)\n\t\t- stripeCustomer\n\t- subscriptions (array of Subscriptions)\n- **Users** (on an Account)\n\t- reference (e.g. user ID in another app)\n\t- account (reference to Account)\n\t- consumables\n\t\t- projects: 2\n\t- metadata (free form data)\n- **Plans**\n\t- name\n\t- reference (slug)\n\t- description\n\t- featureDescriptions (string array)\n\t- tags (string array)\n\t- position (order in a list)\n\t- isAvailable: true/false\n\t- allowMultiple: true/false (false = disable all other subscriptions unless they are allowMultiple=true)\n\t- services (array of Services)\n\t- price\n\t\t- month\n\t\t- year\n\t\t- once\n\t\t- vatIncluded\n\t- consumables: { projects: 10 }\n\t- trialDays: 30\n\t- metadata (free form data)\n- **Subscriptions** (an Account subscribes to one or more Plans)\n\t- plan (reference to Plan)\n\t- reference (e.g. domains, User can’t have multiple subscriptions with same Reference)\n\t- dateExpires\n\t- metadata (free form data)\n\t\t- stripeSubscription\n- **Services** (e.g. access to a feature, included in Plan)\n\t- name\n\t- reference (slug)\n\t- description\n\t- metadata (free form data)\n- **Consumables** (e.g. projects, users - limited by Plan, consumed by Users not Accounts)\n\n\n## Environment variables\n\n* `DISABLE_JWT`: set to \"true\" if you don’t want JWT authentication.\n* `JWT_SECRET`: secret key for [JSON Web Token authentication](https://jwt.io).\n* `CACHE_PROVIDER`: defaults to 'fastly'. Add new Cache Providers in folder `/app/cacheProviders`.\n* `PAYMENT_PROVIDER`: defaults to 'stripe'. Add new Payment Providers in folder `/app/paymentProviders`.\n* `STRIPE_SECRET_KEY`: secret key from [Stripe dashboard](https://dashboard.stripe.com/account/apikeys).\n* `VAT_PERCENT`: defaults to \"20\" (%), as in if the price incl. VAT is $10, VAT is $2.\n* `WEBHOOK_RENEW_SUBSCRIPTION`: a complete URL that will receive a POST request whenever a subscription is renewed.\n\n\n## API\n\n\n### Accounts\n\n#### Create new account\n\n\tcurl -X POST http://localhost:3034/api/accounts -H \"Content-Type: application/json\" -d '{ \"name\": \"My Company\" }'\n\n#### Update existing account\n\n\tcurl -X PATCH http://localhost:3034/api/accounts/:accountReference -H \"Content-Type: application/json\" -d '{ \"metadata.stripeCustomer\": \"XYZ\" }'\n\n\n### Users\n\n#### Create new user\n\nNote: `reference` is where you use your main permanent user ID, e.g. from another app.\n\n\tcurl -X POST http://localhost:3034/api/users -H \"Content-Type: application/json\" -d '{ \"reference\": \"userId1\", \"account\": \"my-company\" }'\n\n#### Create new user and account\n\n\tcurl -X POST http://localhost:3034/api/users -H \"Content-Type: application/json\" -d '{ \"reference\": \"userId2\", \"account\": { \"name\": \"My Company 2\", \"email\": \"invoices@mycompany2.com\" } }'\n\n#### Create new user and account and subscription\n\nNote: currently creates a subscription without payment - don't use.\n\n\tcurl -X POST http://localhost:3034/api/users -H \"Content-Type: application/json\" -d '{ \"reference\": \"userId2\", \"account\": { \"name\": \"My Company 2\", \"email\": \"invoices@mycompany2.com\" }, \"subscription\": { \"plan\": \"trial\", \"dateExpires\": \"2018-04-01\" } }'\n\n#### Get user\n\n\tcurl -X GET http://localhost:3034/api/users/:reference\n\nReturns:\n\n\t{\n\t\treference: xxx,\n\t\taccount: { reference: ... },\n\t\tactivePlan: {\n\t\t\treference: 'b2b_small',\n\t\t\tdateExpires: '2017-12-31',\n\t\t},\n\t\tplans: ['b2b_small'],\n\t\tservices: {\n\t\t\tremove_watermark: {\n\t\t\t\tname: 'Remove watermark'\n\t\t\t}\n\t\t},\n\t\tconsumables: {\n\t\t\tprojects: {\n\t\t\t\tmax: 10,\n\t\t\t\tcurrent: 8,\n\t\t\t\tremaining: 2\n\t\t\t}\n\t\t},\n\t\tsubscriptions: [\n\t\t\t…\n\t\t]\n\t}\n\n#### Update user\n\n\tcurl -X PUT http://localhost:3034/api/users/12345 -H \"Content-Type: application/json\" -d '{ \"account\": \"my-company\" }'\n\n\n### Services\n\n#### Create new service\n\n\tcurl -X POST http://localhost:3034/api/services -H \"Content-Type: application/json\" -d '{ \"name\": \"Image hosting\", \"description\": \"Store unlimited images in our cloud service.\" }'\n\n\n### Plans\n\n#### Create new plan\n\n\tcurl -X POST http://localhost:3034/api/plans -H \"Content-Type: application/json\" -d '{ \"name\": \"Standard package\", \"price\": { \"month\": 9.99 }, \"services\": [\"image-hosting\"] }'\n\n#### List plans\n\n\tcurl -X GET http://localhost:3034/api/plans\n\nOptions:\n\n- `includeVAT`: true or false\n\n#### Get plan info\n\n\tcurl -X GET http://localhost:3034/api/plans/:reference\n\nReturns:\n\n\t{\n\t\treference: 'standard-package',\n\t\tname: 'Standard Package',\n\t\tprice: {\n\t\t\tmonth: 149,\n\t\t\tyear: 1490,\n\t\t\tonce: 150000,\n\t\t\tvatIncluded: true\n\t\t},\n\t\tvat: {\n\t\t\tmonth: 15,\n\t\t\tyear: 149,\n\t\t\tonce: 15000,\n\t\t},\n\t\tservices: {\n\t\t\tremove_watermark: {\n\t\t\t\tname: 'Remove watermark'\n\t\t\t}\n\t\t},\n\t\tconsumables: {\n\t\t\tprojects: {\n\t\t\t\tmax: 10,\n\t\t\t\tper: 'user'***,\n\t\t\t},\n\t\t\tusers: {\n\t\t\t\tmax: 2,\n\t\t\t\tper: 'account',\n\t\t\t}\n\t\t},\n\t}\n\n***Support consumables over time? E.g 10 projects/month.\n\n#### Update plan\n\nPartial update:\n\n\tcurl -X PUT http://localhost:3034/api/accounts/my-company/plans/:reference -H \"Content-Type: application/json\" -d '{ \"services\": [\"video-hosting\"] }'\n\n#### Delete plan\n\n\tcurl -X DELETE http://localhost:3034/api/accounts/my-company/plans/:reference\n\n\n### Subscriptions\n\n#### Start subscription\n\nBy Account:\n\n\tcurl -X POST http://localhost:3034/api/accounts/:accountReference/subscriptions -H \"Content-Type: application/json\" -d '{ \"plan\": \"standard-package\", \"billing\": \"year\", \"paymentMethod\": \"pm_123\" }'\n\nor by User:\n\n\tcurl -X POST http://localhost:3034/api/users/:userReference/subscriptions -H \"Content-Type: application/json\" -d '{ \"plan\": \"standard-package\" }'\n\nNotes:\n\n- `billing` defaults to \"month\".\n- Use `?ignorePaymentProvider=true` to not activate Stripe.\n\n\n#### Update subscription\n\nChange plan, billing cycle, etc.\n\nBy Account:\n\n\tcurl -X PUT http://localhost:3034/api/accounts/:accountReference/subscriptions/:id -H \"Content-Type: application/json\" -d '{ \"plan\": \"enterprise\" }'\n\nor by User:\n\n\tcurl -X PUT http://localhost:3034/api/users/:userReference/subscriptions/:id -H \"Content-Type: application/json\" -d '{ \"plan\": \"enterprise\" }'\n\n\n#### Renew subscription\n\nE.g. called from Stripe webhook:\n\n\tcurl -X POST http://localhost:3034/api/subscriptions/renew\n\nSee “Stripe example webhook” below.\n\nWill send a POST to URL specified in `WEBHOOK_RENEW_SUBSCRIPTION` if successful.\n\n\n#### Stop subscription\n\nNote: when you stop a subscription, it’s not deleted but a `dateStopped` is set and the subscription won’t be listed in Account/User.subscriptions.\n\n\tcurl -X DELETE http://localhost:3034/api/accounts/:accountReference/subscriptions/:id\n\nor:\n\n\tcurl -X DELETE http://localhost:3034/api/users/:userReference/subscriptions/:id\n\n\nStop all subscriptions:\n\n\tcurl -X DELETE http://localhost:3034/api/accounts/:accountReference/subscriptions\n\nor:\n\n\tcurl -X DELETE http://localhost:3034/api/users/:userReference/subscriptions\n\n\n## Implementation\n\nBuilt on Node.js, Express, MongoDB, [mongoose-crudify](https://github.com/ryo718/mongoose-crudify).\n\n\n## Deploying on Heroku\n\n\t# Set up and configure app\n\theroku create MYAPPNAME\n\theroku addons:add mongolab\n\theroku config:set JWT_SECRET=...\n\theroku config:set STRIPE_SECRET_KEY=...\n\theroku config:set WEBHOOK_RENEW_SUBSCRIPTION=...\n\n\n## Payment providers (including Stripe)\n\nStripe is currently the only payment provider supported, but the idea is that it should be easy to add more payment provider integrations to `/app/paymentProviders` and change the `PAYMENT_PROVIDER` environment variable.\n\n* Stripe plan **ID**’s (“This will identify this plan in the API”) are currently derived from Plan reference + billing period, e.g. `basicplan_month`.\n* Stripe customer ID is saved in Accounts `metadata.stripeCustomer`.\n* Stripe subscription ID is saved in Subscriptions `metadata.stripeSubscription`.\n\n### Stripe example webhook\n\nSee https://stripe.com/docs/api#invoice_object\n\nSmaller version with only the fields needed for Subscription Service:\n\n\t{\n\t\t\"type\": \"invoice.payment_succeeded\",\n\t\t\"data\": {\n\t\t\t\"object\": {\n\t\t\t\t\"customer\": \"cus_BpmeYvqhVnkuY9\",\n\t\t\t\t\"subscription\": \"sub_9PpDkJFsxRMEg5\",\n\t\t\t\t\"lines\": {\n\t\t\t\t\t\"data\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"plan\": {\n\t\t\t\t\t\t\t\t\"interval\": \"year\",\n\t\t\t\t\t\t\t\t\"interval_count\": 1\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\nComplete:\n\n\t{\n\t\t\"type\": \"invoice.payment_succeeded\",\n\t\t\"data\": {\n\t\t\t\"object\": {\n\t\t\t\t\"id\": \"in_196zZUCjkwdpPaFTm8GgPYth\",\n\t\t\t\t\"object\": \"invoice\",\n\t\t\t\t\"amount_due\": 11880,\n\t\t\t\t\"application_fee\": null,\n\t\t\t\t\"attempt_count\": 1,\n\t\t\t\t\"attempted\": true,\n\t\t\t\t\"billing\": \"charge_automatically\",\n\t\t\t\t\"charge\": \"ch_196zZUCjkwdpPaFTCG1T4BZX\",\n\t\t\t\t\"closed\": true,\n\t\t\t\t\"currency\": \"sek\",\n\t\t\t\t\"customer\": \"cus_BpmeYvqhVnkuY9\",\n\t\t\t\t\"date\": 1477043056,\n\t\t\t\t\"description\": null,\n\t\t\t\t\"discount\": null,\n\t\t\t\t\"ending_balance\": 0,\n\t\t\t\t\"forgiven\": false,\n\t\t\t\t\"lines\": {\n\t\t\t\t\t\"data\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"id\": \"sub_BpmewCPihjSysf\",\n\t\t\t\t\t\t\t\"object\": \"line_item\",\n\t\t\t\t\t\t\t\"amount\": 2000,\n\t\t\t\t\t\t\t\"currency\": \"sek\",\n\t\t\t\t\t\t\t\"description\": null,\n\t\t\t\t\t\t\t\"discountable\": true,\n\t\t\t\t\t\t\t\"livemode\": true,\n\t\t\t\t\t\t\t\"metadata\": {\n\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"period\": {\n\t\t\t\t\t\t\t\t\"start\": 1514221509,\n\t\t\t\t\t\t\t\t\"end\": 1516899909\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"plan\": {\n\t\t\t\t\t\t\t\t\"id\": \"professional_yearly_10\",\n\t\t\t\t\t\t\t\t\"object\": \"plan\",\n\t\t\t\t\t\t\t\t\"amount\": 9504,\n\t\t\t\t\t\t\t\t\"created\": 1473759356,\n\t\t\t\t\t\t\t\t\"currency\": \"sek\",\n\t\t\t\t\t\t\t\t\"interval\": \"year\",\n\t\t\t\t\t\t\t\t\"interval_count\": 1,\n\t\t\t\t\t\t\t\t\"livemode\": false,\n\t\t\t\t\t\t\t\t\"metadata\": {\n\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"name\": \"Weld professional website (yearly)\",\n\t\t\t\t\t\t\t\t\"statement_descriptor\": null,\n\t\t\t\t\t\t\t\t\"trial_period_days\": null\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"proration\": false,\n\t\t\t\t\t\t\t\"quantity\": 1,\n\t\t\t\t\t\t\t\"subscription\": null,\n\t\t\t\t\t\t\t\"subscription_item\": \"si_BpmejWAFkv1rLv\",\n\t\t\t\t\t\t\t\"type\": \"subscription\"\n\t\t\t\t\t\t}\n\t\t\t\t\t],\n\t\t\t\t\t\"has_more\": false,\n\t\t\t\t\t\"object\": \"list\",\n\t\t\t\t\t\"url\": \"/v1/invoices/in_196zZUCjkwdpPaFTm8GgPYth/lines\"\n\t\t\t\t},\n\t\t\t\t\"livemode\": false,\n\t\t\t\t\"metadata\": {\n\n\t\t\t\t},\n\t\t\t\t\"next_payment_attempt\": null,\n\t\t\t\t\"paid\": true,\n\t\t\t\t\"period_end\": 1477043056,\n\t\t\t\t\"period_start\": 1477043056,\n\t\t\t\t\"receipt_number\": null,\n\t\t\t\t\"starting_balance\": 0,\n\t\t\t\t\"statement_descriptor\": null,\n\t\t\t\t\"subscription\": \"sub_9PpDkJFsxRMEg5\",\n\t\t\t\t\"subtotal\": 9504,\n\t\t\t\t\"tax\": 2376,\n\t\t\t\t\"tax_percent\": 25.0,\n\t\t\t\t\"total\": 11880,\n\t\t\t\t\"webhooks_delivered_at\": 1477043069\n\t\t\t}\n\t\t}\n\t}\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fweld-io%2Fsubscription-service","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fweld-io%2Fsubscription-service","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fweld-io%2Fsubscription-service/lists"}