synapse_payments 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ddd2a41ccc17df99fb5fe4db0ac880ab279c7435
4
+ data.tar.gz: 7af2509dd87a509263c946d4f18ca892f903af49
5
+ SHA512:
6
+ metadata.gz: 518d596a730d075ba628eb364df903adbb906ea641588ec814d6cddc16b20998825ae065f98d9683a23b57e72e39e00648644dbfa35bb1b59ec44888a598424c
7
+ data.tar.gz: b16a8975143fbe27fac7538210432c76e1390218bc7897f1078db858ee8f3ad6fef26ca34eed1c1e4fc5767b7ac8a0c8035259c4960303ae67ec0786e1efd573
@@ -0,0 +1,2 @@
1
+ SYNAPSE_PAYMENTS_CLIENT_ID="YOUR_CLIENT_ID"
2
+ SYNAPSE_PAYMENTS_CLIENT_SECRET="YOUR_CLIENT_SECRET"
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ .env
@@ -0,0 +1,14 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.5
4
+ - 2.2.3
5
+ before_install: gem install bundler -v 1.10.6
6
+ cache: bundler
7
+ sudo: false
8
+ fast_finish: true
9
+ env:
10
+ - USER_ID=
11
+ notifications:
12
+ email:
13
+ on_success: always
14
+ on_failure: always
@@ -0,0 +1,13 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
4
+
5
+ We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
6
+
7
+ Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
8
+
9
+ Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
10
+
11
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
12
+
13
+ This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in synapse_payments.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Javier Julio
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,67 @@
1
+ # The SynapsePayments Ruby Gem
2
+
3
+ A tested Ruby interface to the [SynapsePay v3 API](http://docs.synapsepay.com/v3.1). Note: Requires **Ruby 2.1 and up**. Not all API actions are supported. Find out more in the TODO section.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'synapse_payments'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install synapse_payments
20
+
21
+ To try out the gem and experiment, you're better off following the development instructions.
22
+
23
+ ## Usage
24
+
25
+ Check out [samples.md](samples.md) to review how to use this library.
26
+
27
+ ## Development
28
+
29
+ 1. Clone the repo: `git clone https://github.com/javierjulio/synapse_payments.git`
30
+ 2. Use Ruby 2.1 and up. If you need to install use [rbenv](https://github.com/sstephenson/rbenv) and [ruby-build](https://github.com/sstephenson/ruby-build) and then run:
31
+
32
+ gem update --system
33
+ gem update
34
+ gem install bundler --no-rdoc --no-ri
35
+
36
+ 3. From project root run `./bin/setup` script
37
+ 4. Run `./bin/console` for an interactive prompt with an authenticated client for you to experiment:
38
+
39
+ ```ruby
40
+ users = client.users.all
41
+ puts users
42
+ # => {...
43
+ ```
44
+
45
+ ### TODO
46
+
47
+ * add pagination/querying to `users.all`, `nodes.all`, and `transactions.all`
48
+ * add support for new `subscriptions` resource
49
+ * add new methods to UserClient: `link_bank_account`, `verify_mfa`, `attach_photo_id`, `add_escrow_account`
50
+ * add `Banks` object with `list` method which returns supported banks from https://synapsepay.com/api/v3/institutions/show
51
+ * consider creating a `Response` object wrapper
52
+
53
+ ### Tests
54
+
55
+ Run `bundle exec rake test`. To include integration tests run with `USER_ID=YOUR_USER_ID` being a user you created in sandbox.
56
+
57
+ ### Releasing
58
+
59
+ To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
60
+
61
+ ## Contributing
62
+
63
+ Bug reports and pull requests are welcome on GitHub at https://github.com/javierjulio/synapse_payments. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
64
+
65
+ ## License
66
+
67
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "synapse_payments"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require 'dotenv'
14
+ Dotenv.load
15
+
16
+ def client
17
+ @client ||= SynapsePayments::Client.new do |config|
18
+ config.client_id = ENV['SYNAPSE_PAYMENTS_CLIENT_ID']
19
+ config.client_secret = ENV['SYNAPSE_PAYMENTS_CLIENT_SECRET']
20
+ end
21
+ end
22
+
23
+ def reset_client
24
+ @client = nil
25
+ client
26
+ true
27
+ end
28
+
29
+ require "irb"
30
+ IRB.start
@@ -0,0 +1,29 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ read -r -p 'Do you have a SynapsePay sandbox account? (y/n) ' has_account
8
+
9
+ if [[ "$has_account" =~ ^(Yes|yes|Y|y)$ ]]; then
10
+ echo "Great! You can get your account credentials from:"
11
+ echo " https://sandbox.synapsepay.com/v3/dashboard/#/profile"
12
+ echo
13
+ else
14
+ echo "Then you'll need to create an account first at:"
15
+ echo " http://docs.synapsepay.com/docs/sandbox-keys"
16
+ echo
17
+ read -s -p "Press Enter key if you're ready to continue..."
18
+ echo
19
+ fi
20
+
21
+ echo "Enter your account credentials below."
22
+ read -p 'Client ID: ' client_id
23
+ read -p 'Client Secret: ' client_secret
24
+
25
+ cp .env.sample .env
26
+ sed -i -e s/YOUR_CLIENT_ID/"$client_id"/g .env
27
+ sed -i -e s/YOUR_CLIENT_SECRET/"$client_secret"/g .env
28
+
29
+ echo "Done."
@@ -0,0 +1,9 @@
1
+ require "synapse_payments/version"
2
+ require "synapse_payments/error"
3
+ require "synapse_payments/client"
4
+ require "synapse_payments/user_client"
5
+ require "synapse_payments/request"
6
+ require "synapse_payments/users"
7
+ require "synapse_payments/nodes"
8
+ require "synapse_payments/node"
9
+ require "synapse_payments/transactions"
@@ -0,0 +1,60 @@
1
+ require 'http'
2
+
3
+ module SynapsePayments
4
+ class Client
5
+
6
+ API_TEST = 'https://sandbox.synapsepay.com/api/3'
7
+ API_LIVE = 'https://synapsepay.com/api/3'
8
+
9
+ attr_accessor :client_id, :client_secret, :sandbox_mode
10
+ attr_reader :api_base, :users
11
+
12
+ # Initializes a new Client object
13
+ #
14
+ # @param options [Hash]
15
+ # @return [SynapsePayments::Client]
16
+ def initialize(options={})
17
+ @sandbox_mode = true
18
+
19
+ options.each do |key, value|
20
+ instance_variable_set("@#{key}", value)
21
+ end
22
+
23
+ yield(self) if block_given?
24
+
25
+ @api_base = @sandbox_mode ? API_TEST : API_LIVE
26
+
27
+ @users = Users.new(self)
28
+ end
29
+
30
+ # @return [Hash]
31
+ def credentials
32
+ {
33
+ client_id: client_id,
34
+ client_secret: client_secret
35
+ }
36
+ end
37
+
38
+ # @return [Boolean]
39
+ def credentials?
40
+ credentials.values.all?
41
+ end
42
+
43
+ def get(path:, oauth_key: nil)
44
+ Request.new(client: self, method: :get, path: path, oauth_key: oauth_key).perform
45
+ end
46
+
47
+ def post(path:, json:, oauth_key: nil)
48
+ Request.new(client: self, method: :post, path: path, oauth_key: oauth_key, json: json).perform
49
+ end
50
+
51
+ def patch(path:, json:, oauth_key: nil)
52
+ Request.new(client: self, method: :patch, path: path, oauth_key: oauth_key, json: json).perform
53
+ end
54
+
55
+ def delete(path:, oauth_key: nil)
56
+ Request.new(client: self, method: :delete, path: path, oauth_key: oauth_key).perform
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,114 @@
1
+ module SynapsePayments
2
+ class Error < StandardError
3
+ # Raised on a 4xx HTTP status code
4
+ ClientError = Class.new(self)
5
+
6
+ # Raised on the HTTP status code 400
7
+ BadRequest = Class.new(ClientError)
8
+
9
+ # Raised on the HTTP status code 401
10
+ Unauthorized = Class.new(ClientError)
11
+
12
+ # Raised on the HTTP status code 402
13
+ RequestDeclined = Class.new(ClientError)
14
+
15
+ # Raised on the HTTP status code 403
16
+ Forbidden = Class.new(ClientError)
17
+
18
+ # Raised on the HTTP status code 404
19
+ NotFound = Class.new(ClientError)
20
+
21
+ # Raised on the HTTP status code 406
22
+ NotAcceptable = Class.new(ClientError)
23
+
24
+ # Raised on the HTTP status code 409
25
+ Conflict = Class.new(ClientError)
26
+
27
+ # Raised on the HTTP status code 415
28
+ UnsupportedMediaType = Class.new(ClientError)
29
+
30
+ # Raised on the HTTP status code 422
31
+ UnprocessableEntity = Class.new(ClientError)
32
+
33
+ # Raised on the HTTP status code 429
34
+ TooManyRequests = Class.new(ClientError)
35
+
36
+ # Raised on a 5xx HTTP status code
37
+ ServerError = Class.new(self)
38
+
39
+ # Raised on the HTTP status code 500
40
+ InternalServerError = Class.new(ServerError)
41
+
42
+ # Raised on the HTTP status code 502
43
+ BadGateway = Class.new(ServerError)
44
+
45
+ # Raised on the HTTP status code 503
46
+ ServiceUnavailable = Class.new(ServerError)
47
+
48
+ # Raised on the HTTP status code 504
49
+ GatewayTimeout = Class.new(ServerError)
50
+
51
+ ERRORS = {
52
+ 400 => SynapsePayments::Error::BadRequest,
53
+ 401 => SynapsePayments::Error::Unauthorized,
54
+ 402 => SynapsePayments::Error::RequestDeclined,
55
+ 403 => SynapsePayments::Error::Forbidden,
56
+ 404 => SynapsePayments::Error::NotFound,
57
+ 406 => SynapsePayments::Error::NotAcceptable,
58
+ 409 => SynapsePayments::Error::Conflict,
59
+ 415 => SynapsePayments::Error::UnsupportedMediaType,
60
+ 422 => SynapsePayments::Error::UnprocessableEntity,
61
+ 429 => SynapsePayments::Error::TooManyRequests,
62
+ 500 => SynapsePayments::Error::InternalServerError,
63
+ 502 => SynapsePayments::Error::BadGateway,
64
+ 503 => SynapsePayments::Error::ServiceUnavailable,
65
+ 504 => SynapsePayments::Error::GatewayTimeout,
66
+ }
67
+
68
+ # The SynapsePay API Error Code
69
+ #
70
+ # @return [Integer]
71
+ attr_reader :code
72
+
73
+ # The JSON HTTP response in Hash form
74
+ #
75
+ # @return [Hash]
76
+ attr_reader :response
77
+
78
+ class << self
79
+ # Create a new error from an HTTP response
80
+ #
81
+ # @param body [String]
82
+ # @param code [Integer]
83
+ # @return [SynapsePayments::Error]
84
+ def error_from_response(body, code)
85
+ klass = ERRORS[code] || SynapsePayments::Error
86
+ message, error_code = parse_error(body)
87
+ klass.new(message: message, code: error_code, response: body)
88
+ end
89
+
90
+ private
91
+
92
+ def parse_error(body)
93
+ if body.nil? || body.empty?
94
+ ['', nil]
95
+ elsif body.is_a?(Hash) && body['error'].is_a?(Hash)
96
+ [body['error']['en'], body['error_code']]
97
+ end
98
+ end
99
+
100
+ end
101
+
102
+ # Initializes a new Error object
103
+ #
104
+ # @param message [Exception, String]
105
+ # @param code [Integer]
106
+ # @param response [Hash]
107
+ # @return [SynapsePayments::Error]
108
+ def initialize(message: '', code: nil, response: {})
109
+ super(message)
110
+ @code = code
111
+ @response = response
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,16 @@
1
+ module SynapsePayments
2
+ class Node
3
+
4
+ attr_reader :transactions
5
+
6
+ def initialize(client, user_id, node_id, oauth_key)
7
+ @client = client
8
+ @user_id = user_id
9
+ @node_id = node_id
10
+ @oauth_key = oauth_key
11
+ @transactions = Transactions.new(@client, user_id, node_id, oauth_key)
12
+ end
13
+
14
+ end
15
+
16
+ end
@@ -0,0 +1,28 @@
1
+ module SynapsePayments
2
+ class Nodes
3
+
4
+ def initialize(client, user_id, oauth_key)
5
+ @client = client
6
+ @user_id = user_id
7
+ @oauth_key = oauth_key
8
+ end
9
+
10
+ def all
11
+ @client.get(path: "/users/#{@user_id}/nodes", oauth_key: @oauth_key)
12
+ end
13
+
14
+ def find(id)
15
+ @client.get(path: "/users/#{@user_id}/nodes/#{id}", oauth_key: @oauth_key)
16
+ end
17
+
18
+ def create(data)
19
+ @client.post(path: "/users/#{@user_id}/nodes", oauth_key: @oauth_key, json: data)
20
+ end
21
+
22
+ def delete(id)
23
+ @client.delete(path: "/users/#{@user_id}/nodes/#{id}", oauth_key: @oauth_key)
24
+ end
25
+
26
+ end
27
+
28
+ end
@@ -0,0 +1,57 @@
1
+ module SynapsePayments
2
+ class Request
3
+
4
+ HEADERS = {
5
+ 'Accept' => 'application/json',
6
+ 'User-Agent' => "SynapsePaymentsRubyGem/#{SynapsePayments::VERSION}",
7
+ 'X-Ruby-Version' => RUBY_VERSION,
8
+ 'X-Ruby-Platform' => RUBY_PLATFORM
9
+ }
10
+
11
+ def initialize(client:, method:, path:, oauth_key: nil, json: nil)
12
+ @client = client
13
+ @method = method
14
+ @path = path
15
+ @oauth_key = oauth_key
16
+ @json = json
17
+ end
18
+
19
+ def perform
20
+ options_key = @method == :get ? :params : :json
21
+ response = http_client.public_send(@method, "#{@client.api_base}#{@path}", options_key => @json)
22
+ response_body = symbolize_keys!(response.parse)
23
+ fail_or_return_response_body(response.code, response_body)
24
+ end
25
+
26
+ def http_client
27
+ headers = HEADERS.merge({
28
+ 'X-SP-GATEWAY' => "#{@client.client_id}|#{@client.client_secret}",
29
+ 'X-SP-USER' => "#{@oauth_key}|",
30
+ 'X-SP-USER-IP' => ''
31
+ })
32
+ HTTP.headers(headers).timeout(write: 2, connect: 5, read: 10)
33
+ end
34
+
35
+ def symbolize_keys!(object)
36
+ if object.is_a?(Array)
37
+ object.each_with_index do |val, index|
38
+ object[index] = symbolize_keys!(val)
39
+ end
40
+ elsif object.is_a?(Hash)
41
+ object.keys.each do |key|
42
+ object[key.to_sym] = symbolize_keys!(object.delete(key))
43
+ end
44
+ end
45
+ object
46
+ end
47
+
48
+ def fail_or_return_response_body(code, body)
49
+ if code < 200 || code >= 206
50
+ error = SynapsePayments::Error.error_from_response(body, code)
51
+ fail(error)
52
+ end
53
+ body
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,47 @@
1
+ module SynapsePayments
2
+ class Transactions
3
+
4
+ def initialize(client, user_id, node_id, oauth_key)
5
+ @client = client
6
+ @user_id = user_id
7
+ @node_id = node_id
8
+ @oauth_key = oauth_key
9
+ end
10
+
11
+ def all
12
+ @client.get(path: "/users/#{@user_id}/nodes/#{@node_id}/trans", oauth_key: @oauth_key)
13
+ end
14
+
15
+ def create(node_id:, node_type:, amount:, currency:, ip_address:, **args)
16
+ data = {
17
+ to: {
18
+ type: node_type,
19
+ id: node_id
20
+ },
21
+ amount: {
22
+ amount: amount,
23
+ currency: currency
24
+ },
25
+ extra: {
26
+ ip: ip_address
27
+ }.merge(args)
28
+ }
29
+
30
+ @client.post(path: "/users/#{@user_id}/nodes/#{@node_id}/trans", oauth_key: @oauth_key, json: data)
31
+ end
32
+
33
+ def delete(id)
34
+ @client.delete(path: "/users/#{@user_id}/nodes/#{@node_id}/trans/#{id}", oauth_key: @oauth_key)
35
+ end
36
+
37
+ def find(id)
38
+ @client.get(path: "/users/#{@user_id}/nodes/#{@node_id}/trans/#{id}", oauth_key: @oauth_key)
39
+ end
40
+
41
+ def update(id, data)
42
+ @client.patch(path: "/users/#{@user_id}/nodes/#{@node_id}/trans/#{id}", oauth_key: @oauth_key, json: data)
43
+ end
44
+
45
+ end
46
+
47
+ end
@@ -0,0 +1,105 @@
1
+ module SynapsePayments
2
+ class UserClient
3
+
4
+ def initialize(client, user_id, response)
5
+ @client = client
6
+ @user_id = user_id
7
+ @response = response
8
+ @oauth_key = response[:oauth_key]
9
+
10
+ response.each do |key, value|
11
+ (class << self; self; end).class_eval do
12
+ define_method key do |*args|
13
+ response[key]
14
+ end
15
+ end
16
+ end
17
+
18
+ @nodes = Nodes.new(@client, user_id, oauth_key)
19
+ end
20
+
21
+ def user
22
+ @client.get(path: "/users/#{@user_id}", oauth_key: @oauth_key)
23
+ end
24
+
25
+ # Adds a virtual document for KYC
26
+ #
27
+ # @param birthdate [Date]
28
+ # @param first_name [String]
29
+ # @param last_name [String]
30
+ # @param street [String]
31
+ # @param postal_code [String]
32
+ # @param country_code [String] The country code in ISO format e.g. US
33
+ # @param document_type [String] Acceptable document types: SSN, PASSPORT, DRIVERS_LICENSE, PERSONAL_IDENTIFICATION, NONE
34
+ # @param document_value [String]
35
+ # @return [Hash]
36
+ def add_document(birthdate:, first_name:, last_name:, street:, postal_code:, country_code:, document_type:, document_value:)
37
+ data = {
38
+ doc: {
39
+ birth_day: birthdate.day,
40
+ birth_month: birthdate.month,
41
+ birth_year: birthdate.year,
42
+ name_first: first_name,
43
+ name_last: last_name,
44
+ address_street1: street,
45
+ address_postal_code: postal_code,
46
+ address_country_code: country_code,
47
+ document_type: document_type,
48
+ document_value: document_value
49
+ }
50
+ }
51
+
52
+ @client.patch(path: "/users/#{@user_id}", oauth_key: @oauth_key, json: data)
53
+ end
54
+
55
+ def answer_kba(question_set_id:, answers:)
56
+ data = {
57
+ doc: {
58
+ question_set_id: question_set_id,
59
+ answers: answers
60
+ }
61
+ }
62
+
63
+ @client.patch(path: "/users/#{@user_id}", oauth_key: @oauth_key, json: data)
64
+ end
65
+
66
+ # Adds a bank account by creating a node of node type ACH-US.
67
+ #
68
+ # @param name [String] the name of the account holder
69
+ # @param account_number [String]
70
+ # @param routing_number [String]
71
+ # @param category [String] the account category, `personal` or `business`
72
+ # @param type [String] the account type, `checking` or `savings`
73
+ # @return [Hash]
74
+ def add_bank_account(name:, account_number:, routing_number:, category:, type:, **args)
75
+ data = {
76
+ type: 'ACH-US',
77
+ info: {
78
+ nickname: args[:nickname] || name,
79
+ name_on_account: name,
80
+ account_num: account_number,
81
+ routing_num: routing_number,
82
+ type: category,
83
+ class: type
84
+ },
85
+ extra: {
86
+ supp_id: args[:supp_id]
87
+ }
88
+ }
89
+ nodes.create(data)
90
+ end
91
+
92
+ def send_money(from:, to:, to_node_type:, amount:, currency:, ip_address:)
93
+ nodes(from).transactions.create(node_id: to, node_type: to_node_type, amount: amount, currency: currency, ip_address: ip_address)
94
+ end
95
+
96
+ def nodes(id=nil)
97
+ if id.nil?
98
+ @nodes
99
+ else
100
+ Node.new(@client, @user_id, id, @oauth_key)
101
+ end
102
+ end
103
+
104
+ end
105
+ end
@@ -0,0 +1,38 @@
1
+ module SynapsePayments
2
+ class Users
3
+
4
+ def initialize(client)
5
+ @client = client
6
+ end
7
+
8
+ def all
9
+ @client.get(path: '/users')
10
+ end
11
+
12
+ def authenticate_as(id:, refresh_token:)
13
+ response = @client.post(path: "/oauth/#{id}", json: { refresh_token: refresh_token })
14
+ UserClient.new(@client, id, response)
15
+ end
16
+
17
+ def create(name:, email:, phone:, is_business: false, **args)
18
+ data = {
19
+ logins: email.is_a?(Array) ? email : [{ email: email }],
20
+ phone_numbers: phone.is_a?(Array) ? phone : [phone],
21
+ legal_names: name.is_a?(Array) ? name : [name],
22
+ extra: {
23
+ note: args[:note],
24
+ supp_id: args[:supp_id],
25
+ is_business: is_business
26
+ }
27
+ }
28
+
29
+ @client.post(path: '/users', json: data)
30
+ end
31
+
32
+ def find(id)
33
+ @client.get(path: "/users/#{id}")
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -0,0 +1,3 @@
1
+ module SynapsePayments
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,150 @@
1
+ ## Initialization
2
+
3
+ ```ruby
4
+ require 'synapse_payments'
5
+
6
+ client = SynapsePayments::Client.new(client_id: 'client_id', client_secret: 'client_secret')
7
+
8
+ # or configure with a block (note: sandbox_mode is true by default)
9
+
10
+ client = SynapsePayments::Client.new do |config|
11
+ config.client_id = 'your_client_id'
12
+ config.client_secret = 'your_client_id'
13
+ config.sandbox_mode = false
14
+ end
15
+ ```
16
+
17
+ ### Users
18
+
19
+ #### Retrieve all users (paginated)
20
+
21
+ ```ruby
22
+ response = client.users.all
23
+ ```
24
+
25
+ #### Create a user
26
+
27
+ ```ruby
28
+ response = client.users.create(
29
+ name: 'John Smith',
30
+ email: 'johnsmith@example.com',
31
+ phone: '123-456-7890'
32
+ )
33
+
34
+ # or specify multiple names, logins, phones...
35
+
36
+ response = client.users.create(
37
+ name: ['John Smith', 'Bill Smith'],
38
+ email: [
39
+ { email: 'johnsmith@example.com' },
40
+ { email: 'billsmith@example.com' }
41
+ ],
42
+ phone: ['123-456-7890','123-555-6677']
43
+ )
44
+ ```
45
+
46
+ #### Retrieve a user
47
+
48
+ ```ruby
49
+ response = client.users.find(id)
50
+ ```
51
+
52
+ #### Authenticate as a user
53
+
54
+ ```ruby
55
+ response = client.users.find(id)
56
+
57
+ user_client = client.users.authenticate_as(id: id, refresh_token: response[:refresh_token])
58
+
59
+ user = user_client.user # returns user representation
60
+ ```
61
+
62
+ #### Update a user
63
+
64
+ NOTE: Action needs to be implemented.
65
+
66
+ #### Add a document
67
+
68
+ ```ruby
69
+ response = user_client.add_document(
70
+ birthdate: Date.parse('1970/3/14'),
71
+ first_name: 'John',
72
+ last_name: 'Doe',
73
+ street: '1 Infinite Loop',
74
+ postal_code: '95014',
75
+ country_code: 'US',
76
+ document_type: 'SSN',
77
+ document_value: '2222'
78
+ )
79
+ ```
80
+
81
+ #### Answer KBA questions
82
+
83
+ ```ruby
84
+ response = user_client.answer_kba(
85
+ question_set_id: "557520ad343463000300005a",
86
+ answers: [
87
+ { question_id: 1, answer_id: 1 },
88
+ { question_id: 2, answer_id: 1 },
89
+ { question_id: 3, answer_id: 1 },
90
+ { question_id: 4, answer_id: 1 },
91
+ { question_id: 5, answer_id: 1 }
92
+ ]
93
+ )
94
+ ```
95
+
96
+ #### Attach photo ID
97
+
98
+ NOTE: Action needs to be implemented.
99
+
100
+ #### Add a bank account
101
+
102
+ ```ruby
103
+ response = user_client.add_bank_account(
104
+ name: 'John Doe',
105
+ account_number: '72347235423',
106
+ routing_number: '051000017',
107
+ category: 'PERSONAL',
108
+ type: 'CHECKING'
109
+ )
110
+ ```
111
+
112
+ #### Send money 💸
113
+
114
+ ```ruby
115
+ response = user_client.send_money(
116
+ from: node_id,
117
+ to: to_node_id,
118
+ to_node_type: 'SYNAPSE-US',
119
+ amount: 24.00,
120
+ currency: 'USD',
121
+ ip_address: '192.168.0.1'
122
+ )
123
+ ```
124
+
125
+ #### Nodes
126
+
127
+ TODO: add more detail
128
+
129
+ ```ruby
130
+ user_client.nodes.all
131
+ user_client.nodes.create(data)
132
+ user_client.nodes.delete(id)
133
+ user_client.nodes.find(id)
134
+ ```
135
+
136
+ #### Transactions
137
+
138
+ TODO: add more detail
139
+
140
+ ```ruby
141
+ user_client.nodes(node_id).transactions.all
142
+ user_client.nodes(node_id).transactions.create(node_id:, node_type:, amount:, currency:, ip_address:)
143
+ user_client.nodes(node_id).transactions.delete(id)
144
+ user_client.nodes(node_id).transactions.find(id)
145
+ user_client.nodes(node_id).transactions.update(id, data)
146
+ ```
147
+
148
+ #### Error Handling
149
+
150
+ TODO: add detail
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'synapse_payments/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "synapse_payments"
8
+ spec.version = SynapsePayments::VERSION
9
+ spec.authors = ["Javier Julio"]
10
+ spec.email = ["jjfutbol@gmail.com"]
11
+
12
+ spec.summary = "A tested Ruby interface to the SynapsePay v3 API."
13
+ spec.description = "Requires Ruby 2.1 and up. Not all API actions are supported. Find out more in the readme todo section."
14
+ spec.homepage = "https://github.com/javierjulio/synapse_payments"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.10"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+ spec.add_development_dependency "dotenv"
25
+ spec.add_development_dependency "minitest"
26
+ spec.add_development_dependency "minitest-reporters"
27
+ spec.add_development_dependency "vcr"
28
+ spec.add_development_dependency "webmock"
29
+
30
+ spec.add_dependency "http", '~> 0.9.8'
31
+
32
+ end
metadata ADDED
@@ -0,0 +1,179 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: synapse_payments
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Javier Julio
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-11-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.10'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: dotenv
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: minitest-reporters
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: vcr
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: webmock
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: http
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 0.9.8
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 0.9.8
125
+ description: Requires Ruby 2.1 and up. Not all API actions are supported. Find out
126
+ more in the readme todo section.
127
+ email:
128
+ - jjfutbol@gmail.com
129
+ executables: []
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - ".env.sample"
134
+ - ".gitignore"
135
+ - ".travis.yml"
136
+ - CODE_OF_CONDUCT.md
137
+ - Gemfile
138
+ - LICENSE.txt
139
+ - README.md
140
+ - Rakefile
141
+ - bin/console
142
+ - bin/setup
143
+ - lib/synapse_payments.rb
144
+ - lib/synapse_payments/client.rb
145
+ - lib/synapse_payments/error.rb
146
+ - lib/synapse_payments/node.rb
147
+ - lib/synapse_payments/nodes.rb
148
+ - lib/synapse_payments/request.rb
149
+ - lib/synapse_payments/transactions.rb
150
+ - lib/synapse_payments/user_client.rb
151
+ - lib/synapse_payments/users.rb
152
+ - lib/synapse_payments/version.rb
153
+ - samples.md
154
+ - synapse_payments.gemspec
155
+ homepage: https://github.com/javierjulio/synapse_payments
156
+ licenses:
157
+ - MIT
158
+ metadata: {}
159
+ post_install_message:
160
+ rdoc_options: []
161
+ require_paths:
162
+ - lib
163
+ required_ruby_version: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ version: '0'
168
+ required_rubygems_version: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - ">="
171
+ - !ruby/object:Gem::Version
172
+ version: '0'
173
+ requirements: []
174
+ rubyforge_project:
175
+ rubygems_version: 2.4.8
176
+ signing_key:
177
+ specification_version: 4
178
+ summary: A tested Ruby interface to the SynapsePay v3 API.
179
+ test_files: []