├── .gitignore ├── .rustfmt.toml ├── .travis.yml ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README ├── examples ├── create_charge.rs ├── create_customer.rs ├── create_customer_with_card.rs └── list_customers.rs ├── src ├── client.rs ├── error.rs ├── ids.rs ├── lib.rs ├── params.rs └── resources │ ├── account.rs │ ├── address.rs │ ├── application_fee.rs │ ├── application_refund.rs │ ├── balance.rs │ ├── bank_account.rs │ ├── card.rs │ ├── charge.rs │ ├── coupon.rs │ ├── currency.rs │ ├── customer.rs │ ├── deleted.rs │ ├── discount.rs │ ├── dispute.rs │ ├── event.rs │ ├── file.rs │ ├── invoice_item.rs │ ├── invoices.rs │ ├── mod.rs │ ├── order.rs │ ├── order_return.rs │ ├── payment_source.rs │ ├── payout.rs │ ├── plan.rs │ ├── product.rs │ ├── refund.rs │ ├── review.rs │ ├── scheduled_query.rs │ ├── sku.rs │ ├── subscription.rs │ ├── transaction.rs │ └── transfer.rs └── tests ├── encoding.rs ├── example.rs └── sync.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | fn_call_width = 80 2 | max_width = 120 3 | error_on_line_overflow = false 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - stable 4 | - beta 5 | - nightly 6 | matrix: 7 | allow_failures: 8 | - rust: nightly 9 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Version 0.5.0 (Sep 26, 2018) 2 | 3 | ## New Features 4 | 5 | * Implemented the [sources resource](https://stripe.com/docs/api#sources) and 6 | added the `Source` type . 7 | 8 | ## Breaking Changes 9 | 10 | * The `CustomerSourceParams` struct was renamed to `PaymentSourceParams`. 11 | * The `Source` enum was renamed to `PaymentSource` (there is a new `Source` struct). 12 | * Source and token fields (like `token: &str`) now use `source: SourceId` or `token: TokenId` instead. 13 | 14 | ## General Improvements 15 | 16 | * Added missing `default_source` field to `Customer`. 17 | * The `Deserialize` and `Serialize` traits have now been implemented for all param and resource structs. 18 | * The `Copy`, `Clone`, `Eq`, `PartialEq`, and `Hash` traits have been derived for flat enum types. 19 | 20 | # Version 0.4.7 (Jun 11, 2018) 21 | 22 | ## Changes 23 | 24 | * Fix, adds all missing error code variants to `stripe::error::ErrorCode`. 25 | 26 | # Version 0.4.6 (Jun 9, 2018) 27 | 28 | ## Changes 29 | 30 | * Fixed field `nickname` of `Plan` can be null. 31 | 32 | # Version 0.4.5 (Feb 20, 2018) 33 | 34 | ## Changes 35 | 36 | * Fixed field `nickname` of `Plan` should be `name` 37 | 38 | # Version 0.4.4 (Jan 4, 2018) 39 | 40 | ## Breaking Changes 41 | 42 | * The `balance_transaction` field of `Charge` is now `Option<_>`. 43 | 44 | # Version 0.4.2 (August 20, 2017) 45 | 46 | ## Changes 47 | 48 | * Added basic crate documentation 49 | * Added the `invoice.upcoming` event 50 | 51 | # Version 0.4.1 (August 8, 2017) 52 | 53 | ## Changes 54 | 55 | * Add RangeQuery struct for created/date filters in list requests 56 | * Implement `Customer::list` request (ie. "GET /customers"); Thanks @pocket7878 57 | * Add missing params to `InvoiceListParams` for `Invoice::list` 58 | 59 | # Version 0.4.0 (August 2, 2017) 60 | 61 | ## Breaking Changes 62 | 63 | * Upgrade Serde to v1.0 64 | 65 | # Version 0.3.3 (August 1, 2017) 66 | 67 | ## Changes 68 | 69 | * Add support for authentication using the Stripe-Account header 70 | * Implement `Event` struct for implementing a Stripe Webhook (only some events) 71 | * Implement `Invoice::update` request (ie. POST "/invoices/{invoice_id}") 72 | * Implement `InvoiceItem::create` request (ie. POST "/invoiceitems") 73 | * Fix `Subscription::cancel` request (previously used wrong method/path) 74 | 75 | # Version 0.3.2 (June 17, 2017) 76 | 77 | ## Changes 78 | 79 | * Implemented the `Invoice::list` API (ie. "/invoices") 80 | * Fixed a request encoding error for `Invoice::pay` (ie. "/invoices/{invoice_id}/pay") 81 | * Fixed fields on `Subscription` that could be null but were missing `Optional<..>` 82 | * Added missing `last4` field to `Card` resource 83 | * Changed the repository URL 84 | 85 | # Version 0.3.1 (Mar 31, 2017) 86 | 87 | ## Changes 88 | 89 | * Made rust docs slightly easier to read 90 | * Fixed incorrect method name for `Plan` resource 91 | * Use `native-tls` by default and add feature-flag supporting `openssl` 92 | 93 | # Version 0.3.0 (Mar 28, 2017) 94 | 95 | ## New Features 96 | 97 | * Implemented the [charges resource](https://stripe.com/docs/api#charges) and 98 | added the `Charge` type. 99 | 100 | ## Breaking Changes 101 | 102 | * The `Resource::get` requests have been renamed to `Resource::retrieve`. 103 | * The `Subscription::cancel` request now expects `CancelParams` instead of 104 | expecting a one-off function argument. 105 | * Removed the `blame` method and `Blame` type from errors. 106 | * The `Error::Decode` and `Error::Encode` variants have been combined into a 107 | single `Error::Conversion` variant. 108 | 109 | ## General Improvements 110 | 111 | * The `Error` type now has easier to read error messages and will parses JSON 112 | errors returned by Stripe into a structured error type (`RequestError`). 113 | * Added Travis CI for automated testing on GitHub. 114 | * Added reference documentation to implemented resources (but still no docs at 115 | crate/module level nor a "Getting started" guide) 116 | 117 | 118 | # Version 0.2.0 (Mar 17, 2017) 119 | 120 | ## New Features 121 | 122 | * Added `Client` which is created once with a stripe private key and is 123 | intended to be re-used for multiple requests. It implements `Sync` so you 124 | can share it among multiple threads. 125 | * Added new strongly-typed `Currency` type following the example of 126 | https://github.com/stripe/stripe-go. 127 | * `Customer::create`/`CustomerParams` now support using `CardParams` as a 128 | source instead of just tokens. 129 | * Implemented the [sources API](https://stripe.com/docs/api#sources) in the `Source` type. 130 | 131 | ## Breaking Changes 132 | 133 | * All `Params` types now use `&str` fields instead of `String`s. 134 | * Requests used to require a `stripe_key: &str` as their final argument but 135 | now use a `&Client` as the first argument instead. 136 | * Stripe tokens used to be directly used as a source in `CustomerParams` but 137 | now must be used with `CustomerSourceParams::Token("tok_xyzABC123")`. 138 | 139 | ## General Improvements 140 | 141 | * Added remaining fields to `Params` types after switching from 142 | `serde_urlencoded` to `serde_qs` to support nested params. 143 | * Added the `create_customer` example 144 | * Types that implement `Deserialize` now also implement `Debug`. 145 | * Types that implement `Serialize` now also implement `Default`. 146 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stripe-rust" # b.c. stripe and stripe-rs were already taken 3 | version = "0.5.0" 4 | description = "API bindings for the Stripe v1 HTTP API" 5 | authors = [ 6 | "Anna Baldwin ", 7 | "Kevin Stenerson " 8 | ] 9 | license = "MIT/Apache-2.0" 10 | readme = "README.md" 11 | repository = "https://github.com/wyyerd/stripe-rs" 12 | documentation = "https://docs.rs/stripe-rust" 13 | keywords = ["stripe", "v1", "api"] 14 | categories = ["api-bindings"] 15 | 16 | [badges] 17 | travis-ci = {repository = "wyyerd/stripe-rs"} 18 | 19 | [features] 20 | default = ["with-rustls"] 21 | with-rustls = ["hyper-rustls"] 22 | with-openssl = ["hyper-openssl"] 23 | 24 | [lib] 25 | name = "stripe" 26 | 27 | [dependencies] 28 | chrono = { version = "0.4", features = ["serde"] } 29 | hmac = "^0.1" 30 | hyper = "^0.10" 31 | hyper-rustls = { version = "^0.6", optional = true } 32 | hyper-openssl = { version = "^0.2", optional = true } 33 | serde = "^1.0" 34 | serde_derive = "^1.0" 35 | serde_json = "^1.0" 36 | serde_qs = "^0.2" 37 | sha2 = "^0.5" 38 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Rapidity Networks, Inc. 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | stripe-rust 2 | =========== 3 | 4 | This project has moved to https://github.com/wyyerd/stripe-rs 5 | -------------------------------------------------------------------------------- /examples/create_charge.rs: -------------------------------------------------------------------------------- 1 | extern crate stripe; 2 | 3 | use std::env; 4 | 5 | fn main() { 6 | // Create a new client 7 | let secret_key = env::var("STRIPE_SECRET_KEY").expect("Missing STRIPE_SECRET_KEY in env"); 8 | let client = stripe::Client::new(secret_key); 9 | 10 | // Define a card to charge 11 | let mut card = stripe::CardParams::default(); 12 | card.number = "4242424242424242"; 13 | card.exp_month = "10"; 14 | card.exp_year = "20"; 15 | 16 | // Define the charge 17 | let mut params = stripe::ChargeParams::default(); 18 | params.amount = Some(1000); 19 | params.source = Some(stripe::PaymentSourceParams::Card(card)); 20 | 21 | // Create the charge 22 | let charge = stripe::Charge::create(&client, params).unwrap(); 23 | 24 | // Output in a ~prettyprint format 25 | println!( 26 | "Charge {{ 27 | id: {:?}, 28 | amount: {:?}, 29 | created: {:?}, 30 | status: {:?}, 31 | .. 32 | }}", 33 | charge.id, 34 | charge.amount, 35 | charge.created, 36 | charge.status 37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /examples/create_customer.rs: -------------------------------------------------------------------------------- 1 | extern crate stripe; 2 | 3 | use std::env; 4 | use stripe::{Customer, CustomerParams, PaymentSourceParams}; 5 | 6 | fn main() { 7 | // Create a new client 8 | let secret_key = env::var("STRIPE_SECRET_KEY").expect("Missing STRIPE_SECRET_KEY in env"); 9 | let client = stripe::Client::new(secret_key); 10 | 11 | // Create the customer 12 | let token = "tok_189g322eZvKYlo2CeoPw2sdy".parse().expect("expected token to be valid"); 13 | let customer = Customer::create( 14 | &client, 15 | CustomerParams { 16 | email: Some("jdoe@example.org"), 17 | source: Some(PaymentSourceParams::Token(token)), 18 | default_source: None, 19 | 20 | // TODO: Keep track of https://github.com/rust-lang/rust-roadmap/issues/17 21 | // so we can use default struct field value syntax eventually 22 | account_balance: None, 23 | business_vat_id: None, 24 | coupon: None, 25 | description: None, 26 | metadata: None, 27 | shipping: None, 28 | }, 29 | ).unwrap(); 30 | 31 | 32 | // Output in a ~prettyprint format 33 | println!( 34 | "Customer {{ 35 | id: {:?}, 36 | created: {:?}, 37 | default_source: {:?}, 38 | email: {:?}, 39 | .. 40 | }}", 41 | customer.id, 42 | customer.created, 43 | customer.default_source, 44 | customer.email 45 | ); 46 | } 47 | -------------------------------------------------------------------------------- /examples/create_customer_with_card.rs: -------------------------------------------------------------------------------- 1 | extern crate stripe; 2 | 3 | use std::env; 4 | 5 | fn main() { 6 | // Create a new client 7 | let secret_key = env::var("STRIPE_SECRET_KEY").expect("Missing STRIPE_SECRET_KEY in env"); 8 | let client = stripe::Client::new(secret_key); 9 | 10 | // Define a card for the customer 11 | let mut card = stripe::CardParams::default(); 12 | card.number = "4242424242424242"; 13 | card.exp_month = "10"; 14 | card.exp_year = "20"; 15 | 16 | // Define the customer 17 | let mut params = stripe::CustomerParams::default(); 18 | params.email = Some("jdoe@example.org"); 19 | params.source = Some(stripe::PaymentSourceParams::Card(card)); 20 | 21 | // Perform request 22 | let customer = stripe::Customer::create(&client, params).unwrap(); 23 | 24 | // Output in a ~prettyprint format 25 | println!( 26 | "Customer {{ 27 | id: {:?}, 28 | created: {:?}, 29 | default_source: {:?}, 30 | email: {:?}, 31 | .. 32 | }}", 33 | customer.id, 34 | customer.created, 35 | customer.default_source, 36 | customer.email 37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /examples/list_customers.rs: -------------------------------------------------------------------------------- 1 | extern crate stripe; 2 | 3 | use std::env; 4 | use stripe::{Customer, CustomerListParams, RangeQuery, RangeBounds}; 5 | 6 | fn main() { 7 | // Create a new client 8 | let secret_key = env::var("STRIPE_SECRET_KEY").expect("Missing STRIPE_SECRET_KEY in env"); 9 | let client = stripe::Client::new(secret_key); 10 | 11 | // List customers 12 | let customers = Customer::list( 13 | &client, 14 | CustomerListParams { 15 | created: Some(RangeQuery::gte(1501598702)), 16 | ending_before: None, 17 | limit: Some(3), 18 | starting_after: None, 19 | }, 20 | ).unwrap(); 21 | 22 | // Print the first three customers 23 | println!("{:?}", customers); 24 | 25 | // List the next three customers (using default) 26 | let mut params = CustomerListParams::default(); 27 | params.limit = Some(3); 28 | params.starting_after = customers.data.last().map(|cust| cust.id.as_str()); 29 | let customers2 = Customer::list(&client, params).unwrap(); 30 | 31 | // Print the following three customers 32 | println!("{:?}", customers2); 33 | 34 | // List all customers within a given time range 35 | let range = RangeQuery::Bounds(RangeBounds { 36 | gt: None, 37 | gte: Some(customers.data[0].created as i64), 38 | lt: None, 39 | lte: customers2.data.last().map(|cust| cust.created as i64), 40 | }); 41 | let mut params = CustomerListParams::default(); 42 | params.created = Some(range); 43 | let customers3 = Customer::list(&client, params).unwrap(); 44 | 45 | // Print all customers create in the time range 46 | println!("{:?}", customers3); 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/client.rs: -------------------------------------------------------------------------------- 1 | use error::{Error, ErrorObject, RequestError}; 2 | use hyper; 3 | use hyper::client::RequestBuilder; 4 | use hyper::header::{Authorization, Basic, ContentType, Headers}; 5 | use hyper::net::HttpsConnector; 6 | use serde; 7 | use serde_json as json; 8 | use serde_qs as qs; 9 | use std::io::Read; 10 | 11 | #[derive(Clone, Default)] 12 | pub struct Params { 13 | pub stripe_account: Option, 14 | } 15 | 16 | // TODO: #[derive(Clone)] 17 | pub struct Client { 18 | client: hyper::Client, 19 | secret_key: String, 20 | params: Params, 21 | } 22 | 23 | // TODO: With Hyper 0.11.x, hyper::Client implements clone, and we can just derive this 24 | impl Clone for Client { 25 | fn clone(&self) -> Self { 26 | let mut client = Client::new(self.secret_key.as_str()); 27 | client.params = self.params.clone(); 28 | client 29 | } 30 | } 31 | 32 | impl Client { 33 | fn url(path: &str) -> String { 34 | format!("https://api.stripe.com/v1/{}", &path[1..]) 35 | } 36 | 37 | #[cfg(feature = "with-rustls")] 38 | pub fn new>(secret_key: Str) -> Client { 39 | use hyper_rustls::TlsClient; 40 | 41 | let tls = TlsClient::new(); 42 | let connector = HttpsConnector::new(tls); 43 | let client = hyper::Client::with_connector(connector); 44 | Client { 45 | client: client, 46 | secret_key: secret_key.into(), 47 | params: Params::default(), 48 | } 49 | } 50 | 51 | #[cfg(feature = "with-openssl")] 52 | pub fn new>(secret_key: Str) -> Client { 53 | use hyper_openssl::OpensslClient; 54 | 55 | let tls = OpensslClient::new().unwrap(); 56 | let connector = HttpsConnector::new(tls); 57 | let client = hyper::Client::with_connector(connector); 58 | Client { 59 | client: client, 60 | secret_key: secret_key.into(), 61 | params: Params::default(), 62 | } 63 | } 64 | 65 | /// Clones a new client with different params. 66 | /// 67 | /// This is the recommended way to send requests for many different Stripe accounts 68 | /// or with different Meta, Extra, and Expand params while using the same secret key. 69 | pub fn with(&self, params: Params) -> Client { 70 | let mut client = self.clone(); 71 | client.params = params; 72 | client 73 | } 74 | 75 | /// Sets a value for the Stripe-Account header 76 | /// 77 | /// This is recommended if you are acting as only one Account for the lifetime of the client. 78 | /// Otherwise, prefer `client.with(Params{stripe_account: "acct_ABC", ..})`. 79 | pub fn set_stripe_account>(&mut self, account_id: Str) { 80 | self.params.stripe_account = Some(account_id.into()); 81 | } 82 | 83 | pub fn get(&self, path: &str) -> Result { 84 | let url = Client::url(path); 85 | let request = self.client.get(&url).headers(self.headers()); 86 | send(request) 87 | } 88 | 89 | pub fn post(&self, path: &str, params: P) -> Result { 90 | let url = Client::url(path); 91 | let body = qs::to_string(¶ms)?; 92 | let request = self.client.post(&url).headers(self.headers()).body(&body); 93 | send(request) 94 | } 95 | 96 | pub fn post_empty(&self, path: &str) -> Result { 97 | let url = Client::url(path); 98 | let request = self.client.post(&url).headers(self.headers()); 99 | send(request) 100 | } 101 | 102 | pub fn delete(&self, path: &str) -> Result { 103 | let url = Client::url(path); 104 | let request = self.client.delete(&url).headers(self.headers()); 105 | send(request) 106 | } 107 | 108 | fn headers(&self) -> Headers { 109 | let mut headers = Headers::new(); 110 | headers.set(Authorization(Basic { 111 | username: self.secret_key.clone(), 112 | password: None, 113 | })); 114 | headers.set(ContentType::form_url_encoded()); 115 | if let Some(ref account) = self.params.stripe_account { 116 | headers.set_raw("Stripe-Account", vec![account.as_bytes().to_vec()]); 117 | } 118 | headers 119 | } 120 | } 121 | 122 | fn send(request: RequestBuilder) -> Result { 123 | let mut response = request.send()?; 124 | let mut body = String::with_capacity(4096); 125 | response.read_to_string(&mut body)?; 126 | 127 | let status = response.status_raw().0; 128 | match status { 129 | 200...299 => {} 130 | _ => { 131 | let mut err = json::from_str(&body).unwrap_or_else(|err| { 132 | let mut req = ErrorObject { error: RequestError::default() }; 133 | req.error.message = Some(format!("failed to deserialize error: {}", err)); 134 | req 135 | }); 136 | err.error.http_status = status; 137 | return Err(Error::from(err.error)); 138 | } 139 | } 140 | 141 | json::from_str(&body).map_err(|err| Error::from(err)) 142 | } 143 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | extern crate hyper; 2 | extern crate serde_json as json; 3 | extern crate serde_qs as qs; 4 | 5 | use params::to_snakecase; 6 | use std::error; 7 | use std::fmt; 8 | use std::io; 9 | use std::num::ParseIntError; 10 | 11 | /// An error encountered when communicating with the Stripe API. 12 | #[derive(Debug)] 13 | pub enum Error { 14 | /// An error reported by Stripe. 15 | Stripe(RequestError), 16 | /// A networking error communicating with the Stripe server. 17 | Http(hyper::Error), 18 | /// An error reading the response body. 19 | Io(io::Error), 20 | /// An error converting between wire format and Rust types. 21 | Conversion(Box), 22 | } 23 | 24 | impl fmt::Display for Error { 25 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 26 | f.write_str(error::Error::description(self))?; 27 | match *self { 28 | Error::Stripe(ref err) => write!(f, ": {}", err), 29 | Error::Http(ref err) => write!(f, ": {}", err), 30 | Error::Io(ref err) => write!(f, ": {}", err), 31 | Error::Conversion(ref err) => write!(f, ": {}", err), 32 | } 33 | } 34 | } 35 | 36 | impl error::Error for Error { 37 | fn description(&self) -> &str { 38 | match *self { 39 | Error::Stripe(_) => "error reported by stripe", 40 | Error::Http(_) => "error communicating with stripe", 41 | Error::Io(_) => "error reading response from stripe", 42 | Error::Conversion(_) => "error converting between wire format and Rust types", 43 | } 44 | } 45 | 46 | fn cause(&self) -> Option<&error::Error> { 47 | match *self { 48 | Error::Stripe(ref err) => Some(err), 49 | Error::Http(ref err) => Some(err), 50 | Error::Io(ref err) => Some(err), 51 | Error::Conversion(ref err) => Some(&**err), 52 | } 53 | } 54 | } 55 | 56 | impl From for Error { 57 | fn from(err: RequestError) -> Error { 58 | Error::Stripe(err) 59 | } 60 | } 61 | 62 | impl From for Error { 63 | fn from(err: hyper::Error) -> Error { 64 | Error::Http(err) 65 | } 66 | } 67 | 68 | impl From for Error { 69 | fn from(err: io::Error) -> Error { 70 | Error::Io(err) 71 | } 72 | } 73 | 74 | impl From for Error { 75 | fn from(err: qs::Error) -> Error { 76 | Error::Conversion(Box::new(err)) 77 | } 78 | } 79 | 80 | impl From for Error { 81 | fn from(err: json::Error) -> Error { 82 | Error::Conversion(Box::new(err)) 83 | } 84 | } 85 | 86 | 87 | /// The list of possible values for a RequestError's type. 88 | #[derive(Debug, PartialEq, Deserialize)] 89 | pub enum ErrorType { 90 | #[serde(skip_deserializing)] 91 | Unknown, 92 | 93 | #[serde(rename = "api_error")] 94 | Api, 95 | #[serde(rename = "api_connection_error")] 96 | Connection, 97 | #[serde(rename = "authentication_error")] 98 | Authentication, 99 | #[serde(rename = "card_error")] 100 | Card, 101 | #[serde(rename = "invalid_request_error")] 102 | InvalidRequest, 103 | #[serde(rename = "rate_limit_error")] 104 | RateLimit, 105 | #[serde(rename = "validation_error")] 106 | Validation, 107 | } 108 | 109 | impl Default for ErrorType { 110 | fn default() -> Self { 111 | ErrorType::Unknown 112 | } 113 | } 114 | 115 | impl fmt::Display for ErrorType { 116 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 117 | write!(f, "{}", to_snakecase(&format!("{:?}Error", self))) 118 | } 119 | } 120 | 121 | /// The list of possible values for a RequestError's code. 122 | #[derive(Debug, Deserialize, Serialize, Eq, PartialEq, Hash)] 123 | #[serde(rename_all = "snake_case")] 124 | pub enum ErrorCode { 125 | AccountAlreadyExists, 126 | AccountCountryInvalidAddress, 127 | AccountInvalid, 128 | AccountNumberInvalid, 129 | AlipayUpgradeRequired, 130 | AmountTooLarge, 131 | AmountTooSmall, 132 | ApiKeyExpired, 133 | BalanceInsufficient, 134 | BankAccountExists, 135 | BankAccountUnusable, 136 | BankAccountUnverified, 137 | BitcoinUpgradeRequired, 138 | CardDeclined, 139 | ChargeAlreadyCaptured, 140 | ChargeAlreadyRefunded, 141 | ChargeDisputed, 142 | ChargeExpiredForCapture, 143 | CountryUnsupported, 144 | CouponExpired, 145 | CustomerMaxSubscriptions, 146 | EmailInvalid, 147 | ExpiredCard, 148 | IncorrectAddress, 149 | IncorrectCvc, 150 | IncorrectNumber, 151 | IncorrectZip, 152 | InstantPayoutsUnsupported, 153 | InvalidCardType, 154 | InvalidChargeAmount, 155 | InvalidCvc, 156 | InvalidExpiryMonth, 157 | InvalidExpiryYear, 158 | InvalidNumber, 159 | InvalidSourceUsage, 160 | InvoiceNoCustomerLineItems, 161 | InvoiceNoSubscriptionLineItems, 162 | InvoiceNotEditable, 163 | InvoiceUpcomingNone, 164 | LivemodeMismatch, 165 | Missing, 166 | OrderCreationFailed, 167 | OrderRequiredSettings, 168 | OrderStatusInvalid, 169 | OrderUpstreamTimeout, 170 | OutOfInventory, 171 | ParameterInvalidEmpty, 172 | ParameterInvalidInteger, 173 | ParameterInvalidStringBlank, 174 | ParameterInvalidStringEmpty, 175 | ParameterMissing, 176 | ParameterUnknown, 177 | PaymentMethodUnactivated, 178 | PayoutsNotAllowed, 179 | PlatformApiKeyExpired, 180 | PostalCodeInvalid, 181 | ProcessingError, 182 | ProductInactive, 183 | RateLimit, 184 | ResourceAlreadyExists, 185 | ResourceMissing, 186 | RoutingNumberInvalid, 187 | SecretKeyRequired, 188 | SepaUnsupportedAccount, 189 | ShippingCalculationFailed, 190 | SkuInactive, 191 | StateUnsupported, 192 | TaxIdInvalid, 193 | TaxesCalculationFailed, 194 | TestmodeChargesOnly, 195 | TlsVersionUnsupported, 196 | TokenAlreadyUsed, 197 | TokenInUse, 198 | TransfersNotAllowed, 199 | UpstreamOrderCreationFailed, 200 | UrlInvalid, 201 | #[doc(hidden)] __NonExhaustive, 202 | } 203 | 204 | impl fmt::Display for ErrorCode { 205 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 206 | write!(f, "{}", to_snakecase(&format!("{:?}", self))) 207 | } 208 | } 209 | 210 | /// An error reported by stripe in a request's response. 211 | /// 212 | /// For more details see https://stripe.com/docs/api#errors. 213 | #[derive(Debug, Default, Deserialize)] 214 | pub struct RequestError { 215 | /// The HTTP status in the response. 216 | #[serde(skip_deserializing)] 217 | pub http_status: u16, 218 | 219 | /// The type of error returned. 220 | #[serde(rename = "type")] 221 | pub error_type: ErrorType, 222 | 223 | /// A human-readable message providing more details about the error. 224 | /// For card errors, these messages can be shown to end users. 225 | #[serde(default)] 226 | pub message: Option, 227 | 228 | /// For card errors, a value describing the kind of card error that occured. 229 | pub code: Option, 230 | 231 | /// For card errors resulting from a bank decline, a string indicating the 232 | /// bank's reason for the decline if they provide one. 233 | pub decline_code: Option, 234 | 235 | /// The ID of the failed charge, if applicable. 236 | pub charge: Option, 237 | } 238 | 239 | impl fmt::Display for RequestError { 240 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 241 | write!(f, "{}({})", self.error_type, self.http_status)?; 242 | if let Some(ref message) = self.message { 243 | write!(f, ": {}", message)?; 244 | } 245 | Ok(()) 246 | } 247 | } 248 | 249 | impl error::Error for RequestError { 250 | fn description(&self) -> &str { 251 | self.message.as_ref().map(|s| s.as_str()).unwrap_or( 252 | "request error", 253 | ) 254 | } 255 | } 256 | 257 | #[doc(hidden)] 258 | #[derive(Deserialize)] 259 | pub struct ErrorObject { 260 | pub error: RequestError, 261 | } 262 | 263 | /// An error encountered when communicating with the Stripe API webhooks. 264 | #[derive(Debug)] 265 | pub enum WebhookError { 266 | BadHeader(ParseIntError), 267 | BadSignature, 268 | BadTimestamp(i64), 269 | BadParse(json::Error), 270 | } 271 | 272 | impl fmt::Display for WebhookError { 273 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 274 | f.write_str(error::Error::description(self))?; 275 | match *self { 276 | WebhookError::BadHeader(ref err) => write!(f, ": {}", err), 277 | WebhookError::BadSignature => write!(f, "Signatures do not match"), 278 | WebhookError::BadTimestamp(ref err) => write!(f, ": {}", err), 279 | WebhookError::BadParse(ref err) => write!(f, ": {}", err), 280 | } 281 | } 282 | } 283 | 284 | impl error::Error for WebhookError { 285 | fn description(&self) -> &str { 286 | match *self { 287 | WebhookError::BadHeader(_) => "error parsing timestamp", 288 | WebhookError::BadSignature => "error comparing signatures", 289 | WebhookError::BadTimestamp(_) => "error comparing timestamps - over tolerance", 290 | WebhookError::BadParse(_) => "error parsing event object", 291 | } 292 | } 293 | 294 | fn cause(&self) -> Option<&error::Error> { 295 | match *self { 296 | WebhookError::BadHeader(ref err) => Some(err), 297 | WebhookError::BadSignature => None, 298 | WebhookError::BadTimestamp(_) => None, 299 | WebhookError::BadParse(ref err) => Some(err), 300 | } 301 | } 302 | } 303 | -------------------------------------------------------------------------------- /src/ids.rs: -------------------------------------------------------------------------------- 1 | #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] 2 | pub struct TokenId(String); 3 | 4 | impl ::std::fmt::Display for TokenId { 5 | fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { 6 | self.0.fmt(f) 7 | } 8 | } 9 | 10 | impl ::std::str::FromStr for TokenId { 11 | type Err = ParseIdError; 12 | 13 | fn from_str(s: &str) -> Result { 14 | if !s.starts_with("tok_") { 15 | Err(ParseIdError { prefix: "tok_" }) 16 | } else { 17 | Ok(TokenId(s.to_owned())) 18 | } 19 | } 20 | } 21 | 22 | impl ::serde::Serialize for TokenId { 23 | fn serialize(&self, serializer: S) -> Result 24 | where S: ::serde::ser::Serializer 25 | { 26 | self.to_string().serialize(serializer) 27 | } 28 | } 29 | 30 | impl<'de> ::serde::Deserialize<'de> for TokenId { 31 | fn deserialize(deserializer: D) -> Result 32 | where D: ::serde::de::Deserializer<'de> 33 | { 34 | let s: String = ::serde::Deserialize::deserialize(deserializer)?; 35 | s.parse::().map_err(|e| ::serde::de::Error::custom(e)) 36 | } 37 | } 38 | 39 | #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] 40 | pub struct SourceId(String); 41 | 42 | impl ::std::fmt::Display for SourceId { 43 | fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { 44 | self.0.fmt(f) 45 | } 46 | } 47 | 48 | impl ::std::str::FromStr for SourceId { 49 | type Err = ParseIdError; 50 | 51 | fn from_str(s: &str) -> Result { 52 | if !s.starts_with("src_") { 53 | Err(ParseIdError { prefix: "src_" }) 54 | } else { 55 | Ok(SourceId(s.to_owned())) 56 | } 57 | } 58 | } 59 | 60 | impl ::serde::Serialize for SourceId { 61 | fn serialize(&self, serializer: S) -> Result 62 | where S: ::serde::ser::Serializer 63 | { 64 | self.to_string().serialize(serializer) 65 | } 66 | } 67 | 68 | impl<'de> ::serde::Deserialize<'de> for SourceId { 69 | fn deserialize(deserializer: D) -> Result 70 | where D: ::serde::de::Deserializer<'de> 71 | { 72 | let s: String = ::serde::Deserialize::deserialize(deserializer)?; 73 | s.parse::().map_err(|e| ::serde::de::Error::custom(e)) 74 | } 75 | } 76 | 77 | #[derive(Debug)] 78 | pub struct ParseIdError { prefix: &'static str } 79 | 80 | impl ::std::fmt::Display for ParseIdError { 81 | fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { 82 | write!(f, "expected id to start with '{}'", self.prefix) 83 | } 84 | } 85 | 86 | impl ::std::error::Error for ParseIdError { 87 | fn description(&self) -> &str { 88 | "error parsing id" 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Rapidity Networks, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | #![doc(html_root_url = "https://docs.rs/stripe-rust/")] 10 | 11 | //! This crate provides Rust bindings to the Stripe HTTP API. 12 | //! 13 | //! ## Getting Started 14 | //! 15 | //! To get started, we need to create a client: 16 | //! 17 | //! ```rust 18 | //! let client = stripe::Client::new("sk_test_YOUR_STRIPE_SECRET"); 19 | //! ``` 20 | //! 21 | //! Then we can begin making requests as we'd like. Most Stripe requests accept 22 | //! many optional parameters, so we usually get the `::default()` params and then 23 | //! set the ones we want from there. 24 | //! 25 | //! Most requests for creating or updating a Stripe object use the same Rust struct, 26 | //! so you may frequently need to refer to the [official API docs](https://stripe.com/docs/api) 27 | //! to determine which fields are required for either request. 28 | //! 29 | //! ```rust,ignore 30 | //! /* Creating a Stripe Charge */ 31 | //! 32 | //! let token = "TOKEN_FROM_CHECKOUT"; 33 | //! let mut params = stripe::ChargeParams::default(); 34 | //! // NOTE: Stripe represents currency in the lowest denominations (e.g. cents) 35 | //! params.amount = Some(1095); // e.g. $10.95 36 | //! params.source = Some(stripe::PaymentSourceParams::Token(token)); 37 | //! 38 | //! // Example: Override currency to be in Canadian Dollars 39 | //! params.currency = Some(stripe::Currency::CAD); 40 | //! let charge = stripe::Charge::create(&client, params).unwrap(); 41 | //! println!("{:?}", charge); // => Charge { id: "ch_12345", amount: 1095, .. } 42 | //! ``` 43 | //! 44 | //! ```rust,ignore 45 | //! /* Listing Stripe Charges */ 46 | //! 47 | //! let params = stripe::ChargeListParams::default(); 48 | //! let charges = stripe::Charge::list(&client, params).unwrap(); 49 | //! println!("{:?}", charges); // => List { data: [Charge { id: "ch_12345", .. }] } 50 | //! ``` 51 | 52 | extern crate chrono; 53 | extern crate hmac; 54 | extern crate hyper; 55 | #[cfg(feature = "with-rustls")] 56 | extern crate hyper_rustls; 57 | #[cfg(feature = "with-openssl")] 58 | extern crate hyper_openssl; 59 | extern crate serde; 60 | #[macro_use] 61 | extern crate serde_derive; 62 | extern crate serde_json; 63 | extern crate serde_qs; 64 | extern crate sha2; 65 | 66 | mod client; 67 | mod error; 68 | mod ids; 69 | mod resources; 70 | mod params; 71 | 72 | pub use client::{Client, Params}; 73 | pub use error::{Error, ErrorCode, ErrorType, RequestError}; 74 | pub use ids::{SourceId, TokenId}; 75 | pub use params::{List, RangeQuery, RangeBounds, Metadata, Timestamp}; 76 | pub use resources::*; 77 | -------------------------------------------------------------------------------- /src/params.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | #[derive(Debug, Deserialize, Serialize)] 4 | pub struct List { 5 | pub data: Vec, 6 | pub has_more: bool, 7 | pub total_count: Option, 8 | pub url: String, 9 | } 10 | 11 | pub type Metadata = HashMap; 12 | pub type Timestamp = i64; 13 | 14 | #[derive(Debug, Deserialize, Serialize)] 15 | #[serde(rename_all = "lowercase")] 16 | pub struct RangeBounds { 17 | pub gt: Option, 18 | pub gte: Option, 19 | pub lt: Option, 20 | pub lte: Option, 21 | } 22 | 23 | impl Default for RangeBounds { 24 | fn default() -> Self { 25 | RangeBounds { 26 | gt: None, 27 | gte: None, 28 | lt: None, 29 | lte: None, 30 | } 31 | } 32 | } 33 | 34 | /// A set of generic request parameters that can be used on 35 | /// list endpoints to filter their results by some timestamp. 36 | #[derive(Debug, Deserialize, Serialize)] 37 | #[serde(untagged)] 38 | pub enum RangeQuery { 39 | Exact(T), 40 | Bounds(RangeBounds), 41 | } 42 | 43 | impl RangeQuery { 44 | /// Filter results to exactly match a given value 45 | pub fn eq(value: T) -> RangeQuery { 46 | RangeQuery::Exact(value) 47 | } 48 | 49 | /// Filter results to be after a given value 50 | pub fn gt(value: T) -> RangeQuery { 51 | let mut bounds = RangeBounds::default(); 52 | bounds.gt = Some(value); 53 | RangeQuery::Bounds(bounds) 54 | } 55 | 56 | /// Filter results to be after or equal to a given value 57 | pub fn gte(value: T) -> RangeQuery { 58 | let mut bounds = RangeBounds::default(); 59 | bounds.gte = Some(value); 60 | RangeQuery::Bounds(bounds) 61 | } 62 | 63 | /// Filter results to be before to a given value 64 | pub fn lt(value: T) -> RangeQuery { 65 | let mut bounds = RangeBounds::default(); 66 | bounds.gt = Some(value); 67 | RangeQuery::Bounds(bounds) 68 | } 69 | 70 | /// Filter results to be before or equal to a given value 71 | pub fn lte(value: T) -> RangeQuery { 72 | let mut bounds = RangeBounds::default(); 73 | bounds.gte = Some(value); 74 | RangeQuery::Bounds(bounds) 75 | } 76 | } 77 | 78 | // NOTE: Only intended to handle conversion from ASCII CamelCase to SnakeCase 79 | // This function is used to convert static Rust identifiers to snakecase 80 | // TODO: pub(crate) fn 81 | pub fn to_snakecase(camel: &str) -> String { 82 | let mut i = 0; 83 | let mut snake = String::new(); 84 | let mut chars = camel.chars().peekable(); 85 | while let Some(ch) = chars.next() { 86 | if ch.is_uppercase() { 87 | if i > 0 && !chars.peek().unwrap_or(&'A').is_uppercase() { 88 | snake.push('_'); 89 | } 90 | snake.push(ch.to_lowercase().next().unwrap_or(ch)); 91 | } else { 92 | snake.push(ch); 93 | } 94 | i += 1; 95 | } 96 | 97 | snake 98 | } 99 | 100 | #[cfg(test)] 101 | mod tests { 102 | #[test] 103 | fn to_snakecase() { 104 | use super::to_snakecase; 105 | 106 | assert_eq!(to_snakecase("snake_case").as_str(), "snake_case"); 107 | assert_eq!(to_snakecase("CamelCase").as_str(), "camel_case"); 108 | assert_eq!(to_snakecase("XMLHttpRequest").as_str(), "xml_http_request"); 109 | assert_eq!(to_snakecase("UPPER").as_str(), "upper"); 110 | assert_eq!(to_snakecase("lower").as_str(), "lower"); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/resources/account.rs: -------------------------------------------------------------------------------- 1 | use params::{List, Metadata, Timestamp}; 2 | use resources::BankAccount; 3 | use serde_json as json; 4 | 5 | #[derive(Debug, Default, Deserialize, Serialize)] 6 | pub struct DeclineChargeDetails { 7 | #[serde(skip_serializing_if = "Option::is_none")] 8 | pub avs_failure: Option, 9 | #[serde(skip_serializing_if = "Option::is_none")] 10 | pub cvc_failure: Option, 11 | } 12 | 13 | #[derive(Debug, Default, Deserialize, Serialize)] 14 | pub struct PayoutScheduleDetails { 15 | pub delay_days: u64, 16 | pub interval: String, 17 | #[serde(skip_serializing_if = "Option::is_none")] 18 | pub monthly_anchor: Option, 19 | #[serde(skip_serializing_if = "Option::is_none")] 20 | pub weekly_anchor: Option, 21 | } 22 | 23 | #[derive(Debug, Default, Deserialize, Serialize)] 24 | pub struct TOSAcceptanceDetails { 25 | #[serde(skip_serializing_if = "Option::is_none")] 26 | pub date: Option, 27 | #[serde(skip_serializing_if = "Option::is_none")] 28 | pub ip: Option, 29 | #[serde(skip_serializing_if = "Option::is_none")] 30 | pub user_agent: Option, 31 | } 32 | 33 | /// The set of parameters that can be used when creating an account for users. 34 | /// 35 | /// For more details see https://stripe.com/docs/api#create_account. 36 | #[derive(Debug, Deserialize, Serialize)] 37 | pub struct AccountParams<'a> { 38 | #[serde(skip_serializing_if = "Option::is_none")] 39 | pub country: Option<&'a str>, // (country the account holder resides in) 40 | #[serde(skip_serializing_if = "Option::is_none")] 41 | pub email: Option<&'a str>, // (required if account type is standard) 42 | #[serde(rename = "type")] 43 | pub account_type: &'static str, 44 | } 45 | 46 | /// The resource representing a Stripe account. 47 | /// 48 | /// For more details see https://stripe.com/docs/api#account. 49 | #[derive(Debug, Deserialize, Serialize)] 50 | pub struct Account { 51 | pub id: String, 52 | pub object: String, 53 | pub business_name: String, 54 | pub business_url: Option, 55 | pub charges_enabed: bool, 56 | pub country: String, 57 | pub debit_negative_balances: Option, 58 | pub decline_charge_on: Option, 59 | pub default_currency: String, 60 | pub details_submitted: bool, 61 | pub display_name: String, 62 | pub email: String, 63 | pub external_accounts: List, 64 | pub legal_entity: Option, 65 | pub metadata: Metadata, 66 | pub payout_schedule: Option, 67 | pub payout_statement_descriptor: Option, 68 | pub payouts_enabled: bool, 69 | pub product_description: Option, 70 | pub statement_descriptor: String, 71 | pub support_email: String, 72 | pub support_phone: String, 73 | pub timezone: String, 74 | pub tos_acceptance: Option, // (who accepted Stripe's terms of service) 75 | #[serde(rename = "type")] 76 | pub account_type: Option, // (Stripe, Custom, or Express) 77 | pub verification: Option, 78 | } 79 | -------------------------------------------------------------------------------- /src/resources/address.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Deserialize, Serialize)] 2 | pub struct Address { 3 | pub line1: String, 4 | pub line2: String, 5 | pub city: String, 6 | pub state: String, 7 | pub postal_code: String, 8 | pub country: String, 9 | } 10 | -------------------------------------------------------------------------------- /src/resources/application_fee.rs: -------------------------------------------------------------------------------- 1 | use params::{List, Timestamp}; 2 | use resources::{Currency, Refund}; 3 | 4 | /// The resource representing a Stripe application fee. 5 | /// 6 | /// For more details see https://stripe.com/docs/api#application_fees. 7 | #[derive(Debug, Deserialize, Serialize)] 8 | pub struct ApplicationFee { 9 | pub id: String, 10 | pub object: String, 11 | pub account: String, 12 | pub amount: u64, 13 | pub amount_refunded: i64, 14 | pub application: String, 15 | pub balance_transaction: String, 16 | pub charge: String, 17 | pub created: Timestamp, 18 | pub currency: Currency, 19 | pub livemode: bool, 20 | pub originating_transaction: Option, 21 | pub refunded: bool, 22 | pub refunds: List, 23 | } 24 | -------------------------------------------------------------------------------- /src/resources/application_refund.rs: -------------------------------------------------------------------------------- 1 | use params::{Timestamp, Metadata}; 2 | use resources::Currency; 3 | 4 | /// The resource representing a Stripe application fee refund. 5 | /// 6 | /// For more details see https://stripe.com/docs/api#fee_refunds. 7 | #[derive(Debug, Deserialize, Serialize)] 8 | pub struct ApplicationFeeRefund { 9 | pub id: String, 10 | pub object: String, 11 | pub amount: u64, 12 | pub balance_transaction: Option, 13 | pub created: Timestamp, 14 | pub currency: Currency, 15 | pub fee: String, 16 | pub metadata: Metadata, 17 | } 18 | -------------------------------------------------------------------------------- /src/resources/balance.rs: -------------------------------------------------------------------------------- 1 | use serde_json as json; 2 | use params::{List, Timestamp}; 3 | use resources::{Currency, PaymentSource}; 4 | 5 | #[derive(Debug, Deserialize, Serialize)] 6 | pub struct FeeDetails { 7 | pub amount: u64, 8 | pub application: String, 9 | pub currency: Currency, 10 | pub description: String, 11 | #[serde(rename = "type")] 12 | pub fee_type: String, // (application_fee, stripe_fee, or tax) 13 | } 14 | 15 | /// The resource representing a Stripe account balance. 16 | /// 17 | /// For more details see https://stripe.com/docs/api#balance_object. 18 | #[derive(Debug, Deserialize, Serialize)] 19 | pub struct Balance { 20 | pub object: String, 21 | pub available: Vec, 22 | pub connect_reserved: Vec, 23 | pub livemode: bool, 24 | pub pending: Vec, 25 | } 26 | 27 | /// The resource representing a Stripe balance transaction. 28 | /// 29 | /// For more details see https://stripe.com/docs/api#balance_transaction_object. 30 | #[derive(Debug, Deserialize, Serialize)] 31 | pub struct BalanceTransaction { 32 | pub id: String, 33 | pub object: String, 34 | pub amount: u64, 35 | pub available_on: Timestamp, 36 | pub created: Timestamp, 37 | pub currency: Currency, 38 | pub description: String, 39 | pub fee: u64, 40 | pub fee_details: List, 41 | pub net: u64, 42 | pub source: PaymentSource, 43 | pub status: String, 44 | #[serde(rename = "type")] 45 | pub transaction_type: String, 46 | } 47 | -------------------------------------------------------------------------------- /src/resources/bank_account.rs: -------------------------------------------------------------------------------- 1 | use params::Metadata; 2 | use resources::Currency; 3 | 4 | /// The resource representing a Stripe bank account. 5 | /// 6 | /// For more details see https://stripe.com/docs/api#customer_bank_account_object. 7 | #[derive(Debug, Deserialize, Serialize)] 8 | pub struct BankAccount { 9 | pub id: String, 10 | pub object: String, 11 | pub account: String, 12 | pub account_holder_name: String, 13 | pub account_holder_type: String, // (individual or company) 14 | pub bank_name: String, 15 | pub country: String, 16 | pub currency: Currency, 17 | pub customer: String, 18 | pub default_for_currency: bool, 19 | pub fingerprint: String, 20 | pub last4: String, 21 | pub metadata: Metadata, 22 | pub routing_number: String, 23 | pub status: String, // (new, validated, verified, verification_failed, errored) 24 | } 25 | -------------------------------------------------------------------------------- /src/resources/card.rs: -------------------------------------------------------------------------------- 1 | use serde::ser::SerializeStruct; 2 | 3 | #[derive(Debug, Deserialize /*, Serialize */)] 4 | pub struct CardParams<'a> { 5 | pub exp_month: &'a str, // eg. "12" 6 | pub exp_year: &'a str, // eg. "17" or 2017" 7 | 8 | pub number: &'a str, // card number 9 | pub name: Option<&'a str>, // cardholder's full name 10 | pub cvc: Option<&'a str>, // card security code 11 | } 12 | 13 | impl<'a> Default for CardParams<'a> { 14 | fn default() -> Self { 15 | CardParams { 16 | exp_month: "", 17 | exp_year: "", 18 | number: "", 19 | name: None, 20 | cvc: None, 21 | } 22 | } 23 | } 24 | 25 | impl<'a> ::serde::Serialize for CardParams<'a> { 26 | fn serialize(&self, serializer: S) -> Result 27 | where S: ::serde::ser::Serializer 28 | { 29 | let mut s = serializer.serialize_struct("CardParams", 6)?; 30 | s.serialize_field("object", "card")?; 31 | s.serialize_field("exp_month", &self.exp_month)?; 32 | s.serialize_field("exp_year", &self.exp_year)?; 33 | s.serialize_field("number", &self.number)?; 34 | s.serialize_field("name", &self.name)?; 35 | s.serialize_field("cvc", &self.cvc)?; 36 | s.end() 37 | } 38 | } 39 | 40 | 41 | #[derive(Debug, Deserialize, Serialize)] 42 | pub struct Card { 43 | pub id: String, 44 | pub address_city: Option, 45 | pub address_country: Option, 46 | pub address_line1: Option, 47 | pub address_line1_check: Option, // (pass, fail, unavailable, unchecked) 48 | pub address_line2: Option, 49 | pub address_state: Option, 50 | pub address_zip: Option, 51 | pub address_zip_check: Option, // (pass, fail, unavailable, unchecked) 52 | pub brand: String, // (Visa, American Express, MasterCard, Discover, JCB, Diners Club, or Unknown) 53 | pub country: String, // eg. "US" 54 | pub customer: Option, 55 | pub cvc_check: Option, // (pass, fail, unavailable, unchecked) 56 | pub exp_month: u32, 57 | pub exp_year: u32, 58 | pub fingerprint: String, 59 | pub funding: String, // (credit, debit, prepaid, unknown) 60 | pub last4: String, 61 | } 62 | -------------------------------------------------------------------------------- /src/resources/charge.rs: -------------------------------------------------------------------------------- 1 | use client::Client; 2 | use error::{Error, ErrorCode}; 3 | use params::{List, Metadata, RangeQuery, Timestamp}; 4 | use resources::{Address, Currency, Refund, PaymentSourceParams, PaymentSource}; 5 | use serde_qs as qs; 6 | 7 | #[derive(Debug, Deserialize, Serialize)] 8 | pub struct ChargeOutcome { 9 | #[serde(rename = "type")] 10 | pub outcome_type: String, // (authorized, manual_review, issuer_declined, blocked, invalid) 11 | pub network_status: String, // (approved_by_network, declined_by_network, not_sent_to_network, reversed_after_approval) 12 | #[serde(default)] 13 | pub reason: Option, 14 | #[serde(default)] 15 | pub risk_level: Option, // (normal, elevated, highest, not_assessed, unknown) 16 | #[serde(default)] 17 | pub seller_message: Option, 18 | #[serde(default)] 19 | pub rule: Option, 20 | } 21 | 22 | #[derive(Debug, Default, Deserialize, Serialize)] 23 | pub struct FraudDetails { 24 | pub user_report: Option, 25 | #[serde(skip_serializing)] 26 | pub stripe_report: Option, 27 | } 28 | 29 | #[derive(Debug, Deserialize, Serialize)] 30 | pub struct ShippingDetails { 31 | pub name: String, 32 | pub address: Address, 33 | #[serde(skip_serializing_if = "Option::is_none")] 34 | pub carrier: Option, // eg. Fedex, UPS, USPS 35 | #[serde(skip_serializing_if = "Option::is_none")] 36 | pub phone: Option, 37 | #[serde(skip_serializing_if = "Option::is_none")] 38 | pub tracking_number: Option, 39 | } 40 | 41 | /// The set of parameters that can be used when capturing a charge. 42 | /// 43 | /// For more details see https://stripe.com/docs/api#charge_capture. 44 | #[derive(Debug, Default, Deserialize, Serialize)] 45 | pub struct CaptureParams<'a> { 46 | #[serde(skip_serializing_if = "Option::is_none")] 47 | pub amount: Option, 48 | #[serde(skip_serializing_if = "Option::is_none")] 49 | pub application_fee: Option, 50 | #[serde(skip_serializing_if = "Option::is_none")] 51 | pub receipt_email: Option<&'a str>, 52 | #[serde(skip_serializing_if = "Option::is_none")] 53 | pub statement_descriptor: Option<&'a str>, 54 | } 55 | 56 | #[derive(Debug, Deserialize, Serialize)] 57 | pub struct DestinationParams<'a> { 58 | pub account: &'a str, 59 | pub amount: u64, 60 | } 61 | 62 | 63 | /// The set of parameters that can be used when creating or updating a charge. 64 | /// 65 | /// For more details see https://stripe.com/docs/api#create_charge and https://stripe.com/docs/api#update_charge. 66 | #[derive(Debug, Default, /* Deserialize, */ Serialize)] 67 | pub struct ChargeParams<'a> { 68 | #[serde(skip_serializing_if = "Option::is_none")] 69 | pub amount: Option, 70 | #[serde(skip_serializing_if = "Option::is_none")] 71 | pub currency: Option, 72 | #[serde(skip_serializing_if = "Option::is_none")] 73 | pub application_fee: Option, 74 | #[serde(skip_serializing_if = "Option::is_none")] 75 | pub capture: Option, // NOTE: if None, Stripe assumes true 76 | #[serde(skip_serializing_if = "Option::is_none")] 77 | pub description: Option<&'a str>, 78 | #[serde(skip_serializing_if = "Option::is_none")] 79 | pub destination: Option>, 80 | #[serde(skip_serializing_if = "Option::is_none")] 81 | pub fraud_details: Option, 82 | #[serde(skip_serializing_if = "Option::is_none")] 83 | pub transfer_group: Option<&'a str>, 84 | #[serde(skip_serializing_if = "Option::is_none")] 85 | pub on_behalf_of: Option<&'a str>, 86 | #[serde(skip_serializing_if = "Option::is_none")] 87 | pub metadata: Option, 88 | #[serde(skip_serializing_if = "Option::is_none")] 89 | pub receipt_email: Option<&'a str>, 90 | #[serde(skip_serializing_if = "Option::is_none")] 91 | pub shipping: Option, 92 | #[serde(skip_serializing_if = "Option::is_none")] 93 | pub customer: Option, 94 | #[serde(skip_serializing_if = "Option::is_none")] 95 | pub source: Option>, 96 | #[serde(skip_serializing_if = "Option::is_none")] 97 | pub statement_descriptor: Option<&'a str>, 98 | } 99 | 100 | #[derive(Copy, Clone, Debug, Deserialize, Serialize, Eq, PartialEq, Hash)] 101 | #[serde(rename_all = "snake_case")] 102 | pub enum SourceType { 103 | All, 104 | AlipayAccount, 105 | BankAccount, 106 | BitcoinReceiver, 107 | Card, 108 | } 109 | 110 | #[derive(Debug, Deserialize, Serialize)] 111 | pub struct SourceFilter { 112 | pub object: SourceType, 113 | } 114 | 115 | impl SourceFilter { 116 | pub fn all() -> SourceFilter { 117 | SourceFilter { object: SourceType::All } 118 | } 119 | pub fn alipay() -> SourceFilter { 120 | SourceFilter { object: SourceType::AlipayAccount } 121 | } 122 | pub fn bank() -> SourceFilter { 123 | SourceFilter { object: SourceType::BankAccount } 124 | } 125 | pub fn bitcoin() -> SourceFilter { 126 | SourceFilter { object: SourceType::BitcoinReceiver } 127 | } 128 | pub fn card() -> SourceFilter { 129 | SourceFilter { object: SourceType::Card } 130 | } 131 | } 132 | 133 | /// The set of parameters that can be used when listing charges. 134 | /// 135 | /// For more details see https://stripe.com/docs/api#list_charges 136 | #[derive(Debug, Default, Deserialize, Serialize)] 137 | pub struct ChargeListParams<'a> { 138 | #[serde(skip_serializing_if = "Option::is_none")] 139 | pub created: Option>, 140 | #[serde(skip_serializing_if = "Option::is_none")] 141 | pub customer: Option<&'a str>, 142 | #[serde(skip_serializing_if = "Option::is_none")] 143 | pub ending_before: Option<&'a str>, 144 | #[serde(skip_serializing_if = "Option::is_none")] 145 | pub limit: Option, 146 | #[serde(skip_serializing_if = "Option::is_none")] 147 | pub source: Option, 148 | #[serde(skip_serializing_if = "Option::is_none")] 149 | pub starting_after: Option<&'a str>, 150 | #[serde(skip_serializing_if = "Option::is_none")] 151 | pub transfer_group: Option<&'a str>, 152 | } 153 | 154 | /// The resource representing a Stripe charge. 155 | /// 156 | /// For more details see https://stripe.com/docs/api#charges. 157 | #[derive(Debug, Deserialize, Serialize)] 158 | pub struct Charge { 159 | pub id: String, 160 | pub amount: u64, 161 | pub amount_refunded: u64, 162 | pub application: Option, 163 | pub application_fee: Option, 164 | pub balance_transaction: Option, 165 | pub captured: bool, 166 | pub created: Timestamp, 167 | pub currency: Currency, 168 | pub customer: Option, 169 | pub description: Option, 170 | pub destination: Option, 171 | pub dispute: Option, 172 | pub failure_code: Option, 173 | pub failure_message: Option, 174 | pub fraud_details: FraudDetails, 175 | pub invoice: Option, 176 | pub livemode: bool, 177 | pub metadata: Metadata, 178 | pub on_behalf_of: Option, 179 | pub order: Option, 180 | pub outcome: Option, 181 | pub paid: bool, 182 | pub receipt_email: Option, 183 | pub receipt_number: Option, 184 | pub refunded: bool, 185 | pub refunds: List, 186 | pub shipping: Option, 187 | pub source: PaymentSource, 188 | pub source_transfer: Option, 189 | pub statement_descriptor: Option, 190 | pub status: String, // (succeeded, pending, failed) 191 | pub transfer_group: Option, 192 | } 193 | 194 | impl Charge { 195 | /// Creates a new charge. 196 | /// 197 | /// For more details see https://stripe.com/docs/api#create_charge. 198 | pub fn create(client: &Client, params: ChargeParams) -> Result { 199 | client.post("/charges", params) 200 | } 201 | 202 | /// Retrieves the details of a charge. 203 | /// 204 | /// For more details see https://stripe.com/docs/api#retrieve_charge. 205 | pub fn retrieve(client: &Client, charge_id: &str) -> Result { 206 | client.get(&format!("/charges/{}", charge_id)) 207 | } 208 | 209 | /// Updates a charge's properties. 210 | /// 211 | /// For more details see https://stripe.com/docs/api#update_charge. 212 | pub fn update(client: &Client, charge_id: &str, params: ChargeParams) -> Result { 213 | client.post(&format!("/charges/{}", charge_id), params) 214 | } 215 | 216 | /// Capture captures a previously created charge with capture set to false. 217 | /// 218 | /// For more details see https://stripe.com/docs/api#charge_capture. 219 | pub fn capture(client: &Client, charge_id: &str, params: CaptureParams) -> Result { 220 | client.post(&format!("/charges/{}/capture", charge_id), params) 221 | } 222 | 223 | /// List all charges. 224 | /// 225 | /// For more details see https://stripe.com/docs/api#list_charges. 226 | pub fn list(client: &Client, params: ChargeListParams) -> Result, Error> { 227 | client.get(&format!("/charges?{}", qs::to_string(¶ms)?)) 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /src/resources/coupon.rs: -------------------------------------------------------------------------------- 1 | use params::{Metadata, Timestamp}; 2 | use resources::Currency; 3 | 4 | /// The resource representing a Stripe coupon. 5 | /// 6 | /// For more details see https://stripe.com/docs/api#coupon_object. 7 | #[derive(Debug, Deserialize, Serialize)] 8 | pub struct Coupon { 9 | pub id: String, 10 | pub object: String, 11 | pub amount_off: Option, 12 | pub created: Timestamp, 13 | pub currency: Option, 14 | pub duration: String, // (forever, once, repeating) 15 | pub duration_in_months: Option, 16 | pub livemode: bool, 17 | pub max_redemptions: Option, 18 | pub metadata: Metadata, 19 | pub percent_off: u64, // eg. 50 => 50% 20 | pub redeem_by: Timestamp, 21 | pub redeemed: u64, 22 | pub valid: bool, 23 | pub deleted: bool, 24 | } 25 | -------------------------------------------------------------------------------- /src/resources/currency.rs: -------------------------------------------------------------------------------- 1 | use params::to_snakecase; 2 | 3 | /// Currency is the list of supported currencies. 4 | /// 5 | /// For more details see https://support.stripe.com/questions/which-currencies-does-stripe-support. 6 | #[derive(Copy, Clone, Debug, Deserialize, Serialize, Eq, PartialEq, Hash)] 7 | pub enum Currency { 8 | #[serde(rename = "aed")] 9 | AED, // United Arab Emirates Dirham 10 | #[serde(rename = "afn")] 11 | AFN, // Afghan Afghani 12 | #[serde(rename = "all")] 13 | ALL, // Albanian Lek 14 | #[serde(rename = "amd")] 15 | AMD, // Armenian Dram 16 | #[serde(rename = "ang")] 17 | ANG, // Netherlands Antillean Gulden 18 | #[serde(rename = "aoa")] 19 | AOA, // Angolan Kwanza 20 | #[serde(rename = "ars")] 21 | ARS, // Argentine Peso 22 | #[serde(rename = "aud")] 23 | AUD, // Australian Dollar 24 | #[serde(rename = "awg")] 25 | AWG, // Aruban Florin 26 | #[serde(rename = "azn")] 27 | AZN, // Azerbaijani Manat 28 | #[serde(rename = "bam")] 29 | BAM, // Bosnia & Herzegovina Convertible Mark 30 | #[serde(rename = "bbd")] 31 | BBD, // Barbadian Dollar 32 | #[serde(rename = "bdt")] 33 | BDT, // Bangladeshi Taka 34 | #[serde(rename = "bgn")] 35 | BGN, // Bulgarian Lev 36 | #[serde(rename = "bif")] 37 | BIF, // Burundian Franc 38 | #[serde(rename = "bmd")] 39 | BMD, // Bermudian Dollar 40 | #[serde(rename = "bnd")] 41 | BND, // Brunei Dollar 42 | #[serde(rename = "bob")] 43 | BOB, // Bolivian Boliviano 44 | #[serde(rename = "brl")] 45 | BRL, // Brazilian Real 46 | #[serde(rename = "bsd")] 47 | BSD, // Bahamian Dollar 48 | #[serde(rename = "bwp")] 49 | BWP, // Botswana Pula 50 | #[serde(rename = "bzd")] 51 | BZD, // Belize Dollar 52 | #[serde(rename = "cad")] 53 | CAD, // Canadian Dollar 54 | #[serde(rename = "cdf")] 55 | CDF, // Congolese Franc 56 | #[serde(rename = "chf")] 57 | CHF, // Swiss Franc 58 | #[serde(rename = "clp")] 59 | CLP, // Chilean Peso 60 | #[serde(rename = "cny")] 61 | CNY, // Chinese Renminbi Yuan 62 | #[serde(rename = "cop")] 63 | COP, // Colombian Peso 64 | #[serde(rename = "crc")] 65 | CRC, // Costa Rican Colón 66 | #[serde(rename = "cve")] 67 | CVE, // Cape Verdean Escudo 68 | #[serde(rename = "czk")] 69 | CZK, // Czech Koruna 70 | #[serde(rename = "djf")] 71 | DJF, // Djiboutian Franc 72 | #[serde(rename = "dkk")] 73 | DKK, // Danish Krone 74 | #[serde(rename = "dop")] 75 | DOP, // Dominican Peso 76 | #[serde(rename = "dzd")] 77 | DZD, // Algerian Dinar 78 | #[serde(rename = "eek")] 79 | EEK, // Estonian Kroon 80 | #[serde(rename = "egp")] 81 | EGP, // Egyptian Pound 82 | #[serde(rename = "etb")] 83 | ETB, // Ethiopian Birr 84 | #[serde(rename = "eur")] 85 | EUR, // Euro 86 | #[serde(rename = "fjd")] 87 | FJD, // Fijian Dollar 88 | #[serde(rename = "fkp")] 89 | FKP, // Falkland Islands Pound 90 | #[serde(rename = "gbp")] 91 | GBP, // British Pound 92 | #[serde(rename = "gel")] 93 | GEL, // Georgian Lari 94 | #[serde(rename = "gip")] 95 | GIP, // Gibraltar Pound 96 | #[serde(rename = "gmd")] 97 | GMD, // Gambian Dalasi 98 | #[serde(rename = "gnf")] 99 | GNF, // Guinean Franc 100 | #[serde(rename = "gtq")] 101 | GTQ, // Guatemalan Quetzal 102 | #[serde(rename = "gyd")] 103 | GYD, // Guyanese Dollar 104 | #[serde(rename = "hkd")] 105 | HKD, // Hong Kong Dollar 106 | #[serde(rename = "hnl")] 107 | HNL, // Honduran Lempira 108 | #[serde(rename = "hrk")] 109 | HRK, // Croatian Kuna 110 | #[serde(rename = "htg")] 111 | HTG, // Haitian Gourde 112 | #[serde(rename = "huf")] 113 | HUF, // Hungarian Forint 114 | #[serde(rename = "idr")] 115 | IDR, // Indonesian Rupiah 116 | #[serde(rename = "ils")] 117 | ILS, // Israeli New Sheqel 118 | #[serde(rename = "inr")] 119 | INR, // Indian Rupee 120 | #[serde(rename = "isk")] 121 | ISK, // Icelandic Króna 122 | #[serde(rename = "jmd")] 123 | JMD, // Jamaican Dollar 124 | #[serde(rename = "jpy")] 125 | JPY, // Japanese Yen 126 | #[serde(rename = "kes")] 127 | KES, // Kenyan Shilling 128 | #[serde(rename = "kgs")] 129 | KGS, // Kyrgyzstani Som 130 | #[serde(rename = "khr")] 131 | KHR, // Cambodian Riel 132 | #[serde(rename = "kmf")] 133 | KMF, // Comorian Franc 134 | #[serde(rename = "krw")] 135 | KRW, // South Korean Won 136 | #[serde(rename = "kyd")] 137 | KYD, // Cayman Islands Dollar 138 | #[serde(rename = "kzt")] 139 | KZT, // Kazakhstani Tenge 140 | #[serde(rename = "lak")] 141 | LAK, // Lao Kip 142 | #[serde(rename = "lbp")] 143 | LBP, // Lebanese Pound 144 | #[serde(rename = "lkr")] 145 | LKR, // Sri Lankan Rupee 146 | #[serde(rename = "lrd")] 147 | LRD, // Liberian Dollar 148 | #[serde(rename = "lsl")] 149 | LSL, // Lesotho Loti 150 | #[serde(rename = "ltl")] 151 | LTL, // Lithuanian Litas 152 | #[serde(rename = "lvl")] 153 | LVL, // Latvian Lats 154 | #[serde(rename = "mad")] 155 | MAD, // Moroccan Dirham 156 | #[serde(rename = "mdl")] 157 | MDL, // Moldovan Leu 158 | #[serde(rename = "mga")] 159 | MGA, // Malagasy Ariary 160 | #[serde(rename = "mkd")] 161 | MKD, // Macedonian Denar 162 | #[serde(rename = "mnt")] 163 | MNT, // Mongolian Tögrög 164 | #[serde(rename = "mop")] 165 | MOP, // Macanese Pataca 166 | #[serde(rename = "mro")] 167 | MRO, // Mauritanian Ouguiya 168 | #[serde(rename = "mur")] 169 | MUR, // Mauritian Rupee 170 | #[serde(rename = "mvr")] 171 | MVR, // Maldivian Rufiyaa 172 | #[serde(rename = "mwk")] 173 | MWK, // Malawian Kwacha 174 | #[serde(rename = "mxn")] 175 | MXN, // Mexican Peso 176 | #[serde(rename = "myr")] 177 | MYR, // Malaysian Ringgit 178 | #[serde(rename = "mzn")] 179 | MZN, // Mozambican Metical 180 | #[serde(rename = "nad")] 181 | NAD, // Namibian Dollar 182 | #[serde(rename = "ngn")] 183 | NGN, // Nigerian Naira 184 | #[serde(rename = "nio")] 185 | NIO, // Nicaraguan Córdoba 186 | #[serde(rename = "nok")] 187 | NOK, // Norwegian Krone 188 | #[serde(rename = "npr")] 189 | NPR, // Nepalese Rupee 190 | #[serde(rename = "nzd")] 191 | NZD, // New Zealand Dollar 192 | #[serde(rename = "pab")] 193 | PAB, // Panamanian Balboa 194 | #[serde(rename = "pen")] 195 | PEN, // Peruvian Nuevo Sol 196 | #[serde(rename = "pgk")] 197 | PGK, // Papua New Guinean Kina 198 | #[serde(rename = "php")] 199 | PHP, // Philippine Peso 200 | #[serde(rename = "pkr")] 201 | PKR, // Pakistani Rupee 202 | #[serde(rename = "pln")] 203 | PLN, // Polish Złoty 204 | #[serde(rename = "pyg")] 205 | PYG, // Paraguayan Guaraní 206 | #[serde(rename = "qar")] 207 | QAR, // Qatari Riyal 208 | #[serde(rename = "ron")] 209 | RON, // Romanian Leu 210 | #[serde(rename = "rsd")] 211 | RSD, // Serbian Dinar 212 | #[serde(rename = "rub")] 213 | RUB, // Russian Ruble 214 | #[serde(rename = "rwf")] 215 | RWF, // Rwandan Franc 216 | #[serde(rename = "sar")] 217 | SAR, // Saudi Riyal 218 | #[serde(rename = "sbd")] 219 | SBD, // Solomon Islands Dollar 220 | #[serde(rename = "scr")] 221 | SCR, // Seychellois Rupee 222 | #[serde(rename = "sek")] 223 | SEK, // Swedish Krona 224 | #[serde(rename = "sgd")] 225 | SGD, // Singapore Dollar 226 | #[serde(rename = "shp")] 227 | SHP, // Saint Helenian Pound 228 | #[serde(rename = "sll")] 229 | SLL, // Sierra Leonean Leone 230 | #[serde(rename = "sos")] 231 | SOS, // Somali Shilling 232 | #[serde(rename = "srd")] 233 | SRD, // Surinamese Dollar 234 | #[serde(rename = "std")] 235 | STD, // São Tomé and Príncipe Dobra 236 | #[serde(rename = "svc")] 237 | SVC, // Salvadoran Colón 238 | #[serde(rename = "szl")] 239 | SZL, // Swazi Lilangeni 240 | #[serde(rename = "thb")] 241 | THB, // Thai Baht 242 | #[serde(rename = "tjs")] 243 | TJS, // Tajikistani Somoni 244 | #[serde(rename = "top")] 245 | TOP, // Tongan Paʻanga 246 | #[serde(rename = "try")] 247 | TRY, // Turkish Lira 248 | #[serde(rename = "ttd")] 249 | TTD, // Trinidad and Tobago Dollar 250 | #[serde(rename = "twd")] 251 | TWD, // New Taiwan Dollar 252 | #[serde(rename = "tzs")] 253 | TZS, // Tanzanian Shilling 254 | #[serde(rename = "uah")] 255 | UAH, // Ukrainian Hryvnia 256 | #[serde(rename = "ugx")] 257 | UGX, // Ugandan Shilling 258 | #[serde(rename = "usd")] 259 | USD, // United States Dollar 260 | #[serde(rename = "uyu")] 261 | UYU, // Uruguayan Peso 262 | #[serde(rename = "uzs")] 263 | UZS, // Uzbekistani Som 264 | #[serde(rename = "vef")] 265 | VEF, // Venezuelan Bolívar 266 | #[serde(rename = "vnd")] 267 | VND, // Vietnamese Đồng 268 | #[serde(rename = "vuv")] 269 | VUV, // Vanuatu Vatu 270 | #[serde(rename = "wst")] 271 | WST, // Samoan Tala 272 | #[serde(rename = "xaf")] 273 | XAF, // Central African Cfa Franc 274 | #[serde(rename = "xcd")] 275 | XCD, // East Caribbean Dollar 276 | #[serde(rename = "xof")] 277 | XOF, // West African Cfa Franc 278 | #[serde(rename = "xpf")] 279 | XPF, // Cfp Franc 280 | #[serde(rename = "yer")] 281 | YER, // Yemeni Rial 282 | #[serde(rename = "zar")] 283 | ZAR, // South African Rand 284 | #[serde(rename = "zmw")] 285 | ZMW, // Zambian Kwacha 286 | } 287 | 288 | impl Default for Currency { 289 | fn default() -> Self { 290 | Currency::USD 291 | } 292 | } 293 | 294 | impl ::std::fmt::Display for Currency { 295 | fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { 296 | write!(f, "{}", to_snakecase(&format!("{:?}", self))) 297 | } 298 | } 299 | 300 | impl ::std::str::FromStr for Currency { 301 | type Err = ParseCurrencyError; 302 | fn from_str(s: &str) -> Result { 303 | match s { 304 | "aed" => Ok(Currency::AED), 305 | "afn" => Ok(Currency::AFN), 306 | "all" => Ok(Currency::ALL), 307 | "amd" => Ok(Currency::AMD), 308 | "ang" => Ok(Currency::ANG), 309 | "aoa" => Ok(Currency::AOA), 310 | "ars" => Ok(Currency::ARS), 311 | "aud" => Ok(Currency::AUD), 312 | "awg" => Ok(Currency::AWG), 313 | "azn" => Ok(Currency::AZN), 314 | "bam" => Ok(Currency::BAM), 315 | "bbd" => Ok(Currency::BBD), 316 | "bdt" => Ok(Currency::BDT), 317 | "bgn" => Ok(Currency::BGN), 318 | "bif" => Ok(Currency::BIF), 319 | "bmd" => Ok(Currency::BMD), 320 | "bnd" => Ok(Currency::BND), 321 | "bob" => Ok(Currency::BOB), 322 | "brl" => Ok(Currency::BRL), 323 | "bsd" => Ok(Currency::BSD), 324 | "bwp" => Ok(Currency::BWP), 325 | "bzd" => Ok(Currency::BZD), 326 | "cad" => Ok(Currency::CAD), 327 | "cdf" => Ok(Currency::CDF), 328 | "chf" => Ok(Currency::CHF), 329 | "clp" => Ok(Currency::CLP), 330 | "cny" => Ok(Currency::CNY), 331 | "cop" => Ok(Currency::COP), 332 | "crc" => Ok(Currency::CRC), 333 | "cve" => Ok(Currency::CVE), 334 | "czk" => Ok(Currency::CZK), 335 | "djf" => Ok(Currency::DJF), 336 | "dkk" => Ok(Currency::DKK), 337 | "dop" => Ok(Currency::DOP), 338 | "dzd" => Ok(Currency::DZD), 339 | "eek" => Ok(Currency::EEK), 340 | "egp" => Ok(Currency::EGP), 341 | "etb" => Ok(Currency::ETB), 342 | "eur" => Ok(Currency::EUR), 343 | "fjd" => Ok(Currency::FJD), 344 | "fkp" => Ok(Currency::FKP), 345 | "gbp" => Ok(Currency::GBP), 346 | "gel" => Ok(Currency::GEL), 347 | "gip" => Ok(Currency::GIP), 348 | "gmd" => Ok(Currency::GMD), 349 | "gnf" => Ok(Currency::GNF), 350 | "gtq" => Ok(Currency::GTQ), 351 | "gyd" => Ok(Currency::GYD), 352 | "hkd" => Ok(Currency::HKD), 353 | "hnl" => Ok(Currency::HNL), 354 | "hrk" => Ok(Currency::HRK), 355 | "htg" => Ok(Currency::HTG), 356 | "huf" => Ok(Currency::HUF), 357 | "idr" => Ok(Currency::IDR), 358 | "ils" => Ok(Currency::ILS), 359 | "inr" => Ok(Currency::INR), 360 | "isk" => Ok(Currency::ISK), 361 | "jmd" => Ok(Currency::JMD), 362 | "jpy" => Ok(Currency::JPY), 363 | "kes" => Ok(Currency::KES), 364 | "kgs" => Ok(Currency::KGS), 365 | "khr" => Ok(Currency::KHR), 366 | "kmf" => Ok(Currency::KMF), 367 | "krw" => Ok(Currency::KRW), 368 | "kyd" => Ok(Currency::KYD), 369 | "kzt" => Ok(Currency::KZT), 370 | "lak" => Ok(Currency::LAK), 371 | "lbp" => Ok(Currency::LBP), 372 | "lkr" => Ok(Currency::LKR), 373 | "lrd" => Ok(Currency::LRD), 374 | "lsl" => Ok(Currency::LSL), 375 | "ltl" => Ok(Currency::LTL), 376 | "lvl" => Ok(Currency::LVL), 377 | "mad" => Ok(Currency::MAD), 378 | "mdl" => Ok(Currency::MDL), 379 | "mga" => Ok(Currency::MGA), 380 | "mkd" => Ok(Currency::MKD), 381 | "mnt" => Ok(Currency::MNT), 382 | "mop" => Ok(Currency::MOP), 383 | "mro" => Ok(Currency::MRO), 384 | "mur" => Ok(Currency::MUR), 385 | "mvr" => Ok(Currency::MVR), 386 | "mwk" => Ok(Currency::MWK), 387 | "mxn" => Ok(Currency::MXN), 388 | "myr" => Ok(Currency::MYR), 389 | "mzn" => Ok(Currency::MZN), 390 | "nad" => Ok(Currency::NAD), 391 | "ngn" => Ok(Currency::NGN), 392 | "nio" => Ok(Currency::NIO), 393 | "nok" => Ok(Currency::NOK), 394 | "npr" => Ok(Currency::NPR), 395 | "nzd" => Ok(Currency::NZD), 396 | "pab" => Ok(Currency::PAB), 397 | "pen" => Ok(Currency::PEN), 398 | "pgk" => Ok(Currency::PGK), 399 | "php" => Ok(Currency::PHP), 400 | "pkr" => Ok(Currency::PKR), 401 | "pln" => Ok(Currency::PLN), 402 | "pyg" => Ok(Currency::PYG), 403 | "qar" => Ok(Currency::QAR), 404 | "ron" => Ok(Currency::RON), 405 | "rsd" => Ok(Currency::RSD), 406 | "rub" => Ok(Currency::RUB), 407 | "rwf" => Ok(Currency::RWF), 408 | "sar" => Ok(Currency::SAR), 409 | "sbd" => Ok(Currency::SBD), 410 | "scr" => Ok(Currency::SCR), 411 | "sek" => Ok(Currency::SEK), 412 | "sgd" => Ok(Currency::SGD), 413 | "shp" => Ok(Currency::SHP), 414 | "sll" => Ok(Currency::SLL), 415 | "sos" => Ok(Currency::SOS), 416 | "srd" => Ok(Currency::SRD), 417 | "std" => Ok(Currency::STD), 418 | "svc" => Ok(Currency::SVC), 419 | "szl" => Ok(Currency::SZL), 420 | "thb" => Ok(Currency::THB), 421 | "tjs" => Ok(Currency::TJS), 422 | "top" => Ok(Currency::TOP), 423 | "try" => Ok(Currency::TRY), 424 | "ttd" => Ok(Currency::TTD), 425 | "twd" => Ok(Currency::TWD), 426 | "tzs" => Ok(Currency::TZS), 427 | "uah" => Ok(Currency::UAH), 428 | "ugx" => Ok(Currency::UGX), 429 | "usd" => Ok(Currency::USD), 430 | "uyu" => Ok(Currency::UYU), 431 | "uzs" => Ok(Currency::UZS), 432 | "vef" => Ok(Currency::VEF), 433 | "vnd" => Ok(Currency::VND), 434 | "vuv" => Ok(Currency::VUV), 435 | "wst" => Ok(Currency::WST), 436 | "xaf" => Ok(Currency::XAF), 437 | "xcd" => Ok(Currency::XCD), 438 | "xof" => Ok(Currency::XOF), 439 | "xpf" => Ok(Currency::XPF), 440 | "yer" => Ok(Currency::YER), 441 | "zar" => Ok(Currency::ZAR), 442 | "zmw" => Ok(Currency::ZMW), 443 | _ => Err(ParseCurrencyError(())) 444 | } 445 | } 446 | } 447 | 448 | #[derive(Debug)] 449 | pub struct ParseCurrencyError(/* private */ ()); 450 | 451 | impl ::std::fmt::Display for ParseCurrencyError { 452 | fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { 453 | fmt.write_str(::std::error::Error::description(self)) 454 | } 455 | } 456 | 457 | impl ::std::error::Error for ParseCurrencyError { 458 | fn description(&self) -> &str { 459 | "unknown currency code" 460 | } 461 | } 462 | -------------------------------------------------------------------------------- /src/resources/customer.rs: -------------------------------------------------------------------------------- 1 | use client::Client; 2 | use error::Error; 3 | use ids::SourceId; 4 | use resources::{Address, Currency, Deleted, Discount, PaymentSource, PaymentSourceParams, Subscription}; 5 | use params::{List, Metadata, RangeQuery, Timestamp}; 6 | use serde_qs as qs; 7 | 8 | #[derive(Debug, Deserialize, Serialize)] 9 | pub struct CustomerShippingDetails { 10 | pub address: Address, 11 | pub name: String, 12 | pub phone: String, 13 | } 14 | 15 | /// The set of parameters that can be used when creating or updating a customer. 16 | /// 17 | /// For more details see https://stripe.com/docs/api#create_customer and https://stripe.com/docs/api#update_customer. 18 | #[derive(Debug, Default, /* Deserialize, */ Serialize)] 19 | pub struct CustomerParams<'a> { 20 | #[serde(skip_serializing_if = "Option::is_none")] 21 | pub account_balance: Option, 22 | #[serde(skip_serializing_if = "Option::is_none")] 23 | pub business_vat_id: Option<&'a str>, 24 | #[serde(skip_serializing_if = "Option::is_none")] 25 | pub default_source: Option, 26 | #[serde(skip_serializing_if = "Option::is_none")] 27 | pub coupon: Option<&'a str>, 28 | #[serde(skip_serializing_if = "Option::is_none")] 29 | pub description: Option<&'a str>, 30 | #[serde(skip_serializing_if = "Option::is_none")] 31 | pub email: Option<&'a str>, 32 | #[serde(skip_serializing_if = "Option::is_none")] 33 | pub metadata: Option, 34 | #[serde(skip_serializing_if = "Option::is_none")] 35 | pub shipping: Option, 36 | #[serde(skip_serializing_if = "Option::is_none")] 37 | pub source: Option>, 38 | } 39 | 40 | /// The set of parameters that can be used when listing customers. 41 | /// 42 | /// For more details see https://stripe.com/docs/api#list_customers 43 | #[derive(Debug, Default, Deserialize, Serialize)] 44 | pub struct CustomerListParams<'a> { 45 | #[serde(skip_serializing_if = "Option::is_none")] 46 | pub created: Option>, 47 | #[serde(skip_serializing_if = "Option::is_none")] 48 | pub ending_before: Option<&'a str>, 49 | #[serde(skip_serializing_if = "Option::is_none")] 50 | pub limit: Option, 51 | #[serde(skip_serializing_if = "Option::is_none")] 52 | pub starting_after: Option<&'a str>, 53 | } 54 | 55 | /// The resource representing a Stripe customer. 56 | /// 57 | /// For more details see https://stripe.com/docs/api#customers. 58 | #[derive(Debug, Deserialize, Serialize)] 59 | pub struct Customer { 60 | pub id: String, 61 | pub account_balance: i64, 62 | pub business_vat_id: Option, 63 | pub created: u64, 64 | pub currency: Option, 65 | pub default_source: Option, 66 | pub delinquent: bool, 67 | pub desc: Option, 68 | pub discount: Option, 69 | pub email: Option, 70 | pub livemode: bool, 71 | pub metadata: Metadata, 72 | pub shipping: Option, 73 | pub sources: List, 74 | pub subscriptions: List, 75 | } 76 | 77 | impl Customer { 78 | /// Creates a new customer. 79 | /// 80 | /// For more details see https://stripe.com/docs/api#create_customer. 81 | pub fn create(client: &Client, params: CustomerParams) -> Result { 82 | client.post("/customers", params) 83 | } 84 | 85 | /// Retrieves the details of a customer. 86 | /// 87 | /// For more details see https://stripe.com/docs/api#retrieve_customer. 88 | pub fn retrieve(client: &Client, customer_id: &str) -> Result { 89 | client.get(&format!("/customers/{}", customer_id)) 90 | } 91 | 92 | /// Updates a customer's properties. 93 | /// 94 | /// For more details see https://stripe.com/docs/api#update_customer. 95 | pub fn update(client: &Client, customer_id: &str, params: CustomerParams) -> Result { 96 | client.post(&format!("/customers/{}", customer_id), params) 97 | } 98 | 99 | /// Deletes a customer. 100 | /// 101 | /// For more details see https://stripe.com/docs/api#delete_customer. 102 | pub fn delete(client: &Client, customer_id: &str) -> Result { 103 | client.delete(&format!("/customers/{}", customer_id)) 104 | } 105 | 106 | /// List customers. 107 | /// 108 | /// For more details see https://stripe.com/docs/api#list_customers. 109 | pub fn list(client: &Client, params: CustomerListParams) -> Result, Error> { 110 | client.get(&format!("/customers?{}", qs::to_string(¶ms)?)) 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/resources/deleted.rs: -------------------------------------------------------------------------------- 1 | #[derive(Deserialize)] 2 | pub struct Deleted { 3 | pub deleted: bool, 4 | pub id: String, 5 | } 6 | -------------------------------------------------------------------------------- /src/resources/discount.rs: -------------------------------------------------------------------------------- 1 | use params::Timestamp; 2 | use resources::Coupon; 3 | 4 | /// The resource representing a Stripe discount. 5 | /// 6 | /// For more details see https://stripe.com/docs/api#discounts. 7 | #[derive(Debug, Deserialize, Serialize)] 8 | pub struct Discount { 9 | pub coupon: Coupon, 10 | pub customer: String, 11 | pub subscription: Option, 12 | 13 | pub start: Timestamp, 14 | pub end: Option, 15 | } 16 | -------------------------------------------------------------------------------- /src/resources/dispute.rs: -------------------------------------------------------------------------------- 1 | use params::{Metadata, Timestamp}; 2 | use resources::{Currency, BalanceTransaction}; 3 | 4 | #[derive(Debug, Default, Deserialize, Serialize)] 5 | pub struct EvidenceDetails { 6 | #[serde(skip_serializing_if = "Option::is_none")] 7 | pub due_by: Option, 8 | pub has_evidence: bool, 9 | pub past_due: bool, 10 | pub submission_count: u64, 11 | } 12 | 13 | /// The resource representing the evidence used to support a dispute. 14 | /// 15 | /// For more details see https://stripe.com/docs/api#dispute_evidence_object. 16 | #[derive(Debug, Default, Deserialize, Serialize)] 17 | pub struct DisputeEvidenceObject { 18 | #[serde(skip_serializing_if = "Option::is_none")] 19 | pub access_activity_log: Option, 20 | #[serde(skip_serializing_if = "Option::is_none")] 21 | pub billing_address: Option, 22 | #[serde(skip_serializing_if = "Option::is_none")] 23 | pub cancellation_policy: Option, 24 | #[serde(skip_serializing_if = "Option::is_none")] 25 | pub cancellation_policy_disclosure: Option, 26 | #[serde(skip_serializing_if = "Option::is_none")] 27 | pub cancellation_rebuttal: Option, 28 | #[serde(skip_serializing_if = "Option::is_none")] 29 | pub customer_communication: Option, 30 | #[serde(skip_serializing_if = "Option::is_none")] 31 | pub customer_email_address: Option, 32 | #[serde(skip_serializing_if = "Option::is_none")] 33 | pub customer_name: Option, 34 | #[serde(skip_serializing_if = "Option::is_none")] 35 | pub customer_purchase_ip: Option, 36 | #[serde(skip_serializing_if = "Option::is_none")] 37 | pub customer_signature: Option, 38 | #[serde(skip_serializing_if = "Option::is_none")] 39 | pub duplicate_charge_documentation: Option, 40 | #[serde(skip_serializing_if = "Option::is_none")] 41 | pub duplicate_charge_explanation: Option, 42 | #[serde(skip_serializing_if = "Option::is_none")] 43 | pub duplicate_charge_id: Option, 44 | #[serde(skip_serializing_if = "Option::is_none")] 45 | pub product_description: Option, 46 | #[serde(skip_serializing_if = "Option::is_none")] 47 | pub receipt: Option, 48 | #[serde(skip_serializing_if = "Option::is_none")] 49 | pub refund_policy: Option, 50 | #[serde(skip_serializing_if = "Option::is_none")] 51 | pub refund_policy_disclosure: Option, 52 | #[serde(skip_serializing_if = "Option::is_none")] 53 | pub refund_refusal_explanation: Option, 54 | #[serde(skip_serializing_if = "Option::is_none")] 55 | pub service_date: Option, 56 | #[serde(skip_serializing_if = "Option::is_none")] 57 | pub service_documentation: Option, 58 | #[serde(skip_serializing_if = "Option::is_none")] 59 | pub shipping_address: Option, 60 | #[serde(skip_serializing_if = "Option::is_none")] 61 | pub shipping_carrier: Option, 62 | #[serde(skip_serializing_if = "Option::is_none")] 63 | pub shipping_date: Option, 64 | #[serde(skip_serializing_if = "Option::is_none")] 65 | pub shipping_documentation: Option, 66 | #[serde(skip_serializing_if = "Option::is_none")] 67 | pub shipping_tracking_number: Option, 68 | #[serde(skip_serializing_if = "Option::is_none")] 69 | pub uncategorized_file: Option, 70 | #[serde(skip_serializing_if = "Option::is_none")] 71 | pub uncategorized_text: Option, 72 | } 73 | 74 | /// The resource representing a Stripe dispute. 75 | /// 76 | /// For more details see https://stripe.com/docs/api#disputes. 77 | #[derive(Debug, Deserialize, Serialize)] 78 | pub struct Dispute { 79 | pub id: String, 80 | pub object: String, 81 | pub amount: u64, 82 | pub balance_transactions: Vec, 83 | pub charge: String, 84 | pub created: Timestamp, 85 | pub currency: Currency, 86 | pub evidence: DisputeEvidenceObject, 87 | pub evidence_details: EvidenceDetails, 88 | pub is_charge_refundable: bool, 89 | pub livemode: bool, 90 | pub metadata: Metadata, 91 | pub reason: Option, 92 | pub status: Option, 93 | } 94 | -------------------------------------------------------------------------------- /src/resources/event.rs: -------------------------------------------------------------------------------- 1 | use chrono::{Utc}; 2 | use error::{WebhookError}; 3 | use resources::*; 4 | use hmac::{Hmac, Mac, MacResult}; 5 | use serde_json as json; 6 | use sha2::Sha256; 7 | use std::str; 8 | 9 | #[derive(Copy, Clone, Debug, Deserialize, Serialize, Eq, PartialEq, Hash)] 10 | pub enum EventType { 11 | #[serde(rename = "account.updated")] 12 | AccountUpdated, 13 | #[serde(rename = "account.application.deauthorized")] 14 | AccountApplicationDeauthorized, 15 | #[serde(rename = "account.external_account.created")] 16 | AccountExternalAccountCreated, 17 | #[serde(rename = "account.external_account.deleted")] 18 | AccountExternalAccountDeleted, 19 | #[serde(rename = "account.external_account.updated")] 20 | AccountExternalAccountUpdated, 21 | #[serde(rename = "application_fee.created")] 22 | ApplicationFeeCreated, 23 | #[serde(rename = "application_fee.refunded")] 24 | ApplicationFeeRefunded, 25 | #[serde(rename = "application_fee.refund.updated")] 26 | ApplicationFeeRefundUpdated, 27 | #[serde(rename = "balance.available")] 28 | BalanceAvailable, 29 | #[serde(rename = "charge.captured")] 30 | ChargeCaptured, 31 | #[serde(rename = "charge.failed")] 32 | ChargeFailed, 33 | #[serde(rename = "charge.pending")] 34 | ChargePending, 35 | #[serde(rename = "charge.refunded")] 36 | ChargeRefunded, 37 | #[serde(rename = "charge.succeeded")] 38 | ChargeSucceeded, 39 | #[serde(rename = "charge.updated")] 40 | ChargeUpdated, 41 | #[serde(rename = "charge.dispute.closed")] 42 | ChargeDisputeClosed, 43 | #[serde(rename = "charge.dispute.created")] 44 | ChargeDisputeCreated, 45 | #[serde(rename = "charge.dispute.funds_reinstated")] 46 | ChargeDisputeFundsReinstated, 47 | #[serde(rename = "charge.dispute.funds_withdrawn")] 48 | ChargeDisputeFundsWithdrawn, 49 | #[serde(rename = "charge.dispute.updated")] 50 | ChargeDisputeUpdated, 51 | #[serde(rename = "charge.refund.updated")] 52 | ChargeRefundUpdated, 53 | #[serde(rename = "coupon.created")] 54 | CouponCreated, 55 | #[serde(rename = "coupon.deleted")] 56 | CouponDeleted, 57 | #[serde(rename = "coupon.updated")] 58 | CouponUpdated, 59 | #[serde(rename = "customer.created")] 60 | CustomerCreated, 61 | #[serde(rename = "customer.deleted")] 62 | CustomerDeleted, 63 | #[serde(rename = "customer.updated")] 64 | CustomerUpdated, 65 | #[serde(rename = "customer.discount.created")] 66 | CustomerDiscountCreated, 67 | #[serde(rename = "customer.discount.deleted")] 68 | CustomerDiscountDeleted, 69 | #[serde(rename = "customer.discount.updated")] 70 | CustomerDiscountUpdated, 71 | #[serde(rename = "customer.source.created")] 72 | CustomerSourceCreated, 73 | #[serde(rename = "customer.source.deleted")] 74 | CustomerSourceDeleted, 75 | #[serde(rename = "customer.source.updated")] 76 | CustomerSourceUpdated, 77 | #[serde(rename = "customer.subscription.created")] 78 | CustomerSubscriptionCreated, 79 | #[serde(rename = "customer.subscription.deleted")] 80 | CustomerSubscriptionDeleted, 81 | #[serde(rename = "customer.subscription.trial_will_end")] 82 | CustomerSubscriptionTrialWillEnd, 83 | #[serde(rename = "customer.subscription.updated")] 84 | CustomerSubscriptionUpdated, 85 | #[serde(rename = "file.created")] 86 | FileCreated, 87 | #[serde(rename = "invoice.created")] 88 | InvoiceCreated, 89 | #[serde(rename = "invoice.payment_failed")] 90 | InvoicePaymentFailed, 91 | #[serde(rename = "invoice.payment_succeeded")] 92 | InvoicePaymentSucceeded, 93 | #[serde(rename = "invoice.updated")] 94 | InvoiceUpdated, 95 | #[serde(rename = "invoice.upcoming")] 96 | InvoiceUpcoming, 97 | #[serde(rename = "invoiceitem.created")] 98 | InvoiceItemCreated, 99 | #[serde(rename = "invoiceitem.deleted")] 100 | InvoiceItemDeleted, 101 | #[serde(rename = "invoiceitem.updated")] 102 | InvoiceItemUpdated, 103 | #[serde(rename = "order.created")] 104 | OrderCreated, 105 | #[serde(rename = "order.payment_failed")] 106 | OrderPaymentFailed, 107 | #[serde(rename = "order.payment_succeeded")] 108 | OrderPaymentSucceeded, 109 | #[serde(rename = "order.updated")] 110 | OrderUpdated, 111 | #[serde(rename = "order_return.updated")] 112 | OrderReturnUpdated, 113 | #[serde(rename = "payout.canceled")] 114 | PayoutCanceled, 115 | #[serde(rename = "payout.created")] 116 | PayoutCreated, 117 | #[serde(rename = "payout.failed")] 118 | PayoutFailed, 119 | #[serde(rename = "payout.paid")] 120 | PayoutPaid, 121 | #[serde(rename = "payout.updated")] 122 | PayoutUpdated, 123 | #[serde(rename = "plan.created")] 124 | PlanCreated, 125 | #[serde(rename = "plan.deleted")] 126 | PlanDeleted, 127 | #[serde(rename = "plan.updated")] 128 | PlanUpdated, 129 | #[serde(rename = "product.created")] 130 | ProductCreated, 131 | #[serde(rename = "product.deleted")] 132 | ProductDeleted, 133 | #[serde(rename = "product.updated")] 134 | ProductUpdated, 135 | #[serde(rename = "review.closed")] 136 | ReviewClosed, 137 | #[serde(rename = "review.opened")] 138 | ReviewOpened, 139 | #[serde(rename = "sigma.scheduled_query_run.created")] 140 | SigmaScheduledQueryRunCreated, 141 | #[serde(rename = "sku.created")] 142 | SkuCreated, 143 | #[serde(rename = "sku.deleted")] 144 | SkuDeleted, 145 | #[serde(rename = "sku.updated")] 146 | SkuUpdated, 147 | #[serde(rename = "source.canceled")] 148 | SourceCanceled, 149 | #[serde(rename = "source.chargeable")] 150 | Sourcechargeable, 151 | #[serde(rename = "source.failed")] 152 | SourceFailed, 153 | #[serde(rename = "source.transaction.created")] 154 | SourceTransactionCreated, 155 | #[serde(rename = "transfer.created")] 156 | TransferCreated, 157 | #[serde(rename = "transfer.reversed")] 158 | TransferReversed, 159 | #[serde(rename = "transfer.updated")] 160 | TransferUpdated, 161 | } 162 | 163 | #[derive(Debug, Deserialize, Serialize)] 164 | pub struct Event { 165 | #[serde(rename = "type")] 166 | pub event_type: EventType, 167 | pub data: EventData, 168 | // ... 169 | } 170 | 171 | #[derive(Debug, Deserialize, Serialize)] 172 | pub struct EventData { 173 | pub object: EventObject, 174 | // previous_attributes: ... 175 | } 176 | 177 | #[derive(Debug, Deserialize, Serialize)] 178 | #[serde(tag = "object", rename_all = "snake_case")] 179 | pub enum EventObject { 180 | Account(Account), 181 | ApplicationFee(ApplicationFee), 182 | #[serde(rename = "fee_refund")] 183 | ApplicationFeeRefund(ApplicationFeeRefund), 184 | Balance(Balance), 185 | BankAccount(BankAccount), 186 | Charge(Charge), 187 | Dispute(Dispute), 188 | File(File), 189 | Invoice(Invoice), 190 | InvoiceItem(InvoiceItem), 191 | Order(Order), 192 | OrderReturn(OrderReturn), 193 | Payout(Payout), 194 | Plan(Plan), 195 | Product(Product), 196 | Refund(Refund), 197 | Review(Review), 198 | Sku(Sku), 199 | Subscription(Subscription), 200 | Transaction(Transaction), 201 | Transfer(Transfer), 202 | } 203 | 204 | pub struct Webhook {} 205 | 206 | impl Webhook { 207 | pub fn construct_event(payload: String, sig: String, secret: String) -> Result { 208 | let mut headers: Vec = sig.split(",").map(|s| s.trim().to_string()).collect(); 209 | 210 | // Prepare the signed payload 211 | let ref mut timestamp: Vec = headers[0].split("=").map(|s| s.to_string()).collect(); 212 | let signed_payload = format!("{}{}{}", timestamp[1], ".", payload); 213 | 214 | // Get Stripe signature from header 215 | let ref mut signature: Vec = headers[1].split("=").map(|s| s.to_string()).collect(); 216 | 217 | // Compute HMAC with the SHA256 hash function, using endpoing secret as key and signed_payload string as the message 218 | let mut mac = Hmac::::new(secret.as_bytes()); 219 | mac.input(signed_payload.as_bytes()); 220 | 221 | let result = mac.result(); 222 | 223 | let bytes_signature = MacResult::from_slice(signature[1].as_bytes()); 224 | 225 | // Get current timestamp to compare to signature timestamp 226 | let current = Utc::now().timestamp(); 227 | let num_timestamp = timestamp[1].parse::() 228 | .map_err(|err| WebhookError::BadHeader(err))?; 229 | 230 | if bytes_signature != result { 231 | return Err(WebhookError::BadSignature); 232 | } 233 | 234 | if current - num_timestamp > 300 { 235 | return Err(WebhookError::BadTimestamp(num_timestamp)); 236 | } 237 | 238 | // return Event 239 | return json::from_str(&payload).map_err(|err| WebhookError::BadParse(err)); 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /src/resources/file.rs: -------------------------------------------------------------------------------- 1 | use params::Timestamp; 2 | 3 | /// The resource representing a Stripe file. 4 | /// 5 | /// For more details see https://stripe.com/docs/api#file_object. 6 | #[derive(Debug, Deserialize, Serialize)] 7 | pub struct File { 8 | pub id: String, 9 | pub object: String, 10 | pub created: Timestamp, 11 | pub purpose: String, 12 | pub size: u64, 13 | pub title: Option, 14 | #[serde(rename = "type")] 15 | pub file_type: String, // (csv, pdf, jpg, png) 16 | pub url: String, 17 | } 18 | -------------------------------------------------------------------------------- /src/resources/invoice_item.rs: -------------------------------------------------------------------------------- 1 | use params::{Metadata, Timestamp}; 2 | use resources::{Currency, Period, Plan}; 3 | 4 | /// The resource representing a Stripe invoice item. 5 | /// 6 | /// For more details see https://stripe.com/docs/api#invoiceitem_object. 7 | #[derive(Debug, Deserialize, Serialize)] 8 | pub struct InvoiceItem { 9 | pub id: String, 10 | pub object: String, 11 | pub amount: u64, 12 | pub currency: Currency, 13 | pub customer: String, 14 | pub date: Timestamp, 15 | pub description: String, 16 | pub discountable: String, 17 | pub invoice: String, 18 | pub livemode: bool, 19 | pub metadata: Metadata, 20 | pub period: Period, 21 | pub plan: Option, 22 | pub proration: bool, 23 | pub quantity: u64, 24 | pub subscription: Option, 25 | pub subscription_item: Option, 26 | } 27 | -------------------------------------------------------------------------------- /src/resources/invoices.rs: -------------------------------------------------------------------------------- 1 | use error::Error; 2 | use client::Client; 3 | use params::{List, Metadata, RangeQuery, Timestamp}; 4 | use resources::{Currency, Discount, Plan}; 5 | use serde_qs as qs; 6 | 7 | /// The set of parameters that can be used when creating or updating an invoice. 8 | /// 9 | /// For more details see https://stripe.com/docs/api#create_invoice, https://stripe.com/docs/api#update_invoice. 10 | #[derive(Debug, Default, Deserialize, Serialize)] 11 | pub struct InvoiceParams<'a> { 12 | #[serde(skip_serializing_if = "Option::is_none")] 13 | pub application_fee: Option, 14 | #[serde(skip_serializing_if = "Option::is_none")] 15 | pub customer: Option<&'a str>, 16 | #[serde(skip_serializing_if = "Option::is_none")] 17 | pub description: Option<&'a str>, 18 | #[serde(skip_serializing_if = "Option::is_none")] 19 | pub statement_descriptor: Option<&'a str>, 20 | #[serde(skip_serializing_if = "Option::is_none")] 21 | pub subscription: Option<&'a str>, 22 | #[serde(skip_serializing_if = "Option::is_none")] 23 | pub tax_percent: Option, 24 | 25 | #[serde(skip_serializing_if = "Option::is_none")] 26 | pub closed: Option, 27 | #[serde(skip_serializing_if = "Option::is_none")] 28 | pub forgiven: Option, 29 | } 30 | 31 | #[derive(Debug, Default, Deserialize, Serialize)] 32 | pub struct InvoiceLineItemParams<'a> { 33 | #[serde(skip_serializing_if = "Option::is_none")] 34 | pub amount: Option, 35 | #[serde(skip_serializing_if = "Option::is_none")] 36 | pub currency: Option, 37 | #[serde(skip_serializing_if = "Option::is_none")] 38 | pub customer: Option<&'a str>, 39 | #[serde(skip_serializing_if = "Option::is_none")] 40 | pub description: Option<&'a str>, 41 | #[serde(skip_serializing_if = "Option::is_none")] 42 | pub discountable: Option, 43 | #[serde(skip_serializing_if = "Option::is_none")] 44 | pub invoice: Option<&'a str>, 45 | #[serde(skip_serializing_if = "Option::is_none")] 46 | pub metadata: Option, 47 | #[serde(skip_serializing_if = "Option::is_none")] 48 | pub subscription: Option, 49 | } 50 | 51 | /* 52 | #[derive(Debug, Deserialize, Serialize)] 53 | pub struct InvoiceListLinesParams { 54 | #[serde(skip_serializing_if = "Option::is_none")] pub limit: Option, 55 | #[serde(skip_serializing_if = "Option::is_none")] pub ending_before: Option, 56 | #[serde(skip_serializing_if = "Option::is_none")] pub starting_after: Option, 57 | 58 | .. 59 | } 60 | */ 61 | 62 | #[derive(Debug, Default, Serialize)] 63 | pub struct InvoiceUpcomingParams<'a> { 64 | pub customer: &'a str, // this is a required param 65 | #[serde(skip_serializing_if = "Option::is_none")] pub coupon: Option<&'a str>, 66 | #[serde(skip_serializing_if = "Option::is_none")] pub subscription: Option<&'a str>, 67 | #[serde(skip_serializing_if = "Option::is_none")] pub subscription_items: Option>, 68 | #[serde(skip_serializing_if = "Option::is_none")] pub subscription_prorate: Option, 69 | #[serde(skip_serializing_if = "Option::is_none")] pub subscription_proration_date: Option, 70 | #[serde(skip_serializing_if = "Option::is_none")] pub subscription_tax_percent: Option, 71 | #[serde(skip_serializing_if = "Option::is_none")] pub subscription_trial_end: Option, 72 | } 73 | 74 | #[derive(Debug, Serialize)] 75 | pub struct SubscriptionItemParams<'a> { 76 | #[serde(skip_serializing_if = "Option::is_none")] 77 | pub id: Option<&'a str>, 78 | #[serde(skip_serializing_if = "Option::is_none")] 79 | pub deleted: Option, 80 | #[serde(skip_serializing_if = "Option::is_none")] 81 | pub metadata: Option, 82 | #[serde(skip_serializing_if = "Option::is_none")] 83 | pub plan: Option<&'a str>, 84 | #[serde(skip_serializing_if = "Option::is_none")] 85 | pub quantity: Option, 86 | } 87 | 88 | /// Period is a structure representing a start and end dates. 89 | #[derive(Debug, Deserialize, Serialize)] 90 | pub struct Period { 91 | pub start: Timestamp, 92 | pub end: Timestamp, 93 | } 94 | 95 | /// The resource representing a Stripe invoice line item. 96 | /// 97 | /// For more details see https://stripe.com/docs/api#invoice_line_item_object. 98 | #[derive(Debug, Deserialize, Serialize)] 99 | pub struct InvoiceLineItem { 100 | pub id: String, 101 | pub amount: i64, 102 | pub currency: Currency, 103 | pub description: Option, 104 | pub discountable: bool, 105 | pub livemode: bool, 106 | pub metadata: Metadata, 107 | pub period: Period, 108 | pub plan: Option, 109 | pub proration: bool, 110 | pub quantity: Option, 111 | pub subscription: Option, 112 | pub subscription_item: Option, 113 | #[serde(default)] 114 | // NOTE: Missing in response to InvoiceLineItem create 115 | #[serde(rename = "type")] 116 | pub item_type: String, // (invoiceitem, subscription) 117 | } 118 | 119 | /// The resource representing a Stripe invoice. 120 | /// 121 | /// For more details see https://stripe.com/docs/api#invoice_object. 122 | #[derive(Debug, Deserialize, Serialize)] 123 | pub struct Invoice { 124 | pub id: Option, // id field is not present when retrieving upcoming invoices 125 | pub amount_due: u64, 126 | pub application_fee: Option, 127 | pub attempt_count: u64, 128 | pub attempted: bool, 129 | pub charge: Option, 130 | pub closed: bool, 131 | pub currency: Currency, 132 | pub customer: String, 133 | pub date: Timestamp, 134 | pub description: Option, 135 | pub discount: Option, 136 | pub ending_balance: Option, 137 | pub forgiven: bool, 138 | pub lines: List, 139 | pub livemode: bool, 140 | pub metadata: Metadata, 141 | pub next_payment_attempt: Option, 142 | pub paid: bool, 143 | pub period_end: Timestamp, 144 | pub period_start: Timestamp, 145 | pub receipt_number: Option, 146 | pub starting_balance: i64, 147 | pub statment_descriptor: Option, 148 | pub subscription: Option, 149 | pub subscription_proration_date: Option, 150 | pub subtotal: i64, 151 | pub tax: Option, 152 | pub tax_percent: Option, 153 | pub total: i64, 154 | pub webhooks_delivered_at: Option, 155 | } 156 | 157 | #[derive(Debug, Default, Deserialize, Serialize)] 158 | pub struct InvoiceListParams<'a> { 159 | #[serde(skip_serializing_if = "Option::is_none")] 160 | pub customer: Option<&'a str>, 161 | #[serde(skip_serializing_if = "Option::is_none")] 162 | pub date: Option>, 163 | #[serde(skip_serializing_if = "Option::is_none")] 164 | pub ending_before: Option<&'a str>, 165 | #[serde(skip_serializing_if = "Option::is_none")] 166 | pub limit: Option, 167 | #[serde(skip_serializing_if = "Option::is_none")] 168 | pub starting_after: Option<&'a str>, 169 | #[serde(skip_serializing_if = "Option::is_none")] 170 | pub subscription: Option<&'a str>, 171 | } 172 | 173 | impl Invoice { 174 | /// Creates a new invoice. 175 | /// 176 | /// For more details see https://stripe.com/docs/api#create_invoice. 177 | pub fn create(client: &Client, params: InvoiceParams) -> Result { 178 | client.post("/invoices", params) 179 | } 180 | 181 | /// Retrieves the details of an invoice. 182 | /// 183 | /// For more details see https://stripe.com/docs/api#retrieve_invoice. 184 | pub fn retrieve(client: &Client, invoice_id: &str) -> Result { 185 | client.get(&format!("/invoices/{}", invoice_id)) 186 | } 187 | 188 | // TODO: Implement InvoiceListLinesParams 189 | // pub fn get_lines(client: &Client, invoice_id: &str, params: InvoiceListLinesParams) -> Result, Error> { 190 | // client.get(&format!("/invoices/{}/lines", invoice_id)) 191 | // } 192 | 193 | /// Retrieves the details of an upcoming invoice_id 194 | /// 195 | /// For more details see https://stripe.com/docs/api#upcoming_invoice 196 | pub fn upcoming(client: &Client, params: InvoiceUpcomingParams) -> Result { 197 | client.get(&format!("/invoices/upcoming?{}", qs::to_string(¶ms)?)) 198 | } 199 | 200 | /// Pays an invoice. 201 | /// 202 | /// For more details see https://stripe.com/docs/api#pay_invoice. 203 | pub fn pay(client: &Client, invoice_id: &str) -> Result { 204 | client.post_empty(&format!("/invoices/{}/pay", invoice_id)) 205 | } 206 | 207 | /// Updates an invoice. 208 | /// 209 | /// For more details see https://stripe.com/docs/api#update_invoice. 210 | pub fn update(client: &Client, invoice_id: &str, params: InvoiceParams) -> Result { 211 | client.post(&format!("/invoices/{}", invoice_id), ¶ms) 212 | } 213 | 214 | /// Lists all invoices. 215 | /// 216 | /// For more details see https://stripe.com/docs/api#list_invoices. 217 | pub fn list(client: &Client, params: InvoiceListParams) -> Result, Error> { 218 | client.get(&format!("/invoices?{}", qs::to_string(¶ms)?)) 219 | } 220 | } 221 | 222 | impl InvoiceLineItem { 223 | /// Creates an invoice line item. 224 | /// 225 | /// For more details see https://stripe.com/docs/api#invoice_line_item_object 226 | pub fn create(client: &Client, params: InvoiceLineItemParams) -> Result { 227 | client.post(&format!("/invoiceitems"), ¶ms) 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /src/resources/mod.rs: -------------------------------------------------------------------------------- 1 | mod account; 2 | mod address; 3 | mod application_fee; 4 | mod application_refund; 5 | mod balance; 6 | mod bank_account; 7 | mod card; 8 | mod charge; 9 | mod coupon; 10 | mod currency; 11 | mod customer; 12 | mod deleted; 13 | mod discount; 14 | mod dispute; 15 | mod event; 16 | mod file; 17 | mod invoices; 18 | mod invoice_item; 19 | mod order; 20 | mod order_return; 21 | mod payment_source; 22 | mod payout; 23 | mod plan; 24 | mod product; 25 | mod refund; 26 | mod review; 27 | mod scheduled_query; 28 | mod sku; 29 | mod subscription; 30 | mod transaction; 31 | mod transfer; 32 | 33 | pub use resources::account::*; 34 | pub use resources::address::*; 35 | pub use resources::application_fee::*; 36 | pub use resources::application_refund::*; 37 | pub use resources::balance::*; 38 | pub use resources::bank_account::*; 39 | pub use resources::card::*; 40 | pub use resources::charge::*; 41 | pub use resources::coupon::*; 42 | pub use resources::currency::*; 43 | pub use resources::customer::*; 44 | pub use resources::deleted::*; 45 | pub use resources::discount::*; 46 | pub use resources::dispute::*; 47 | pub use resources::event::*; 48 | pub use resources::file::*; 49 | pub use resources::invoices::*; 50 | pub use resources::invoice_item::*; 51 | pub use resources::order::*; 52 | pub use resources::order_return::*; 53 | pub use resources::payment_source::*; 54 | pub use resources::payout::*; 55 | pub use resources::plan::*; 56 | pub use resources::product::*; 57 | pub use resources::refund::*; 58 | pub use resources::review::*; 59 | pub use resources::scheduled_query::*; 60 | pub use resources::sku::*; 61 | pub use resources::subscription::*; 62 | pub use resources::transaction::*; 63 | pub use resources::transfer::*; 64 | -------------------------------------------------------------------------------- /src/resources/order.rs: -------------------------------------------------------------------------------- 1 | use params::{List, Metadata, Timestamp}; 2 | use resources::{Currency, ShippingDetails}; 3 | use serde_json as json; 4 | 5 | #[derive(Debug, Default, Deserialize, Serialize)] 6 | pub struct StatusTransitions { 7 | #[serde(skip_serializing_if = "Option::is_none")] 8 | pub canceled: Option, 9 | #[serde(skip_serializing_if = "Option::is_none")] 10 | pub fulfilled: Option, 11 | #[serde(skip_serializing_if = "Option::is_none")] 12 | pub paid: Option, 13 | #[serde(skip_serializing_if = "Option::is_none")] 14 | pub returned: Option, 15 | } 16 | 17 | /// The resource representing a Stripe order item. 18 | /// 19 | /// For more details see https://stripe.com/docs/api#order_item_object. 20 | #[derive(Debug, Deserialize, Serialize)] 21 | pub struct OrderItem { 22 | pub object: String, 23 | pub amount: u64, 24 | pub currency: Currency, 25 | pub description: String, 26 | pub parent: Option, 27 | pub quantity: Option, 28 | #[serde(rename = "type")] 29 | pub item_type: String, 30 | } 31 | 32 | /// The resource representing a Stripe order. 33 | /// 34 | /// For more details see https://stripe.com/docs/api#order_object. 35 | #[derive(Debug, Deserialize, Serialize)] 36 | pub struct Order { 37 | pub id: String, 38 | pub object: String, 39 | pub amount: u64, 40 | pub amount_returned: u64, 41 | pub application: String, 42 | pub application_fee: u64, 43 | pub charge: Option, 44 | pub created: Timestamp, 45 | pub currency: Currency, 46 | pub customer: String, 47 | pub email: String, 48 | pub external_coupon_code: String, 49 | pub items: List, 50 | pub livemode: bool, 51 | pub metadata: Metadata, 52 | pub returns: List, 53 | pub selected_shipping_method: Option, 54 | pub shipping: Option, 55 | pub shipping_methods: List, 56 | pub status: String, // (created, paid, canceled, fulfilled, returned) 57 | pub status_transitions: StatusTransitions, 58 | pub udpated: Timestamp, 59 | pub upstream_id: Option, 60 | } 61 | -------------------------------------------------------------------------------- /src/resources/order_return.rs: -------------------------------------------------------------------------------- 1 | use params::{List, Timestamp}; 2 | use resources::{Currency, OrderItem}; 3 | 4 | /// The resource representing a Stripe order return. 5 | /// 6 | /// For more details see https://stripe.com/docs/api#order_return_object. 7 | #[derive(Debug, Deserialize, Serialize)] 8 | pub struct OrderReturn { 9 | pub id: String, 10 | pub object: String, 11 | pub amount: u64, 12 | pub created: Timestamp, 13 | pub currency: Currency, 14 | pub items: List, 15 | pub livemode: bool, 16 | pub order: String, 17 | pub refund: String, 18 | } 19 | -------------------------------------------------------------------------------- /src/resources/payment_source.rs: -------------------------------------------------------------------------------- 1 | use client::Client; 2 | use error::Error; 3 | use ids::{SourceId, TokenId}; 4 | use resources::{Address, Card, CardParams, Currency}; 5 | use params::{Metadata, Timestamp}; 6 | 7 | #[derive(Debug, Deserialize, Serialize)] 8 | pub struct OwnerParams<'a> { 9 | #[serde(skip_serializing_if = "Option::is_none")] 10 | pub address: Option
, 11 | #[serde(skip_serializing_if = "Option::is_none")] 12 | pub email: Option<&'a str>, 13 | #[serde(skip_serializing_if = "Option::is_none")] 14 | pub name: Option<&'a str>, 15 | #[serde(skip_serializing_if = "Option::is_none")] 16 | pub phone: Option<&'a str>, 17 | } 18 | 19 | #[derive(Debug, Deserialize, Serialize)] 20 | pub struct CodeVerification { 21 | pub attempts_remaining: i64, 22 | pub status: String, 23 | } 24 | 25 | #[derive(Debug, Deserialize, Serialize)] 26 | pub struct VerifiedAddress { 27 | pub city: Address, 28 | pub country: String, 29 | pub line1: String, 30 | pub line2: String, 31 | pub postal_code: String, 32 | pub state: String, 33 | } 34 | 35 | #[derive(Debug, Deserialize, Serialize)] 36 | pub struct Receiver { 37 | pub address: String, 38 | pub amount_charged: i64, 39 | pub amount_receive: i64, 40 | pub amount_returned: i64, 41 | } 42 | 43 | #[derive(Debug, Deserialize, Serialize)] 44 | pub struct Redirect { 45 | pub failure_reason: String, 46 | pub return_url: String, 47 | pub status: String, 48 | pub url: String, 49 | } 50 | 51 | #[derive(Debug, Deserialize, Serialize)] 52 | pub struct Owner { 53 | pub address: Address, 54 | pub email: String, 55 | pub name: String, 56 | pub phone: String, 57 | pub verified_address: VerifiedAddress, 58 | pub verified_email: String, 59 | pub verified_name: String, 60 | pub verified_phone: String, 61 | pub receiver: Option, 62 | pub redirect: Option, 63 | } 64 | 65 | #[derive(Debug, Deserialize, Serialize)] 66 | pub struct RedirectParams<'a> { 67 | return_url: &'a str, 68 | } 69 | 70 | #[derive(Debug, Default, Deserialize, Serialize)] 71 | pub struct SourceParams<'a> { 72 | #[serde(rename = "type")] 73 | #[serde(skip_serializing_if = "Option::is_none")] 74 | pub source_type: Option<&'a str>, 75 | #[serde(skip_serializing_if = "Option::is_none")] 76 | pub amount: Option, 77 | #[serde(skip_serializing_if = "Option::is_none")] 78 | pub currency: Option, 79 | #[serde(skip_serializing_if = "Option::is_none")] 80 | pub flow: Option<&'a str>, // (redirect, receiver, code_verification, none) 81 | #[serde(skip_serializing_if = "Option::is_none")] 82 | pub metadata: Option, 83 | #[serde(skip_serializing_if = "Option::is_none")] 84 | pub owner: Option>, 85 | #[serde(skip_serializing_if = "Option::is_none")] 86 | pub statement_descriptor: Option<&'a str>, 87 | #[serde(skip_serializing_if = "Option::is_none")] 88 | pub redirect: Option>, 89 | #[serde(skip_serializing_if = "Option::is_none")] 90 | pub token: Option, 91 | #[serde(skip_serializing_if = "Option::is_none")] 92 | pub usage: Option<&'a str>, // (reusable, single-use) 93 | } 94 | 95 | /// The resource representing a Stripe source. 96 | /// 97 | /// For more details see https://stripe.com/docs/api#sources. 98 | #[derive(Debug, Deserialize, Serialize)] 99 | pub struct Source { 100 | pub id: String, 101 | pub object: String, // source 102 | pub amount: i64, 103 | pub client_secret: String, 104 | pub code_verification: Option, 105 | pub created: Timestamp, 106 | pub currency: Currency, 107 | pub flow: String, 108 | pub livemode: bool, 109 | pub metadata: Metadata, 110 | pub owner: Owner, 111 | pub statement_descriptor: String, 112 | pub status: String, 113 | #[serde(rename = "type")] 114 | pub source_type: String, // (ach_credit_transfer, card, alipay etc.) 115 | pub usage: String, // (reusable, single-use) 116 | } 117 | 118 | #[derive(Debug)] 119 | pub enum PaymentSourceParams<'a> { 120 | Source(SourceId), 121 | Token(TokenId), 122 | Card(CardParams<'a>), 123 | } 124 | 125 | impl<'de> ::serde::Deserialize<'de> for PaymentSourceParams<'de> { 126 | fn deserialize(deserializer: D) -> Result 127 | where 128 | D: ::serde::de::Deserializer<'de>, 129 | { 130 | use serde::de::{Deserialize, Error}; 131 | use serde::private::de::{Content, ContentRefDeserializer}; 132 | 133 | #[derive(Deserialize)] 134 | pub struct Any {} 135 | 136 | #[derive(Deserialize)] 137 | #[serde(tag = "object", rename_all = "snake_case")] 138 | pub enum PaymentSourceObjectType { 139 | Card(Any), 140 | } 141 | 142 | // Try deserializing the untagged variants first 143 | let content = ::deserialize(deserializer)?; 144 | let deserializer = ContentRefDeserializer::::new(&content); 145 | if let Ok(ok) = ::deserialize(deserializer) { 146 | return Ok(PaymentSourceParams::Source(ok)); 147 | } 148 | let deserializer = ContentRefDeserializer::::new(&content); 149 | if let Ok(ok) = ::deserialize(deserializer) { 150 | return Ok(PaymentSourceParams::Token(ok)); 151 | } 152 | 153 | // Deserialize just the tag of one of the tagged variants, then deserialize the matching variant 154 | let deserializer = ContentRefDeserializer::::new(&content); 155 | match ::deserialize(deserializer) { 156 | Ok(PaymentSourceObjectType::Card(_)) => { 157 | let deserializer = ContentRefDeserializer::::new(&content); 158 | return ::deserialize(deserializer).map(PaymentSourceParams::Card); 159 | } 160 | _ => {} 161 | } 162 | 163 | Err(Error::custom("data did not match any variant of enum PaymentSourceParams")) 164 | } 165 | } 166 | 167 | impl<'a> ::serde::Serialize for PaymentSourceParams<'a> { 168 | fn serialize(&self, serializer: S) -> Result 169 | where S: ::serde::ser::Serializer 170 | { 171 | #[derive(Serialize)] 172 | #[serde(tag = "object", rename_all = "snake_case")] 173 | enum PaymentSourceTagged<'a> { 174 | Card(&'a CardParams<'a>), 175 | } 176 | 177 | match self { 178 | PaymentSourceParams::Source(id) => id.serialize(serializer), 179 | PaymentSourceParams::Token(id) => id.serialize(serializer), 180 | PaymentSourceParams::Card(card) => PaymentSourceTagged::Card(card).serialize(serializer), 181 | } 182 | } 183 | } 184 | 185 | #[derive(Debug, Deserialize, Serialize)] 186 | #[serde(tag = "object", rename_all = "snake_case")] 187 | pub enum PaymentSource { 188 | // BitcoinReceiver(...), 189 | Card(Card), 190 | Source(Source), 191 | } 192 | 193 | impl PaymentSource { 194 | pub fn create(client: &Client, params: SourceParams) -> Result { 195 | client.post("/sources", params) 196 | } 197 | 198 | pub fn get(client: &Client, source_id: &str) -> Result { 199 | client.get(&format!("/sources/{}", source_id)) 200 | } 201 | 202 | pub fn update(client: &Client, source_id: &str, params: SourceParams) -> Result { 203 | client.post(&format!("/source/{}", source_id), params) 204 | } 205 | 206 | /// Attaches a source to a customer, does not change default Source for the Customer 207 | /// 208 | /// For more details see https://stripe.com/docs/api#attach_source. 209 | pub fn attach_source(client: &Client, customer_id: &str, source: &str) -> Result { 210 | client.post(&format!("/customers/{}/sources", customer_id), source) 211 | } 212 | 213 | /// Detaches a source from a customer 214 | /// 215 | /// For more details see https://stripe.com/docs/api#detach_source. 216 | pub fn detach_source(client: &Client, customer_id: &str, source_id: &str) -> Result { 217 | client.delete(&format!("/customers/{}/sources/{}", customer_id, source_id)) 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /src/resources/payout.rs: -------------------------------------------------------------------------------- 1 | use params::{Metadata, Timestamp}; 2 | use resources::Currency; 3 | 4 | /// The resource representing a Stripe payout. 5 | /// 6 | /// For more details see https://stripe.com/docs/api#payout_object. 7 | #[derive(Debug, Deserialize, Serialize)] 8 | pub struct Payout { 9 | pub id: String, 10 | pub object: String, 11 | pub amount: u64, 12 | pub arrival_date: Timestamp, 13 | pub balance_transaction: String, 14 | pub created: Timestamp, 15 | pub currency: Currency, 16 | pub description: String, 17 | pub destination: Option, 18 | pub failure_balance_transaction: Option, 19 | pub failure_code: Option, 20 | pub failure_message: Option, 21 | pub livemode: bool, 22 | pub metadata: Metadata, 23 | pub method: String, // (standard, instant) 24 | pub source_type: String, // (card, bank_account, bitcoin_receiver, alipay_account) 25 | pub statement_descriptor: Option, 26 | pub status: String, 27 | #[serde(rename = "type")] 28 | pub payout_type: String, // (bank_account, card) 29 | } 30 | -------------------------------------------------------------------------------- /src/resources/plan.rs: -------------------------------------------------------------------------------- 1 | use error::Error; 2 | use client::Client; 3 | use params::{Metadata, Timestamp}; 4 | use resources::{Currency, Deleted}; 5 | 6 | /// The set of parameters that can be used when creating or updating a plan. 7 | /// 8 | /// For more details see https://stripe.com/docs/api#create_plan and https://stripe.com/docs/api#update_plan. 9 | #[derive(Debug, Default, Deserialize, Serialize)] 10 | pub struct PlanParams<'a> { 11 | #[serde(skip_serializing_if = "Option::is_none")] 12 | pub id: Option<&'a str>, 13 | #[serde(skip_serializing_if = "Option::is_none")] 14 | pub amount: Option, 15 | #[serde(skip_serializing_if = "Option::is_none")] 16 | pub currency: Option, 17 | #[serde(skip_serializing_if = "Option::is_none")] 18 | pub interval: Option<&'a str>, // (day, week, month, year) 19 | #[serde(skip_serializing_if = "Option::is_none")] 20 | pub name: Option<&'a str>, 21 | 22 | #[serde(skip_serializing_if = "Option::is_none")] 23 | pub interval_count: Option, 24 | #[serde(skip_serializing_if = "Option::is_none")] 25 | pub metadata: Option, 26 | #[serde(skip_serializing_if = "Option::is_none")] 27 | pub statement_descriptor: Option<&'a str>, 28 | #[serde(skip_serializing_if = "Option::is_none")] 29 | pub trial_period_days: Option, 30 | } 31 | 32 | /// The resource representing a Stripe plan. 33 | /// 34 | /// For more details see https://stripe.com/docs/api#plans. 35 | #[derive(Debug, Deserialize, Serialize)] 36 | pub struct Plan { 37 | pub id: String, 38 | pub amount: u64, 39 | pub created: Timestamp, 40 | pub currency: Currency, 41 | pub interval: String, // (day, week, month, year) 42 | pub interval_count: u64, 43 | pub livemode: bool, 44 | pub metadata: Metadata, 45 | pub nickname: Option, 46 | pub statement_descriptor: Option, 47 | pub trial_period_days: Option, 48 | } 49 | 50 | impl Plan { 51 | /// Creates a new plan. 52 | /// 53 | /// For more details see https://stripe.com/docs/api#create_plan. 54 | pub fn create(client: &Client, params: PlanParams) -> Result { 55 | client.post("/plans", params) 56 | } 57 | 58 | /// Retrieves the details of a plan. 59 | /// 60 | /// For more details see https://stripe.com/docs/api#retrieve_plan. 61 | pub fn retrieve(client: &Client, plan_id: &str) -> Result { 62 | client.get(&format!("/plans/{}", plan_id)) 63 | } 64 | 65 | /// Updates a plan's properties. 66 | /// 67 | /// For more details see https://stripe.com/docs/api#update_plan. 68 | pub fn update(client: &Client, plan_id: &str, params: PlanParams) -> Result { 69 | client.post(&format!("/plans/{}", plan_id), params) 70 | } 71 | 72 | /// Deletes a plan. 73 | /// 74 | /// For more details see https://stripe.com/docs/api#delete_plan. 75 | pub fn delete(client: &Client, plan_id: &str) -> Result { 76 | client.delete(&format!("/plans/{}", plan_id)) 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/resources/product.rs: -------------------------------------------------------------------------------- 1 | use params::{List, Metadata, Timestamp}; 2 | use resources::Sku; 3 | 4 | #[derive(Debug, Default, Deserialize, Serialize)] 5 | pub struct PackageDimensions { 6 | pub height: f64, 7 | pub length: f64, 8 | pub weight: f64, 9 | pub width: f64, 10 | } 11 | 12 | /// The resource representing a Stripe product. 13 | /// 14 | /// For more details see https://stripe.com/docs/api#product_object. 15 | #[derive(Debug, Deserialize, Serialize)] 16 | pub struct Product { 17 | pub id: String, 18 | pub object: String, 19 | pub active: Option, 20 | pub attributes: Vec, 21 | pub caption: Option, 22 | pub created: Timestamp, 23 | pub deactivate_on: Vec, 24 | pub description: Option, 25 | pub images: Vec, 26 | pub livemode: bool, 27 | pub metadata: Metadata, 28 | pub name: String, 29 | pub package_dimensions: Option, 30 | pub shippable: Option, 31 | pub skus: List, 32 | pub updated: Timestamp, 33 | pub url: Option, 34 | } 35 | -------------------------------------------------------------------------------- /src/resources/refund.rs: -------------------------------------------------------------------------------- 1 | use params::{Metadata, Timestamp}; 2 | use resources::Currency; 3 | 4 | /// The resource representing a Stripe refund. 5 | /// 6 | /// For more details see https://stripe.com/docs/api#refunds. 7 | #[derive(Debug, Deserialize, Serialize)] 8 | pub struct Refund { 9 | pub id: String, 10 | pub object: String, 11 | pub amount: u64, 12 | pub balance_transaction: String, 13 | pub charge: String, 14 | pub created: Timestamp, 15 | pub currency: Currency, 16 | pub failure_balance_transaction: Option, 17 | pub failure_reason: Option, 18 | pub metadata: Metadata, 19 | pub reason: Option, // (duplicate, fraudulent, requested_by_customer) 20 | pub receipt_number: Option, 21 | pub status: String, // (succeeded, pending, failed, cancelled) 22 | } 23 | -------------------------------------------------------------------------------- /src/resources/review.rs: -------------------------------------------------------------------------------- 1 | use params::Timestamp; 2 | 3 | /// The resource representing a Stripe review of a payment. 4 | /// 5 | /// For more details see https://stripe.com/docs/api#review_object. 6 | #[derive(Debug, Deserialize, Serialize)] 7 | pub struct Review { 8 | pub id: String, 9 | pub object: String, 10 | pub charge: String, 11 | pub created: Timestamp, 12 | pub livemode: bool, 13 | pub open: bool, 14 | pub reason: String, 15 | } 16 | -------------------------------------------------------------------------------- /src/resources/scheduled_query.rs: -------------------------------------------------------------------------------- 1 | use params::Timestamp; 2 | use resources::File; 3 | use serde_json as json; 4 | 5 | /// The resource representing a Stripe scheduled query run. 6 | /// 7 | /// For more details see https://stripe.com/docs/api#scheduled_query_run_object. 8 | #[derive(Debug, Deserialize, Serialize)] 9 | pub struct ScheduledQueryRun { 10 | pub id: String, 11 | pub object: String, 12 | pub created: Timestamp, 13 | pub data_load_time: Timestamp, 14 | pub error: Option, 15 | pub file: File, 16 | pub livemode: bool, 17 | pub result_available_until: Timestamp, 18 | pub sql: String, 19 | pub status: String, // (completed, canceled, failed, timed_out) 20 | pub title: String, 21 | } 22 | -------------------------------------------------------------------------------- /src/resources/sku.rs: -------------------------------------------------------------------------------- 1 | use params::{Metadata, Timestamp}; 2 | use resources::{Currency, PackageDimensions}; 3 | use serde_json as json; 4 | 5 | #[derive(Debug, Default, Deserialize, Serialize)] 6 | pub struct Inventory { 7 | pub quantity: u64, 8 | #[serde(rename = "type")] 9 | pub inventory_type: String, 10 | pub value: Option, 11 | } 12 | 13 | /// The resource representing a Stripe Sku. 14 | /// 15 | /// For more details see https://stripe.com/docs/api#sku_object. 16 | #[derive(Debug, Deserialize, Serialize)] 17 | pub struct Sku { 18 | pub id: String, 19 | pub object: String, 20 | pub active: bool, 21 | pub attributes: json::Value, 22 | pub created: Timestamp, 23 | pub currency: Currency, 24 | pub image: Option, 25 | pub inventory: Inventory, 26 | pub livemode: bool, 27 | pub metadata: Metadata, 28 | pub package_dimensions: Option, 29 | pub price: u64, 30 | pub product: String, 31 | pub updated: Timestamp, 32 | } 33 | -------------------------------------------------------------------------------- /src/resources/subscription.rs: -------------------------------------------------------------------------------- 1 | use error::Error; 2 | use client::Client; 3 | use resources::{Discount, Plan}; 4 | use params::{List, Metadata, Timestamp}; 5 | use serde_qs as qs; 6 | 7 | #[derive(Debug, Default, Deserialize, Serialize)] 8 | pub struct CancelParams { 9 | #[serde(skip_serializing_if = "Option::is_none")] 10 | pub at_period_end: Option, 11 | } 12 | 13 | #[derive(Serialize, Debug)] 14 | pub struct ItemParams<'a> { 15 | pub plan: &'a str, 16 | #[serde(skip_serializing_if = "Option::is_none")] 17 | pub quantity: Option, 18 | } 19 | 20 | /// The set of parameters that can be used when creating or updating a subscription. 21 | /// 22 | /// For more details see https://stripe.com/docs/api#create_subscription and https://stripe.com/docs/api#update_subscription. 23 | #[derive(Default, Serialize, Debug)] 24 | pub struct SubscriptionParams<'a> { 25 | #[serde(skip_serializing_if = "Option::is_none")] 26 | pub customer: Option<&'a str>, 27 | #[serde(skip_serializing_if = "Option::is_none")] 28 | pub application_fee_percent: Option, 29 | #[serde(skip_serializing_if = "Option::is_none")] 30 | pub coupon: Option<&'a str>, 31 | #[serde(skip_serializing_if = "Option::is_none")] 32 | pub items: Option>>, 33 | #[serde(skip_serializing_if = "Option::is_none")] 34 | pub metadata: Option, 35 | #[serde(skip_serializing_if = "Option::is_none")] 36 | pub plan: Option<&'a str>, 37 | #[serde(skip_serializing_if = "Option::is_none")] 38 | pub prorate: Option, 39 | #[serde(skip_serializing_if = "Option::is_none")] 40 | pub proration_date: Option, 41 | #[serde(skip_serializing_if = "Option::is_none")] 42 | pub quantity: Option, 43 | #[serde(skip_serializing_if = "Option::is_none")] 44 | pub source: Option<&'a str>, 45 | #[serde(skip_serializing_if = "Option::is_none")] 46 | pub tax_percent: Option, 47 | #[serde(skip_serializing_if = "Option::is_none")] 48 | pub trial_end: Option>, 49 | #[serde(skip_serializing_if = "Option::is_none")] 50 | pub trial_period_days: Option, 51 | } 52 | 53 | 54 | #[derive(Serialize, Debug)] 55 | #[serde(untagged)] 56 | pub enum TrialEnd<'a> { 57 | Timestamp(Timestamp), 58 | Special(&'a str) 59 | } 60 | 61 | /// The resource representing a Stripe subscription item. 62 | /// 63 | /// For more details see https://stripe.com/docs/api#subscription_items. 64 | #[derive(Debug, Deserialize, Serialize)] 65 | pub struct SubscriptionItem { 66 | pub id: String, 67 | pub created: Timestamp, 68 | pub plan: Plan, 69 | pub quantity: u64, 70 | } 71 | 72 | /// The resource representing a Stripe subscription. 73 | /// 74 | /// For more details see https://stripe.com/docs/api#subscriptions. 75 | #[derive(Debug, Deserialize, Serialize)] 76 | pub struct Subscription { 77 | pub id: String, 78 | pub application_fee_percent: Option, 79 | pub cancel_at_period_end: bool, 80 | pub canceled_at: Option, 81 | pub created: Option, 82 | pub current_period_start: Timestamp, 83 | pub current_period_end: Timestamp, 84 | pub customer: String, 85 | pub discount: Option, 86 | pub ended_at: Option, 87 | pub items: List, 88 | pub livemode: bool, 89 | pub metadata: Metadata, 90 | pub plan: Plan, 91 | pub quantity: u64, 92 | pub start: Timestamp, 93 | pub status: String, // (trialing, active, past_due, canceled, unpaid) 94 | pub tax_percent: Option, 95 | pub trial_start: Option, 96 | pub trial_end: Option, 97 | } 98 | 99 | impl Subscription { 100 | /// Creates a new subscription for a customer. 101 | /// 102 | /// For more details see https://stripe.com/docs/api#create_subscription. 103 | pub fn create(client: &Client, params: SubscriptionParams) -> Result { 104 | client.post("/subscriptions", params) 105 | } 106 | 107 | /// Retrieves the details of a subscription. 108 | /// 109 | /// For more details see https://stripe.com/docs/api#retrieve_subscription. 110 | pub fn retrieve(client: &Client, subscription_id: &str) -> Result { 111 | client.get(&format!("/subscriptions/{}", subscription_id)) 112 | } 113 | 114 | /// Updates a subscription's properties. 115 | /// For more details see https://stripe.com/docs/api#update_subscription. 116 | pub fn update(client: &Client, subscription_id: &str, params: SubscriptionParams) -> Result { 117 | client.post(&format!("/subscriptions/{}", subscription_id), params) 118 | } 119 | 120 | /// Cancels a subscription. 121 | /// 122 | /// For more details see https://stripe.com/docs/api#cancel_subscription. 123 | pub fn cancel(client: &Client, subscription_id: &str, params: CancelParams) -> Result { 124 | client.delete(&format!("/subscriptions/{}?{}", subscription_id, qs::to_string(¶ms)?)) 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/resources/transaction.rs: -------------------------------------------------------------------------------- 1 | /// The resource representing a Stripe transaction. 2 | /// 3 | /// For more details see https://stripe.com/docs/api#transaction_object. 4 | #[derive(Debug, Deserialize, Serialize)] 5 | pub struct Transaction { 6 | // missing page in Stripe API 7 | } 8 | -------------------------------------------------------------------------------- /src/resources/transfer.rs: -------------------------------------------------------------------------------- 1 | use params::{List, Metadata, Timestamp}; 2 | use resources::Currency; 3 | 4 | /// The resource representing a Stripe transfer reversal. 5 | /// 6 | /// For more details see https://stripe.com/docs/api#transfer_reversal_object. 7 | #[derive(Debug, Deserialize, Serialize)] 8 | pub struct TransferReversal { 9 | pub id: String, 10 | pub object: String, 11 | pub amount: u64, 12 | pub balance_transaction: String, 13 | pub created: Timestamp, 14 | pub currency: Currency, 15 | pub metadata: Metadata, 16 | pub transfer: String, 17 | } 18 | 19 | /// The resource representing a Stripe transfer. 20 | /// 21 | /// For more details see https://stripe.com/docs/api#transfer_object. 22 | #[derive(Debug, Deserialize, Serialize)] 23 | pub struct Transfer { 24 | pub id: String, 25 | pub object: String, 26 | pub amount: u64, 27 | pub amount_reversed: u64, 28 | pub balance_transaction: String, 29 | pub created: Timestamp, 30 | pub currency: Currency, 31 | pub description: Option, 32 | pub destination: String, 33 | pub destination_payment: String, 34 | pub livemode: bool, 35 | pub metadata: Metadata, 36 | pub reversals: List, 37 | pub reversed: bool, 38 | pub source_transaction: String, 39 | pub source_type: String, 40 | pub transfer_group: String, 41 | } 42 | -------------------------------------------------------------------------------- /tests/encoding.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate serde_json as json; 2 | extern crate serde_qs as qs; 3 | extern crate stripe; 4 | 5 | #[test] 6 | fn debug_currency() { 7 | use stripe::Currency; 8 | assert_eq!(format!("{:?}", Currency::AED), "AED"); 9 | assert_eq!(format!("{:?}", Currency::USD), "USD"); 10 | assert_eq!(format!("{:?}", Currency::ZMW), "ZMW"); 11 | } 12 | 13 | #[test] 14 | fn display_currency() { 15 | use stripe::Currency; 16 | assert_eq!(format!("{}", Currency::AED), "aed"); 17 | assert_eq!(format!("{}", Currency::USD), "usd"); 18 | assert_eq!(format!("{}", Currency::ZMW), "zmw"); 19 | } 20 | 21 | #[test] 22 | fn serialize_currency() { 23 | use stripe::Currency; 24 | assert_eq!(json::to_string(&Currency::AED).unwrap(), "\"aed\""); 25 | assert_eq!(json::to_string(&Currency::USD).unwrap(), "\"usd\""); 26 | assert_eq!(json::to_string(&Currency::ZMW).unwrap(), "\"zmw\""); 27 | } 28 | 29 | #[test] 30 | fn deserialize_currency() { 31 | use stripe::Currency; 32 | assert_eq!(json::from_str::("\"aed\"").unwrap(), Currency::AED); 33 | assert_eq!(json::from_str::("\"usd\"").unwrap(), Currency::USD); 34 | assert_eq!(json::from_str::("\"zmw\"").unwrap(), Currency::ZMW); 35 | } 36 | 37 | #[test] 38 | fn serialize_range_query() { 39 | use stripe::{CustomerListParams, RangeQuery, RangeBounds}; 40 | 41 | let query = RangeQuery::Bounds(RangeBounds { 42 | gt: None, 43 | gte: Some(1501598702), 44 | lt: Some(1504233902), 45 | lte: None, 46 | }); 47 | assert_eq!(urldecode(qs::to_string(&query).unwrap()), "gte=1501598702<=1504233902"); 48 | 49 | let mut params = CustomerListParams::default(); 50 | params.created = Some(RangeQuery::eq(1501598702)); 51 | params.limit = Some(3); 52 | assert_eq!(urldecode(qs::to_string(¶ms).unwrap()), "created=1501598702&limit=3"); 53 | 54 | let mut params = CustomerListParams::default(); 55 | params.created = Some(RangeQuery::gte(1501598702)); 56 | params.limit = Some(3); 57 | assert_eq!(urldecode(qs::to_string(¶ms).unwrap()), "created[gte]=1501598702&limit=3"); 58 | 59 | let mut params = CustomerListParams::default(); 60 | params.created = Some(query); 61 | params.limit = Some(3); 62 | let encoded = urldecode(qs::to_string(¶ms).unwrap()); 63 | assert_eq!(encoded, "created[gte]=1501598702&created[lt]=1504233902&limit=3"); 64 | } 65 | 66 | fn urldecode(input: String) -> String { 67 | input.replace("%5B", "[").replace("%5D", "]") 68 | } 69 | 70 | #[test] 71 | fn deserialize_payment_source_params() { 72 | use stripe::{CardParams, PaymentSourceParams, SourceId, TokenId}; 73 | 74 | let examples = [ 75 | (json!("src_xyzABC123"), 76 | Some(PaymentSourceParams::Source("src_xyzABC123".parse::().unwrap()))), 77 | (json!("tok_189g322eZvKYlo2CeoPw2sdy"), 78 | Some(PaymentSourceParams::Token("tok_189g322eZvKYlo2CeoPw2sdy".parse::().unwrap()))), 79 | (json!({"object": "card", "exp_month": "12", "exp_year": "2017", "number": "1111222233334444"}), 80 | Some(PaymentSourceParams::Card(CardParams { 81 | exp_month: "12", 82 | exp_year: "2017", 83 | number: "1111222233334444", 84 | name: None, 85 | cvc: None, 86 | }))), 87 | 88 | // Error: Missing `{"object": "card"}` 89 | (json!({"exp_month": "12", "exp_year": "2017", "number": "1111222233334444"}), None), 90 | ]; 91 | 92 | for (value, expected) in &examples { 93 | let input = json::to_string(value).unwrap(); 94 | let parsed: Option = json::from_str(&input).ok(); 95 | assert_eq!(json!(parsed), json!(expected)); 96 | } 97 | } 98 | 99 | #[test] 100 | fn serialize_payment_source_params() { 101 | use stripe::{CardParams, PaymentSourceParams, SourceId, TokenId}; 102 | 103 | let examples = [ 104 | (PaymentSourceParams::Source("src_xyzABC123".parse::().unwrap()), json!("src_xyzABC123")), 105 | (PaymentSourceParams::Token("tok_189g322eZvKYlo2CeoPw2sdy".parse::().unwrap()), json!("tok_189g322eZvKYlo2CeoPw2sdy")), 106 | (PaymentSourceParams::Card(CardParams { 107 | exp_month: "12", 108 | exp_year: "2017", 109 | number: "1111222233334444", 110 | name: None, 111 | cvc: None, 112 | }), 113 | json!({ 114 | "object": "card", 115 | "exp_month": "12", 116 | "exp_year": "2017", 117 | "number": "1111222233334444", 118 | "name": null, 119 | "cvc": null 120 | })), 121 | ]; 122 | 123 | for (params, expected) in &examples { 124 | let value = json::to_value(params).unwrap(); 125 | assert_eq!(&value, expected); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /tests/example.rs: -------------------------------------------------------------------------------- 1 | extern crate serde_json as json; 2 | extern crate stripe; 3 | 4 | #[test] 5 | #[ignore] // TODO: Figure out how to run this test with an sk_key, etc 6 | fn customer_delete() { 7 | let client = stripe::Client::new("sk_key"); 8 | let result = stripe::Customer::delete(&client, "cus_example_id"); 9 | match result { 10 | Ok(deleted) => assert!(deleted.deleted, "Customer wasn't deleted"), 11 | Err(err) => assert!(false, format!("{}", err)), 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/sync.rs: -------------------------------------------------------------------------------- 1 | extern crate stripe; 2 | 3 | use std::sync::Arc; 4 | use std::thread; 5 | 6 | #[test] 7 | fn sync() { 8 | let client = Arc::new(stripe::Client::new("sk_key")); 9 | let clone1 = client.clone(); 10 | let clone2 = client.clone(); 11 | thread::spawn(move || { 12 | assert!(stripe::Customer::retrieve(&clone1, "").is_err()); 13 | }); 14 | thread::spawn(move || { 15 | assert!(stripe::Customer::retrieve(&clone2, "").is_err()); 16 | }); 17 | } 18 | --------------------------------------------------------------------------------