{"id":19494703,"url":"https://github.com/ceejbot/recurring","last_synced_at":"2025-04-25T21:32:01.928Z","repository":{"id":5497088,"uuid":"6695840","full_name":"ceejbot/recurring","owner":"ceejbot","description":"a node.js client for the recurly recurring billing api","archived":false,"fork":false,"pushed_at":"2023-01-13T01:53:49.000Z","size":404,"stargazers_count":30,"open_issues_count":21,"forks_count":41,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-11-06T09:03:30.585Z","etag":null,"topics":[],"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/ceejbot.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":"2012-11-14T22:12:52.000Z","updated_at":"2021-01-15T04:56:10.000Z","dependencies_parsed_at":"2023-01-14T11:28:11.857Z","dependency_job_id":null,"html_url":"https://github.com/ceejbot/recurring","commit_stats":null,"previous_names":[],"tags_count":31,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ceejbot%2Frecurring","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ceejbot%2Frecurring/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ceejbot%2Frecurring/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ceejbot%2Frecurring/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ceejbot","download_url":"https://codeload.github.com/ceejbot/recurring/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224018311,"owners_count":17242047,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":"2024-11-10T21:32:11.612Z","updated_at":"2024-11-10T21:33:04.668Z","avatar_url":"https://github.com/ceejbot.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"A node client for [recurly](https://recurly.com)'s v2 api, with support for secure parameter signing for [recurly.js](https://docs.recurly.com/recurlyjs) embedded forms.\n\n[![on npm](http://img.shields.io/npm/v/recurring.svg?style=flat)](https://www.npmjs.org/package/recurring)  [![Tests](http://img.shields.io/travis/ceejbot/recurring.svg?style=flat)](http://travis-ci.org/ceejbot/recurring)  [![Dependencies](http://img.shields.io/david/ceejbot/recurring.svg?style=flat)](https://david-dm.org/ceejbot/recurring)  ![io.js supported](https://img.shields.io/badge/io.js-supported-green.svg?style=flat)  \n\n__This code is still in development.__ We do not have complete coverage of the API yet.\n\nThe recurly API has a number of different versions. In order to provide clarity as to which version of the recurly API this package supports, we aim to keep our release versions in sync with the recurly versioning scheme.\n\nThe following versions of the recurring package are currently supported:\n\n| Recurly API version  | NPM dist-tag          | Git development branch\n| -------------------- | --------------------- | -----------------------\n| 2.7                  | recurly-v2.7 (latest) | 2.7 (master)\n| 2.3                  | recurly-v2.3          | 2.3\n\n# Recurly API\n\nAn example of typical usage:\n\n```javascript\nvar Recurring = require('recurring');\nvar recurly = new Recurring();\n\nrecurly.setAPIKey('your-api-key');\nrecurly.setRateLimit(400);\nrecurly.setCache(false);\n\nvar account = recurly.Account();\naccount.id = 'account-uuid';\naccount.fetch(function(err) {\n  account.fetchSubscriptions(function(err, subscriptions {\n    subscriptions[0].cancel(function(err, updated) {\n      console.log(updated.state); // will be 'canceled'\n    });\n  });\n});\n\nrecurly.Account.all(function(err, accounts) {\n  // accounts is an array containing all customer accounts\n});\n\nrecurly.Plan.all(function(err, plans) {\n  // plans is an array containing all plans set up for your account\n});\n\n```\n\n## Configuration\n\n**recurly.setAPIKey()**  \nIn order to access the Recurly API you must supply your API key which can be setterFunc by calling the `setAPIKey()`\nmethod.\n\n```javascript\nvar Recurring = require('recurring');\nvar recurly = new Recurring();\nrecurly.setAPIKey('your-api-key');\n```\n\n**recurly.setRateLimit()**  \nThe recurly API has a rate limit policy in place that prevents excessive calls being made to the API. By default\nsandbox accounts have a limit of 400 requests per minute and live accounts have a limit of 1000 requests per minute.\nIn order to help ensure that you do not exceed these limits Recurring provides a configurable rate limiter.\nThe rate limiter can be configured by calling the `setRateLimit()` method.\n\n```javascript\nvar Recurring = require('recurring');\nvar recurly = new Recurring();\nrecurly.setRateLimit(400);\n```\n\n**recurly.setCache()**\n\nBasic in memory result caching can be enabled by calling the `setCache()` method so that subsequent requests to fetch\nthe same data does not result in additional API calls to Recurly.\n\n```javascript\nvar Recurring = require('recurring');\nvar recurly = new Recurring();\nrecurly.setCache(true);\n```\n\n**recurly.clearCache()**\n\nThe recurly result cache can be cleared by calling the `clearCache()` method.\n\n```javascript\nvar Recurring = require('recurring');\nvar recurly = new Recurring();\nrecurly.clearCache();\n```\n\n## All data types\n\nRecurly is not consistent about how it names the ID fields for each data type. For some it's `uuid` and for others\n`foo_code`. Recurring hides this away: every data type has an `id` property that sets the correct field name for Recurly.\n\n**instance.create()**  \nCreate an object of the given type by POSTing to Recurly.\n\n```javascript\nDataType.create(optionsHash, function(err, object));\n```\n\n**instance.fetch()**  \nFetch an item of a given type from Recurly. The item must have an id.\n\n```javascript\ninstance.fetch(function(err, instance))\n```\n\n**instance.destroy()**  \nDestroy, delete, close, cancel, or otherwise remove the specified object. Invokes http `DELETE` on the item's href. The\nitem must have an id.\n\n```javascript\ninstance.destroy(function(err));\n```\n\n**instance.update()**  \nMost data types have an `update()` method that changes the stored data.\n\n```javascript\ninstance.update(options, function(err, updated));\n```\n\n## Plan\n\n**Plan.all()**  \nFetch a list of plans. Responds with an array of all plans that match the passed-in (optional) filters.\n\n```javascript\nPlan.all(filter, function(err, plans));\n```\n\n**Plan.iterator()**  \nFetch a list of plans. Responds with an async iterator that lazy loads data from recurly in batches of 200.\n\n```javascript\nvar iterators = require('async-iterators');\nvar iterator = Plan.iterator();\niterators.forEachAsync(iterator, function (err, data, next) {\n  ...\n  next();\n});\n```\n\n**plan.fetchAddOns()**  \nFetch plan addons. Responds with a array of plan addons.\n\n```javascript\nplan.fetchAddOns(function(err, addons));\n```\n\n## Account\n\n**Account.all()**  \nFetch a list of accounts. Responds with an array of all accounts that match the passed-in (optional) filters.\n\n```javascript\nAccount.all(filter, function(err, accounts));\n```\n\n**Account.iterator()**  \nFetch a list of accounts. Responds with an async iterator that lazy loads data from recurly in batches of 200.\n\n```javascript\nvar iterators = require('async-iterators');\nvar iterator = Account.iterator();\niterators.forEachAsync(iterator, function (err, data, next) {\n  ...\n  next();\n});\n```\n\n**account.close()**  \nClose an account. Alias for delete.\n\n```javascript\naccount.close(function(err));\n```\n\n**account.reopen()**  \nReopen a closed account:\n\n```javascript\naccount.reopen(function(err, updated));\n```\n\n**account.fetchAdjustments()**\nFetch adjustment information for an account. Responds with an array of adjustments for this account.\n\n```javascript\naccount.fetchAdjustments(function(err, adjustments));\n```\n\n**account.fetchBillingInfo()**  \nFetch billing information for an account. Responds with an BillingInfo object.\n\n```javascript\naccount.fetchBillingInfo(function(err, info));\n```\n\n**account.fetchSubscriptions()**  \nFetch subscription information for an account. Responds with an array of subscriptions for this account.\n\n```javascript\naccount.fetchSubscriptions(function(err, subscriptions));\n```\n\n**account.fetchTransactions()**  \nFetch transaction information for an account. Responds with an array of transactions for this account.\n\n```javascript\naccount.fetchTransactions(function(err, transactions));\n```\n\n**account.fetchInvoices()**  \nFetch invoice information for an account. Responds with an array of invoices for this account.\n\n```javascript\naccount.fetchInvoices(function(err, invoices));\n```\n\n### Billing Info\n\n**billingInfo.update()**  \nAdd/update billing information for an account.\n\n```javascript\nbinfo = recurly.BillingInfo();\nbinfo.account_code = '1234';\nvar billing_data = {\n  first_name: 'Dummy',\n  last_name: 'User',\n  number: '4111-1111-1111-1111',\n  month: 1,\n  year: 2020,\n  verification_value: '123',\n  address1: '760 Market Street',\n  address2: 'Suite 500',\n  city: 'San Francisco',\n  state: 'CA',\n  country: 'USA',\n  zip: '94102'\n};\n\nbinfo.update(billing_data, function(err, binfo) {\n  demand(err).not.exist();\n  binfo.last_four.must.equal('1111');\n});\n```\n\n**Using a billing token**\n\nYou can also update billing information using a recurly.js billing token in place of the raw billing information\n(recommended)\n\n```javascript\nbinfo = recurly.BillingInfo();\nbinfo.account_code = '1234';\nvar billing_data = {\n  token_id: 'bunYTdIdjfJJY6Z87j5NtA' // \u003c- recurly.js billing token.\n};\nbinfo.update(billing_data);\n```\n\n**skipAuthorization**\n\nWhen adding billing information to an account Recurly may ake an authorization attempt against the card which may incur\ncharges depending on your payment gateway. In order to prevent Recurly from making this authorization attempt, a\n``skipAuthorization`` paramater can be supplied along with the billing information.\n\n```javascript\nbinfo = recurly.BillingInfo();\nbinfo.account_code = '1234';\nvar billing_data = {\n  number: '4111-1111-1111-1111',\n  month: 1,\n  year: 2020,\n  skipAuthorization: true // \u003c- do not make authorization request.\n};\nbinfo.update(billing_data);\n```\n\n## Subscription\n\n**Subscription.all()**  \nFetch a list of subscriptions. Responds with an array of all subscriptions that match the passed-in (optional) filters.\n\n```javascript\nSubscription.all(filter, function(err, subscriptions));\n```\n\n**Subscription.iterator()**  \nFetch a list of subscriptions. Responds with an async iterator that lazy loads data from recurly in batches of 200.\n\n```javascript\nvar iterators = require('async-iterators');\nvar iterator = Subscription.iterator();\niterators.forEachAsync(iterator, function (err, data, next) {\n  ...\n  next();\n});\n```\n\n**subscription.cancel()**  \nCancel a subscription.\n\n```javascript\nsubscription.cancel(function(err, updated));\n```\n\n**subscription.reactivate()**  \nReactivate a cancelled subscription.\n\n```javascript\nsubscription.reactivate(function(err, updated));\n```\n\n**subscription.postpone()**  \nPostpone a subscription.\n\n```javascript\nsubscription.postpone(nextRenewalDate, function(err, updated));\n```\n\n**subscription.terminate()**  \nTerminate a subscription using the specific refund type. Valid refund types are 'partial', 'full', and 'none'.\n\n```javascript\nsubscription.terminate(refundType, function(err, updated));\n```\n\n## Coupon\n\n**Coupon.all()**  \nFetch a list of coupons. Responds with an array of all coupons.\n\n```javascript\nCoupon.all(function(err, coupons));\n```\n\n**Coupon.iterator()**  \nFetch a list of coupons. Responds with an async iterator that lazy loads data from recurly in batches of 200.\n\n```javascript\nvar iterators = require('async-iterators');\nvar iterator = Coupon.iterator();\niterators.forEachAsync(iterator, function (err, data, next) {\n  ...\n  next();\n});\n```\n\n**coupon.redeem()**  \nRedeem a coupon.\n\n```javascript\ncoupon.redeem(options, function(err, redemption));\n```\n\n## Redemption\n\n[TODO]\n\n## Transaction\n\n**Transaction.all()**  \nFetch a list of transactions. Responds with an array of all transactions that match the passed-in (optional) filters.\n\n```javascript\nTransaction.all(filter, function(err, transactions));\n```\n\n**Transaction.iterator()**  \nFetch a list of transactions. Responds with an async iterator that lazy loads data from recurly in batches of 200.\n\n```javascript\nvar iterators = require('async-iterators');\nvar iterator = Transaction.iterator();\niterators.forEachAsync(iterator, function (err, data, next) {\n  ...\n  next();\n});\n```\n\n**transaction.refund(amountInCents, function(err)) (DEPRECIATED)**  \nIf amountInCents is omitted, the transaction is refunded in full. Responds with any errors; the transaction object is\nupdated.\n\n## Invoice\n\n**Invoice.all()**  \nFetch a list of invoices. Responds with an array of all invoices that match the passed-in (optional) filters.\n\n```javascript\nInvoice.all(filter, function(err, invoices));\n```\n\n**Invoice.iterator()**  \nFetch a list of invoices. Responds with an async iterator that lazy loads data from recurly in batches of 200.\n\n```javascript\nvar iterators = require('async-iterators');\nvar iterator = Invoice.iterator();\niterators.forEachAsync(iterator, function (err, data, next) {\n  ...\n  next();\n});\n```\n\n**invoice.refund(options, function(err))**  \nIf `options.amount_in_cents` is omitted, the invoice is refunded in full. Responds with any errors; the invoice object is\nupdated.\n\n*options can include:*\n\n - `amount_in_cents` (default: undefined) - The specific amount to be refunded from the original invoice. If left empty, the remaining\n   refundable amount will be refunded.\n\n - `refund_apply_order` (default: 'credit') - If credit line items exist on the invoice, this parameter specifies which\n   refund method to use first. Most relevant in a partial refunds, you can chose to refund credit back to the account\n   first or a transaction giving money back to the customer first. Set as 'credit' or 'transaction'.\n\n**invoice.markSuccessful(function(err))**  \nMark an Invoice as Paid Successfully.\n\n**invoice.markFailed(function(err))**  \nMark an Invoice as Failed Collection.\n\n\n## Errors\n\nAll callbacks follow the node convention of reporting any error in the first parameter. If a transaction with Recurly\nsucceeds but is rejected by Recurly for some reason-- inconsistent data, perhaps, or some other reason-- that err\nparameter is an instance of RecurlyError. The original [transaction errors](http://docs.recurly.com/api/transactions/error-codes)\nreported by Recurly are available as an array of structs in the `errors` parameter. For instance, here's the result of a\nbilling info update with an invalid, expired CC:\n\n```javascript\n{\n\tname: 'RecurlyError',\n\tmessage: '2 transaction errors',\n\terrors: [\n\t\t{\n\t\t\tfield: 'billing_info.number',\n\t\t\tsymbol: 'invalid',\n\t\t\tmessage: 'is not a valid credit card number'\n\t\t},\n\t\t{\n\t\t\tfield: 'billing_info.number',\n\t\t\tsymbol: 'expired',\n\t\t\tmessage: 'is expired or has an invalid expiration date'\n\t\t}\n\t]\n}\n\n```\n\n## SignedQuery\n\nThis provides the back-end support for signing parameters for forms embedded using recurly.js. See Recurly's [signature documentation](https://docs.recurly.com/api/recurlyjs/signatures) for details on which parameters must be signed for\neach form type.\n\n```javascript\nvar Recurring = require('recurring');\nvar recurly = new Recurring();\n\nvar signer = new recurly.SignedQuery('your-private-api-key');\nsigner.set('account', { account_code: 'account-id' });\nvar signedParameters = signer.toString();\n```\n\nThe `nonce` \u0026 `timestamp` parameters are generated for you if you don't provide them. The nonce is created using [node-uuid](https://github.com/broofa/node-uuid).\n\n## FormResponseToken\n\nAfter Recurly handles a form submission, it posts to you a token pointing to the form\nresults. Use a FormResponseToken object to fetch the results object represented by the token.\n\n```javascript\nvar Recurring = require('recurring');\nvar recurly = new Recurring();\n\nvar recurlyResponse = new recurly.FormResponseToken(token, 'subscription');\nrecurlyResponse.process(function(err, subscription) {\n\tif (err)\n\t\treturn handleError(err);\n\n\t// subscription contains the new subscription data;\n});\n```\n\nHaving to hint about the type of the response is clunky; TODO fix.\n\n## Contributing\n\nUnit tests for whatever you fix/implement/improve would be awesome. Recurring's are written with [mocha](http://visionmedia.github.com/mocha/) and [chai](http://chaijs.com).\n\n## License\n\nMIT. See accompanying LICENSE file.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fceejbot%2Frecurring","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fceejbot%2Frecurring","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fceejbot%2Frecurring/lists"}