bitpay-sdk 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 05ceac9c5a451d327ccaca3d7d5df7b4b791612e
4
- data.tar.gz: 8bd0c8fd5d09f22b9a90dfcb8dd80ea841b70b4f
3
+ metadata.gz: a2250870a264044316b2cc449c5b9e03adafc8e4
4
+ data.tar.gz: fddc03975809e69617b2b5f0f489f21a7c4e9d63
5
5
  SHA512:
6
- metadata.gz: 35f0005e156651cf165e3ae64bd42feecca410d7a9ac01dc0dcf3fd4c1e9596cbfe3d45de8c7a98214f95d0fe9ac8fca1a5e96707dbfd2064db9f5abd477353d
7
- data.tar.gz: 431badf6d99383c1670af5f60599186a6c830e62953de356c93e913dedcc6d5738d588de75aadb1cdcc10e45a4edb31ea215845fc6d584d037012842a28f86bd
6
+ metadata.gz: b379b23455f8df1a27b07d701c8c21153414463e5e14a45325e560890958233a23073ef2529fd6cfabf0dac36911647e4f08efc94db4f7fb2c856c6a5a2c8330
7
+ data.tar.gz: 429da072948807f64bcf7a1a6600068cb08fabdc8928e48811be3bcfdba07a5527d032405be1fb2a2e3f4d13478f4b07f6f8ed3f9a52de92d9a68fc72b7d2671
data/.gitignore CHANGED
@@ -7,3 +7,4 @@ pkg
7
7
  .ruby-gemset
8
8
  *.swo
9
9
  *.swp
10
+ bitpaykey.pem
@@ -1,3 +1,2 @@
1
1
  rvm:
2
- - 2.1.0
3
-
2
+ - 2.1.0
data/README.md CHANGED
@@ -1,62 +1,187 @@
1
- # BitPay Library for Ruby [![](https://secure.travis-ci.org/bitpay/ruby-client.png)](http://travis-ci.org/bitpay/ruby-client)
1
+ # BitPay Library for Ruby [![](https://secure.travis-ci.org/bitpay/ruby-client.png)](http://travis-ci.org/bitpay/ruby-client) [![Gem Version](https://badge.fury.io/rb/bitpay-sdk.svg)](http://badge.fury.io/rb/bitpay-sdk)
2
2
  Powerful, flexible, lightweight interface to the BitPay Bitcoin Payment Gateway API.
3
3
 
4
+ The `bitpay-sdk` gem provides all the programattic tools required to implement a ruby client application for the BitPay REST API. For developers who prefer the ease of command-line pairing during the development or deployment process, BitPay provides a complementary [Ruby CLI gem](https://github.com/bitpay/ruby-cli) which can be used in conjunction with this gem.
5
+
4
6
  ## Installation
5
7
 
6
- gem install bitpay-sdk
7
-
8
+ ```bash
9
+ gem install bitpay-sdk
10
+ ```
11
+
8
12
  In your Gemfile:
9
13
 
10
- gem 'bitpay-sdk', :require => 'bitpay_sdk'
14
+ ```ruby
15
+ gem 'bitpay-sdk', :require => 'bitpay_sdk'
16
+ ```
11
17
 
12
18
  Or directly:
13
-
14
- require 'bitpay_sdk'
19
+ ```ruby
20
+ require 'bitpay_sdk'
21
+ ```
15
22
 
16
23
  ## Configuration
17
24
 
18
25
  The bitpay client creates a cryptographically secure connection to your server by pairing an API code with keys generated by the library. The client can be initialized with pre-existing keys passed in as a pem file, or paired if initialized with a pem file and a tokens hash. Examples can be found in the cucumber step helpers.
19
26
 
20
- ## Basic Usage
27
+ ## Client Setup
21
28
 
22
29
  ### Pairing with Bitpay.com
23
30
 
24
- To pair with bitpay.com you need to have an approved merchant account.
25
- 1. Login to your account
26
- 2. Navigate to bitpay.com/api-tokens (Dashboard > My Account > API Tokens)
27
- 3. Create a new token and copy the pairing code.
31
+ Most calls to the BitPay REST API require that your client is paired with the bitpay.com server. To pair with bitpay.com you need to have an approved merchant account.
32
+
33
+ Your client can be paired via the `pos` (point-of-sale) or `merchant` facade (or both). The `pos` facade allows for invoices to be created. The `merchant` facade has broader privileges to view all invoices, bills, and ledger entries, as well as to issue refunds. Consider the level of access required when you pair your client.
34
+
35
+ _For development or quick deployment purposes, consider the [BitPay Ruby Command-Line Interface](https://github.com/bitpay/ruby-cli) to simplify the deployment process_
36
+
37
+ ### Pairing Programattically
38
+
39
+ If you are developing a client with built-in pairing capability, you can pair programattically using the `pair_client` method. This method can be called in two ways:
40
+
41
+ * `pair_client()` will perform a client-initiated pairing, and will provide a pairing code that can be entered at https://bitpay.com/dashboard/merchant/api-tokens to assign either `merchant` or `pos` facade.
42
+ * `pair_client('pairing_code')` will complete a server-initiated pairing, when provided a pre-generated pairing code from https://bitpay.com/dashboard/merchant/api-tokens. In this case, the `pos` facade will be automatically assigned.
28
43
 
29
- client = BitPay::Client.new
30
- client.pair_pos_client(<pairing_code>)
31
- invoice = client.create_invoice (price: <price>, currency: <currency>)
44
+ The example below demonstrates this using a locally generated PEM file using OpenSSL and the irb tool.
45
+
46
+ ```bash
47
+ $ gem install bitpay-sdk
48
+ Successfully installed bitpay-sdk-2.2.0
49
+ 1 gem installed
50
+ $ openssl ecparam -genkey -name secp256k1 -noout -out bitpaykey.pem
51
+ $ irb
52
+ 2.1.1 :001 > require 'bitpay_sdk'
53
+ => true
54
+ 2.1.1 :002 > client = BitPay::SDK::Client.new(api_uri: 'https://test.bitpay.com', pem: File.read('bitpaykey.pem'), insecure: true)
55
+ => #<BitPay::SDK::Client:0x000000019c6d40 @pem="---... @tokens={}>
56
+ 2.1.1 :003 > client.pair_client()
57
+ => {"data"=>[{"policies"=>[{"policy"=>"id", "method"=>"inactive", "params"=>["Tf49SFeiUAtytFEW2EUqZgWj32nP51PK73M"]}], "token"=>"BKQyVdaGQZAArdkkSuvtZN5gcN2355c8vXLj5eFPkfuK", "dateCreated"=>1422474475162, "pairingExpiration"=>1422560875162, "pairingCode"=>"Vy76yTh"}]}
58
+ ```
59
+
60
+ As described above, using the value from the `pairingCode` element, visit https://test.bitpay.com/api-tokens and search to register for the appropriate facade
61
+
62
+ ## General Usage
63
+
64
+ ### Initialize the client
65
+
66
+ ```ruby
67
+ client = BitPay::SDK::Client.new(pem: File.read('bitpaykey.pem')
68
+ ```
69
+
70
+ Optional parameters:
71
+ * `api_uri` - specify a different api endpoint (e.g. 'https://test.bitpay.com'). Ensure no trailing slash.
72
+ * `tokens` - pass a stored hash of bitpay API tokens
73
+ * `user-agent` - specify a custom user-agent value
74
+ * `debug: true` - enable HTTP request logging to $stdout
75
+ * `insecure: true` - disable HTTPs certificate validation (for local test environments)
76
+
77
+ ### Create a new bitcoin invoice
78
+
79
+ ```ruby
80
+ invoice = client.create_invoice (price: <price>, currency: <currency>)
81
+ ```
32
82
 
33
83
  With invoice creation, `price` and `currency` are the only required fields. If you are sending a customer from your website to make a purchase, setting `redirectURL` will redirect the customer to your website when the invoice is paid.
34
84
 
35
85
  Response will be a hash with information on your newly created invoice. Send your customer to the `url` to complete payment:
36
86
 
37
- {
38
- "id" => "DGrAEmbsXe9bavBPMJ8kuk",
39
- "url" => "https://bitpay.com/invoice?id=DGrAEmbsXe9bavBPMJ8kuk",
40
- "status" => "new",
41
- "btcPrice" => "0.0495",
42
- "price" => 10,
43
- "currency" => "USD",
44
- "invoiceTime" => 1383265343674,
45
- "expirationTime" => 1383266243674,
46
- "currentTime" => 1383265957613
47
- }
87
+ ```javascript
88
+ {
89
+ "url": "https://bitpay.com/invoice?id=NKaqMuZWy3BAcP77RdkEEv",
90
+ "paymentUrls": {
91
+ "BIP21": "bitcoin:mvYRECDxKPaPHnjNz9ZxiTpbx29xYNoRy4?amount=0.3745",
92
+ "BIP72": "bitcoin:mvYRECDxKPaPHnjNz9ZxiTpbx29xYNoRy4?amount=0.3745&r=https://bitpay.com/i/NKaqMuZWy3BAcP77RdkEEv",
93
+ "BIP72b": "bitcoin:?r=https://bitpay.com/i/NKaqMuZWy3BAcP77RdkEEv",
94
+ "BIP73": "https://bitpay.com/i/NKaqMuZWy3BAcP77RdkEEv"
95
+ },
96
+ "status": "new",
97
+ "btcPrice": "0.3745",
98
+ "btcDue": "0.3745",
99
+ "price": 148,
100
+ "currency": "USD",
101
+ "exRates": {
102
+ "USD": 395.20000000000005
103
+ },
104
+ "invoiceTime": 1415987168612,
105
+ "expirationTime": 1415988068612,
106
+ "currentTime": 1415987168629,
107
+ "guid": "438e8237-fff1-483c-81b4-dc7dba28922a",
108
+ "id": "NKaqMuZWy3BAcP77RdkEEv",
109
+ "transactions": [
110
+
111
+ ],
112
+ "btcPaid": "0.0000",
113
+ "rate": 395.2,
114
+ "exceptionStatus": false,
115
+ "token": "9kZgUXFb5AC6qMuLaMpP9WopbM8X2UjMhkphKKdaprRbSKgUJNE6JNTX8bGsmgxKKv",
116
+ "buyer": {
117
+ }
118
+ }
119
+ ```
48
120
 
49
121
  There are many options available when creating invoices, which are listed in the [BitPay API documentation](https://bitpay.com/bitcoin-payment-gateway-api).
50
122
 
51
- To get updated information on this invoice, make a get call with the id returned:
123
+ ### Get invoice status
52
124
 
53
- invoice = client.get_public_invoice(id: 'DGrAEmbsXe9bavBPMJ8kuk')
125
+ The ruby library provides two methods for fetching an existing invoice:
126
+
127
+ ```ruby
128
+ # For authorized clients with a 'merchant' token
129
+ client.get_invoice(id: 'PvVhgBfA7wKPWhuVC24rJo')
130
+
131
+ # For non-authenticated clients (public facade)
132
+ # Returns the public subset of invoice fields
133
+ client.get_public_invoice(id: 'PvVhgBfA7wKPWhuVC24rJo')
134
+ ```
135
+
136
+ ### Create a refund request
137
+
138
+ Clients with a `merchant` token can initiate a refund request for a paid invoice:
139
+
140
+ ```ruby
141
+ client.refund_invoice(id: '6pbV13VBZfGFJ8BBmXmLZ8', params: {amount: 10, currency: 'USD'})
142
+ ```
143
+
144
+ Refund rules:
145
+
146
+ * Invoices cannot be refunded prior to 6 blockchain confirmations
147
+ * Invoices without `["flags"]["refundable"] == true` must specify a `bitcoinAddress` param (one was not provided as part of the transaction)
148
+ * Invoices that are paid in full must specify an `amount` and `currency` param to indicate the amount to be refunded
149
+
150
+ ### View Refund Requests
151
+
152
+ The ruby library provides two methods for viewing refund requests. Both require a `merchant` token.
153
+
154
+ ```ruby
155
+ # To get an array of all refunds against a specific invoice
156
+ client.get_all_refunds_for_invoice(id: 'PvVhgBfA7wKPWhuVC24rJo')
157
+
158
+ # To get a specific refund for a specific invoice
159
+ client.get_refund(id: 'JB49z2MsDH7FunczeyDS8j', request_id: '4evCrXq4EDXk4oqDXdWQhX')
160
+ ```
161
+
162
+ ### Make a HTTP request directly against the REST API
163
+
164
+ For API tasks which lack a dedicated library method, BitPay provides a method that will automatically apply the proper cryptographic parameters to a request.
165
+
166
+ ```ruby
167
+ client.send_request("GET", "/invoices/JB49z2MsDH7FunczeyDS8j", facade: 'merchant')
168
+ ```
169
+
170
+ Usage:
171
+ * Specify HTTP verb and REST endpoint
172
+ * Specifying a `facade` will fetch and apply the corresponding `token`
173
+ * Alternatively provide a `token` explicitly
174
+ * For `POST` requests, the `params` hash will be included as the message body
54
175
 
55
176
  ## Testnet Usage
56
177
 
57
178
  During development and testing, take advantage of the [Bitcoin TestNet](https://en.bitcoin.it/wiki/Testnet) by passing a custom `api_uri` option on initialization:
58
179
 
59
- BitPay::Client.new(api_uri: "https://test.bitpay.com/api")
180
+ ```ruby
181
+ BitPay::SDK::Client.new({api_uri: "https://test.bitpay.com/api"})
182
+ ```
183
+
184
+ Note that in order to pair with testnet, you will need a pairing code from test.bitpay.com and will need to use the bitpay client with the --test option.
60
185
 
61
186
  ## API Documentation
62
187
 
@@ -67,10 +192,12 @@ API Documentation is available on the [BitPay site](https://bitpay.com/api).
67
192
  In order to run the tests, you must have phantomjs installed and on your PATH.
68
193
 
69
194
  The tests require that environment variables be set for the bitpay server, user name, and password. First run:
70
-
71
- $ source ./spec/set_constants.sh https://test.bitpay.com <yourusername> <yourpassword>
72
- $ bundle install
73
- $ bundle exec rake
195
+
196
+ ```bash
197
+ $ source ./spec/set_constants.sh https://test.bitpay.com <yourusername> <yourpassword>
198
+ $ bundle install
199
+ $ bundle exec rake
200
+ ```
74
201
 
75
202
  Tests are likely to run up against rate limiters on test.bitpay.com if used too frequently. Rake tasks which interact directly with BitPay will not run for the general public.
76
203
 
data/Rakefile CHANGED
@@ -10,12 +10,19 @@ require_relative 'config/capybara.rb'
10
10
 
11
11
  RSpec::Core::RakeTask.new(:spec)
12
12
 
13
- task :default => :spec
13
+ #task :default => :spec
14
+ task :default => :default_tasks
14
15
 
15
16
  Cucumber::Rake::Task.new(:features) do |t|
16
17
  t.cucumber_opts = "features --format pretty"
17
18
  end
18
19
 
20
+ desc "Run BitPay tests"
21
+ task :default_tasks do
22
+ Rake::Task["spec"].invoke
23
+ Rake::Task["features"].invoke
24
+ end
25
+
19
26
  desc "Bitpay Tasks"
20
27
  namespace :bitpay do
21
28
 
@@ -17,19 +17,19 @@ Gem::Specification.new do |s|
17
17
  s.bindir = 'bin'
18
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
19
 
20
- s.add_dependency 'json', '~> 1.8.1'
21
- s.add_dependency 'rack', '~> 1.5.2'
22
- s.add_dependency 'ecdsa', '~> 1.2.0'
20
+ s.add_dependency 'json', '1.8.1'
21
+ s.add_dependency 'rack', '1.5.2'
22
+ s.add_dependency 'ecdsa', '1.2.0'
23
23
 
24
- s.add_development_dependency 'rake', '~> 10.3.2'
25
- s.add_development_dependency 'webmock', '~> 1.18.0'
26
- s.add_development_dependency 'pry', '~> 0.10.1'
27
- s.add_development_dependency 'pry-byebug', '~> 2.0.0'
28
- s.add_development_dependency 'pry-rescue', '~> 1.4.1'
29
- s.add_development_dependency 'capybara', '~> 2.4.3'
30
- s.add_development_dependency 'cucumber', '~> 1.3.17'
31
- s.add_development_dependency 'poltergeist', '~> 1.5.1'
32
- s.add_development_dependency 'airborne', '~> 0.0.20'
33
- s.add_development_dependency 'rspec', '~> 3.1.0'
34
- s.add_development_dependency 'mongo', '~> 1.11.1'
24
+ s.add_development_dependency 'rake', '10.3.2'
25
+ s.add_development_dependency 'webmock', '1.18.0'
26
+ s.add_development_dependency 'pry', '0.10.1'
27
+ s.add_development_dependency 'pry-byebug', '2.0.0'
28
+ s.add_development_dependency 'pry-rescue', '1.4.1'
29
+ s.add_development_dependency 'capybara', '2.4.3'
30
+ s.add_development_dependency 'cucumber', '1.3.17'
31
+ s.add_development_dependency 'poltergeist', '1.5.1'
32
+ s.add_development_dependency 'airborne', '0.0.20'
33
+ s.add_development_dependency 'rspec', '3.1.0'
34
+ s.add_development_dependency 'mongo', '1.11.1'
35
35
  end
@@ -2,5 +2,5 @@ Capybara.javascript_driver = :poltergeist
2
2
  Capybara.default_driver = :poltergeist
3
3
  Capybara.default_wait_time = 5
4
4
  Capybara.register_driver :poltergeist do |app|
5
- Capybara::Poltergeist::Driver.new(app, js_errors: false, phantomjs_options: ['--ignore-ssl-errors=yes', '--ssl-protocol=TLSv1', '--web-security=false'] )
5
+ Capybara::Poltergeist::Driver.new(app, timeout: 60, js_errors: false, phantomjs_options: ['--ignore-ssl-errors=yes', '--ssl-protocol=TLSv1', '--web-security=false'])
6
6
  end
@@ -1,3 +1,19 @@
1
+ ## Verifies test variables have been set correctly
2
+ #
3
+ # Use 'set_constants.sh' to pre-configure test variables
4
+ # e.g.
5
+ # source ./spec/set_constants.sh https://test.bitpay.com testuser@gmail.com mypassword
6
+ #
7
+
1
8
  ROOT_ADDRESS = ENV['RCROOTADDRESS']
2
9
  TEST_USER = ENV['RCTESTUSER']
3
10
  TEST_PASS = ENV['RCTESTPASSWORD']
11
+ DASHBOARD_URL = "#{ROOT_ADDRESS}/dashboard/merchant/home"
12
+
13
+ unless
14
+ ROOT_ADDRESS &&
15
+ TEST_USER &&
16
+ TEST_PASS
17
+ then
18
+ raise "Missing configuration options - see constants.rb"
19
+ end
@@ -11,16 +11,16 @@ Feature: creating an invoice
11
11
  Then they should recieve an invoice in response for <price> <currency>
12
12
  Examples:
13
13
  | price | currency |
14
- | "500.23" | "USD" |
15
- | "300.21" | "EUR" |
14
+ | "5.23" | "USD" |
15
+ | "10.21" | "EUR" |
16
16
 
17
17
  Scenario Outline: The invoice contains illegal characters
18
18
  When the user creates an invoice for <price> <currency>
19
19
  Then they will receive a BitPay::ArgumentError matching <message>
20
20
  Examples:
21
21
  | price | currency | message |
22
- | "50,023" | "USD" | "Price must be formatted as a float" |
23
- | "300.21" | "EaUR" | "Currency is invalid." |
22
+ | "5,023" | "USD" | "Price must be formatted as a float" |
23
+ | "3.21" | "EaUR" | "Currency is invalid." |
24
24
  | "" | "USD" | "Price must be formatted as a float" |
25
25
  | "Ten" | "USD" | "Price must be formatted as a float" |
26
- | "100" | "" | "Currency is invalid." |
26
+ | "10" | "" | "Currency is invalid." |
@@ -6,13 +6,16 @@ Feature: pairing with bitpay
6
6
  Scenario: the client has a correct pairing code
7
7
  Given the user pairs with BitPay with a valid pairing code
8
8
  Then the user is paired with BitPay
9
+
10
+ Scenario: the client initiates pairing
11
+ Given the user requests a client-side pairing
12
+ Then they will receive a claim code
9
13
 
10
14
  Scenario Outline: the client has a bad pairing code
11
15
  Given the user fails to pair with a semantically <valid> code <code>
12
16
  Then they will receive a <error> matching <message>
13
17
  Examples:
14
18
  | valid | code | error | message |
15
- | valid | "a1b2c3d" | BitPay::BitPayError | "500: Unable to create token" |
16
19
  | invalid | "a1b2c3d4" | BitPay::ArgumentError | "pairing code is not legal" |
17
20
 
18
21
  Scenario: the client has a bad port configuration to a closed port
@@ -1,9 +1,9 @@
1
1
  When(/^the user (?:tries to |)creates? an invoice (?:for|without) "(.*?)" (?:or |and |)"(.*?)"$/) do |price, currency|
2
2
  begin
3
3
  @response = @client.create_invoice(price: price, currency: currency)
4
- rescue => error
5
- @error = error
6
- end
4
+ rescue => error
5
+ @error = error
6
+ end
7
7
  end
8
8
 
9
9
  Then(/^they should recieve an invoice in response for "(.*?)" "(.*?)"$/) do |price, currency|
@@ -15,8 +15,8 @@ Given(/^there is an invalid token$/) do
15
15
  end
16
16
 
17
17
  Given(/^that a user knows an invoice id$/) do
18
- client = new_paired_client
19
- @id = (client.create_invoice(price: 100, currency: "USD" ))['id']
18
+ client = new_client_from_stored_values
19
+ @id = (client.create_invoice(price: 3, currency: "USD" ))['id']
20
20
  end
21
21
 
22
22
  Then(/^they can retrieve that invoice$/) do
@@ -5,6 +5,7 @@ When(/^the user pairs with BitPay(?: with a valid pairing code|)$/) do
5
5
  claim_code = get_claim_code_from_server
6
6
  pem = BitPay::KeyUtils.generate_pem
7
7
  @client = BitPay::SDK::Client.new(api_uri: ROOT_ADDRESS, pem: pem, insecure: true)
8
+ sleep 1 # rate limit compliance
8
9
  @token = @client.pair_pos_client(claim_code)
9
10
  end
10
11
 
@@ -13,6 +14,7 @@ When(/^the fails to pair with BitPay because of an incorrect port$/) do
13
14
  address = ROOT_ADDRESS.split(':').slice(0,2).join(':') + ":999"
14
15
  client = BitPay::SDK::Client.new(api_uri: address, pem: pem, insecure: true)
15
16
  begin
17
+ sleep 1 # rate limit compliance
16
18
  client.pair_pos_client("1ab2c34")
17
19
  raise "pairing unexpectedly worked"
18
20
  rescue => error
@@ -26,9 +28,10 @@ Given(/^the user is authenticated with BitPay$/) do
26
28
  end
27
29
 
28
30
  Given(/^the user is paired with BitPay$/) do
29
- raise "Client is not paired" unless @client.verify_token
31
+ raise "Client is not paired" unless @client.verify_tokens
30
32
  end
31
33
 
34
+
32
35
  Given(/^the user has a bad pairing_code "(.*?)"$/) do |arg1|
33
36
  # This is a no-op, pairing codes are transient and never actually saved
34
37
  end
@@ -37,6 +40,7 @@ Then(/^the user fails to pair with a semantically (?:in|)valid code "(.*?)"$/) d
37
40
  pem = BitPay::KeyUtils.generate_pem
38
41
  client = BitPay::SDK::Client.new(api_uri: ROOT_ADDRESS, pem: pem, insecure: true)
39
42
  begin
43
+ sleep 1 # rate limit compliance
40
44
  client.pair_pos_client(code)
41
45
  raise "pairing unexpectedly worked"
42
46
  rescue => error
@@ -49,3 +53,13 @@ Then(/^they will receive an? (.*?) matching "(.*?)"$/) do |error_class, error_me
49
53
  raise "Error: #{@error.class}, message: #{@error.message}" unless Object.const_get(error_class) == @error.class && @error.message.include?(error_message)
50
54
  end
51
55
 
56
+ Given(/^the user requests a client\-side pairing$/) do
57
+ sleep 1
58
+ pem = BitPay::KeyUtils.generate_pem
59
+ client = BitPay::SDK::Client.new(api_uri: ROOT_ADDRESS, pem: pem, insecure: true)
60
+ @response = client.pair_client({})
61
+ end
62
+
63
+ Then(/^they will receive a claim code$/) do
64
+ expect(@response["data"].first["pairingCode"] ).not_to be_empty
65
+ end