diff --git a/.travis.yml b/.travis.yml index 0abd842e..0e4fd9d9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,10 @@ --- language: python -dist: xenial # required for Python >= 3.7 (travis-ci/travis-ci#9069) python: - - 3.5 - - 3.6 - 3.7 - # Python nightly currently disabled because of: - # curl: (56) Recv failure: Connection reset by peer + - 3.8 + - 3.9-dev + # Python nightly currently disabled because of compilation issues # - nightly install: - pip install flake8 flake8-import-order doc8 Pygments diff --git a/localstripe/__init__.py b/localstripe/__init__.py index 62fc2575..3501fb72 100644 --- a/localstripe/__init__.py +++ b/localstripe/__init__.py @@ -21,4 +21,4 @@ raise RuntimeError('Please run with Python >= 3.5') __author__ = 'Adrien Vergé' -__version__ = '1.12.4' +__version__ = '1.12.7' diff --git a/localstripe/resources.py b/localstripe/resources.py index c3553da1..b5175534 100644 --- a/localstripe/resources.py +++ b/localstripe/resources.py @@ -139,7 +139,7 @@ def _api_create(cls, **data): @classmethod def _api_retrieve(cls, id): - obj = store.get(cls.object + ':' + id, None) + obj = store.get(cls.object + ':' + id) if obj is None: raise UserError(404, 'Not Found') @@ -161,11 +161,11 @@ def _api_delete(cls, id): return {"deleted": True, "id": id} @classmethod - def _api_list_all(cls, url, limit=None, **kwargs): + def _api_list_all(cls, url, limit=None, starting_after=None, **kwargs): if kwargs: raise UserError(400, 'Unexpected ' + ', '.join(kwargs.keys())) - li = List(url, limit=limit) + li = List(url, limit=limit, starting_after=starting_after) li._list = [value for key, value in store.items() if key.startswith(cls.object + ':')] return li @@ -244,6 +244,53 @@ def do_expand(path, obj): return obj +class Balance(object): + object = 'balance' + + def __init__(self): + self.livemode = False + self.available = { + 'amount': 2000, + 'currency': 'eur', + 'source_types': { + 'card': 2000 + } + } + self.pending = { + 'amount': 0, + 'currency': 'eur', + 'source_types': { + 'card': 0 + } + } + + store[self.object] = self + + schedule_webhook(Event('balance.available', self)) + + @classmethod + def _api_retrieve(self): + obj = store.get(self.object) + if obj is None: + return self() + return obj + + def _export(self, expand=None): + obj = {} + + for key, value in vars(self).items(): + if not key.startswith('_'): + if isinstance(value, dict): + obj[key] = value.copy() + else: + obj[key] = value + + return obj + + +extra_apis.append(('GET', '/v1/balance', Balance._api_retrieve)) + + class Card(StripeObject): object = 'card' _id_prefix = 'card_' @@ -254,18 +301,18 @@ def __init__(self, source=None, **kwargs): try: assert type(source) is dict - assert source.get('object', None) == 'card' - number = source.get('number', None) - exp_month = try_convert_to_int(source.get('exp_month', None)) - exp_year = try_convert_to_int(source.get('exp_year', None)) - cvc = source.get('cvc', None) - address_city = source.get('address_city', None) - address_country = source.get('address_country', None) - address_line1 = source.get('address_line1', None) - address_line2 = source.get('address_line2', None) - address_state = source.get('address_state', None) - address_zip = source.get('address_zip', None) - name = source.get('name', None) + assert source.get('object') == 'card' + number = source.get('number') + exp_month = try_convert_to_int(source.get('exp_month')) + exp_year = try_convert_to_int(source.get('exp_year')) + cvc = source.get('cvc') + address_city = source.get('address_city') + address_country = source.get('address_country') + address_line1 = source.get('address_line1') + address_line2 = source.get('address_line2') + address_state = source.get('address_state') + address_zip = source.get('address_zip') + name = source.get('name') assert type(number) is str and len(number) == 16 assert type(exp_month) is int assert exp_month >= 1 and exp_month <= 12 @@ -475,6 +522,40 @@ def amount_refunded(self): def refunded(self): return self.amount <= self.amount_refunded + @classmethod + def _api_list_all(cls, url, customer=None, created=None, limit=10, + starting_after=None): + try: + if customer is not None: + assert type(customer) is str and customer.startswith('cus_') + if created is not None: + assert type(created) in (dict, str) + if type(created) is dict: + assert len(created.keys()) == 1 and \ + list(created.keys())[0] in ('gt', 'gte', 'lt', 'lte') + date = try_convert_to_int(list(created.values())[0]) + elif type(created) is str: + date = try_convert_to_int(created) + assert type(date) is int and date > 1500000000 + except AssertionError: + raise UserError(400, 'Bad request') + + if customer: + Customer._api_retrieve(customer) # to return 404 if not existant + + if created: + if type(created) is str or not created.get('gt'): + raise UserError(500, 'Not implemented') + + li = super(Charge, cls)._api_list_all(url, limit=limit, + starting_after=starting_after) + if customer: + li._list = [c for c in li._list if c.customer == customer] + if created and created.get('gt'): + li._list = [c for c in li._list + if c.created > try_convert_to_int(created['gt'])] + return li + extra_apis.append(( ('POST', '/v1/charges/{id}/capture', Charge._api_capture))) @@ -490,7 +571,7 @@ def __init__(self, id=None, duration=None, amount_off=None, raise UserError(400, 'Unexpected ' + ', '.join(kwargs.keys())) amount_off = try_convert_to_int(amount_off) - percent_off = try_convert_to_int(percent_off) + percent_off = try_convert_to_float(percent_off) duration_in_months = try_convert_to_int(duration_in_months) try: assert type(id) is str and id @@ -498,7 +579,7 @@ def __init__(self, id=None, duration=None, amount_off=None, if amount_off is not None: assert type(amount_off) is int and amount_off >= 0 if percent_off is not None: - assert type(percent_off) is int + assert type(percent_off) is float assert percent_off >= 0 and percent_off <= 100 assert duration in ('forever', 'once', 'repeating') if amount_off is not None: @@ -564,7 +645,7 @@ def __init__(self, name=None, description=None, email=None, assert type(business_vat_id) is str if preferred_locales is not None: assert type(preferred_locales) is list - assert all(type(l) is str for l in preferred_locales) + assert all(type(lo) is str for lo in preferred_locales) if tax_id_data is None: tax_id_data = [] assert type(tax_id_data) is list @@ -895,6 +976,7 @@ def __init__(self, customer=None, subscription=None, metadata=None, self.application_fee = None self.attempt_count = 1 self.attempted = True + self.billing_reason = None self.description = description self.discount = None self.ending_balance = 0 @@ -932,6 +1014,9 @@ def __init__(self, customer=None, subscription=None, metadata=None, else: self.currency = 'eur' # arbitrary default + if subscription is not None and subscription_obj.status == "trialing": + self.lines = List() + self._draft = True self._voided = False @@ -1063,8 +1148,8 @@ def _get_next_invoice(cls, customer=None, subscription=None, if subscription_items is not None: assert type(subscription_items) is list for si in subscription_items: - assert type(si.get('plan', None)) is str - si['tax_rates'] = si.get('tax_rates', None) + assert type(si.get('plan')) is str + si['tax_rates'] = si.get('tax_rates') if si['tax_rates'] is not None: assert type(si['tax_rates']) is list assert all(type(tr) is str for tr in si['tax_rates']) @@ -1221,7 +1306,8 @@ def _api_delete(cls, id): return super()._api_delete(id) @classmethod - def _api_list_all(cls, url, customer=None, subscription=None, limit=None): + def _api_list_all(cls, url, customer=None, subscription=None, limit=None, + starting_after=None): try: if customer is not None: assert type(customer) is str and customer.startswith('cus_') @@ -1231,7 +1317,8 @@ def _api_list_all(cls, url, customer=None, subscription=None, limit=None): except AssertionError: raise UserError(400, 'Bad request') - li = super(Invoice, cls)._api_list_all(url, limit=limit) + li = super(Invoice, cls)._api_list_all(url, limit=limit, + starting_after=starting_after) if customer is not None: Customer._api_retrieve(customer) # to return 404 if not existant li._list = [i for i in li._list if i.customer == customer] @@ -1402,14 +1489,17 @@ def __init__(self, invoice=None, subscription=None, plan=None, amount=None, self.metadata = metadata or {} @classmethod - def _api_list_all(cls, url, customer=None, limit=None): + def _api_list_all(cls, url, customer=None, limit=None, + starting_after=None): try: if customer is not None: assert type(customer) is str and customer.startswith('cus_') except AssertionError: raise UserError(400, 'Bad request') - li = super(InvoiceItem, cls)._api_list_all(url, limit=limit) + li = super(InvoiceItem, + cls)._api_list_all(url, limit=limit, + starting_after=starting_after) li._list = [ii for ii in li._list if ii.invoice is None] if customer is not None: Customer._api_retrieve(customer) # to return 404 if not existant @@ -1480,11 +1570,13 @@ def _api_delete(cls, id): class List(StripeObject): object = 'list' - def __init__(self, url=None, limit=None): + def __init__(self, url=None, limit=None, starting_after=None): limit = try_convert_to_int(limit) limit = 10 if limit is None else limit try: assert type(limit) is int and limit > 0 + if starting_after is not None: + assert type(starting_after) is str and len(starting_after) > 0 except AssertionError: raise UserError(400, 'Bad request') @@ -1494,11 +1586,16 @@ def __init__(self, url=None, limit=None): self.url = url self._limit = limit + self._starting_after = starting_after + self._starting_pos = None self._list = [] @property def data(self): - return [item._export() for item in self._list][:self._limit] + self._compute_starting_pos() + return [item._export() for item in self._list[ + self._starting_pos:self._starting_pos + self._limit + ]] @property def total_count(self): @@ -1506,7 +1603,21 @@ def total_count(self): @property def has_more(self): - return len(self._list) > self._limit + self._compute_starting_pos() + return len(self._list) > self._limit + self._starting_pos + + def _compute_starting_pos(self): + if self._starting_pos is not None: + return + + self._starting_pos = 0 + if self._starting_after is None: + return + + for i, item in enumerate(self._list): + if getattr(item, 'id', None) == self._starting_after: + self._starting_pos = i + 1 + break class PaymentIntent(StripeObject): @@ -1878,7 +1989,8 @@ def _api_retrieve(cls, id): return super()._api_retrieve(id) @classmethod - def _api_list_all(cls, url, customer=None, type=None, limit=None): + def _api_list_all(cls, url, customer=None, type=None, limit=None, + starting_after=None): try: assert _type(customer) is str and customer.startswith('cus_') assert type in ('card', ) @@ -1887,7 +1999,9 @@ def _api_list_all(cls, url, customer=None, type=None, limit=None): Customer._api_retrieve(customer) # to return 404 if not existant - li = super(PaymentMethod, cls)._api_list_all(url, limit=limit) + li = super(PaymentMethod, + cls)._api_list_all(url, limit=limit, + starting_after=starting_after) li._list = [pm for pm in li._list if pm.customer == customer and pm.type == type] return li @@ -1990,7 +2104,7 @@ class Product(StripeObject): object = 'product' _id_prefix = 'prod_' - def __init__(self, id=None, name=None, type=None, active=True, + def __init__(self, id=None, name=None, type='service', active=True, caption=None, description=None, attributes=None, shippable=True, url=None, statement_descriptor=None, metadata=None, **kwargs): @@ -2067,14 +2181,15 @@ def __init__(self, charge=None, amount=None, metadata=None, **kwargs): self.amount = charge_obj.amount @classmethod - def _api_list_all(cls, url, charge=None, limit=None): + def _api_list_all(cls, url, charge=None, limit=None, starting_after=None): try: if charge is not None: assert type(charge) is str and charge.startswith('ch_') except AssertionError: raise UserError(400, 'Bad request') - li = super(Refund, cls)._api_list_all(url, limit=limit) + li = super(Refund, cls)._api_list_all(url, limit=limit, + starting_after=starting_after) if charge is not None: Charge._api_retrieve(charge) # to return 404 if not existant li._list = [r for r in li._list if r.charge == charge] @@ -2318,17 +2433,20 @@ def __init__(self, customer=None, metadata=None, items=None, assert proration_behavior in ['create_prorations', 'none'] assert type(items) is list for item in items: - assert type(item.get('plan', None)) is str - if item.get('quantity', None) is not None: + assert type(item.get('plan')) is str + if item.get('quantity') is not None: item['quantity'] = try_convert_to_int(item['quantity']) assert type(item['quantity']) is int assert item['quantity'] > 0 else: item['quantity'] = 1 - item['tax_rates'] = item.get('tax_rates', None) + item['tax_rates'] = item.get('tax_rates') if item['tax_rates'] is not None: assert type(item['tax_rates']) is list assert all(type(tr) is str for tr in item['tax_rates']) + item['metadata'] = item.get('metadata') + if item['metadata'] is not None: + assert type(item['metadata']) is dict assert type(enable_incomplete_payments) is bool assert payment_behavior in ('allow_incomplete', 'error_if_incomplete') @@ -2380,12 +2498,18 @@ def __init__(self, customer=None, metadata=None, items=None, subscription=self.id, plan=items[0]['plan'], quantity=items[0]['quantity'], + metadata=items[0]['metadata'], tax_rates=items[0]['tax_rates'])) - create_an_invoice = \ - self.trial_end is None and self.trial_period_days is None - if create_an_invoice: - self._create_invoice() + is_trial = \ + self.trial_end is not None and self.trial_end >= int(time.time()) + + if is_trial: + self.trial_start = int(time.time()) + self.status = 'trialing' + + # if subscription is in trial, a 0 € should still be created + self._create_invoice() schedule_webhook(Event('customer.subscription.created', self)) @@ -2424,6 +2548,9 @@ def _create_invoice(self): if invoice.status == 'paid': self.status = 'active' + + if self.trial_end is not None and self.trial_end >= int(time.time()): + self.status = 'trialing' elif invoice.charge: if invoice.charge.status == 'failed': if self.status != 'incomplete': @@ -2511,19 +2638,22 @@ def _update(self, metadata=None, items=None, trial_end=None, if items is not None: assert type(items) is list for item in items: - id = item.get('id', None) + id = item.get('id') if id is not None: assert type(id) is str and id.startswith('si_') - if item.get('quantity', None) is not None: + if item.get('quantity') is not None: item['quantity'] = try_convert_to_int(item['quantity']) assert type(item['quantity']) is int assert item['quantity'] > 0 else: item['quantity'] = 1 - item['tax_rates'] = item.get('tax_rates', None) + item['tax_rates'] = item.get('tax_rates') if item['tax_rates'] is not None: assert type(item['tax_rates']) is list assert all(type(tr) is str for tr in item['tax_rates']) + item['metadata'] = item.get('metadata') + if item['metadata'] is not None: + assert type(item['metadata']) is dict except AssertionError: raise UserError(400, 'Bad request') @@ -2534,7 +2664,7 @@ def _update(self, metadata=None, items=None, trial_end=None, # If no plan specified in update request, we stay on the current # one - if not items[0].get('plan', None): + if not items[0].get('plan'): items[0]['plan'] = self.plan.id # To return 404 if not existant: @@ -2553,6 +2683,7 @@ def _update(self, metadata=None, items=None, trial_end=None, item = SubscriptionItem(subscription=self.id, plan=items[0]['plan'], quantity=items[0]['quantity'], + metadata=items[0]['metadata'], tax_rates=items[0]['tax_rates']) self.items._list.append(item) @@ -2592,6 +2723,8 @@ def _update(self, metadata=None, items=None, trial_end=None, if trial_end is not None: self.trial_end = trial_end + if trial_end > int(time.time()): + self.status = "trialing" if cancel_at_period_end is not None: self.cancel_at_period_end = cancel_at_period_end @@ -2617,7 +2750,8 @@ def _api_delete(cls, id): return obj @classmethod - def _api_list_all(cls, url, customer=None, status=None, limit=None): + def _api_list_all(cls, url, customer=None, status=None, limit=None, + starting_after=None): try: if customer is not None: assert type(customer) is str and customer.startswith('cus_') @@ -2628,7 +2762,9 @@ def _api_list_all(cls, url, customer=None, status=None, limit=None): except AssertionError: raise UserError(400, 'Bad request') - li = super(Subscription, cls)._api_list_all(url, limit=limit) + li = super(Subscription, + cls)._api_list_all(url, limit=limit, + starting_after=starting_after) if status is None: li._list = [sub for sub in li._list if sub.status not in ('canceled', 'incomplete_expired')] diff --git a/test.sh b/test.sh index c8457d54..4029d494 100755 --- a/test.sh +++ b/test.sh @@ -6,19 +6,19 @@ set -eux HOST=http://localhost:8420 SK=sk_test_12345 -cus=$(curl -sSf -u $SK: $HOST/v1/customers \ +cus=$(curl -sSfg -u $SK: $HOST/v1/customers \ -d email=james.robinson@example.com \ | grep -oE 'cus_\w+' | head -n 1) -curl -sSf -u $SK: $HOST/v1/customers/$cus \ +curl -sSfg -u $SK: $HOST/v1/customers/$cus \ -d description='Adding a description...' -curl -sSf -u $SK: $HOST/v1/customers/$cus \ +curl -sSfg -u $SK: $HOST/v1/customers/$cus \ -d preferred_locales[]='fr-FR' -d preferred_locales[]='es-ES' -curl -sSf -u $SK: -X DELETE $HOST/v1/customers/$cus +curl -sSfg -u $SK: -X DELETE $HOST/v1/customers/$cus -cus=$(curl -sSf -u $SK: $HOST/v1/customers \ +cus=$(curl -sSfg -u $SK: $HOST/v1/customers \ -d description='This customer is a company' \ -d email=foo@bar.com \ -d phone=0102030405 \ @@ -27,19 +27,19 @@ cus=$(curl -sSf -u $SK: $HOST/v1/customers \ -d tax_id_data[0][type]=eu_vat -d tax_id_data[0][value]=FR12345678901 \ | grep -oE 'cus_\w+' | head -n 1) -curl -sSf -u $SK: $HOST/v1/customers/$cus/tax_ids \ +curl -sSfg -u $SK: $HOST/v1/customers/$cus/tax_ids \ -d type=eu_vat -d value=DE123456789 \ -d expand[]=customer -curl -sSf -u $SK: $HOST/v1/customers/$cus?expand%5B%5D=tax_ids.data.customer +curl -sSfg -u $SK: $HOST/v1/customers/$cus?expand[]=tax_ids.data.customer -curl -sSf -u $SK: $HOST/v1/customers/$cus?expand%5B%5D=subscriptions.data.items.data +curl -sSfg -u $SK: $HOST/v1/customers/$cus?expand[]=subscriptions.data.items.data -code=$(curl -so /dev/null -w '%{http_code}' -u $SK: \ - $HOST/v1/customers/$cus?expand%5B%5D=subscriptions.data.items.data.tax_ids) +code=$(curl -sg -o /dev/null -w '%{http_code}' -u $SK: \ + $HOST/v1/customers/$cus?expand[]=subscriptions.data.items.data.tax_ids) [ "$code" -eq 400 ] -txr1=$(curl -sSf -u $SK: $HOST/v1/tax_rates \ +txr1=$(curl -sSfg -u $SK: $HOST/v1/tax_rates \ -d display_name=VAT \ -d description='TVA France taux normal' \ -d jurisdiction=FR \ @@ -47,7 +47,7 @@ txr1=$(curl -sSf -u $SK: $HOST/v1/tax_rates \ -d inclusive=false \ | grep -oE 'txr_\w+' | head -n 1) -txr2=$(curl -sSf -u $SK: $HOST/v1/tax_rates \ +txr2=$(curl -sSfg -u $SK: $HOST/v1/tax_rates \ -d display_name=VAT \ -d description='TVA France taux réduit' \ -d jurisdiction=FR \ @@ -55,21 +55,21 @@ txr2=$(curl -sSf -u $SK: $HOST/v1/tax_rates \ -d inclusive=false \ | grep -oE 'txr_\w+' | head -n 1) -curl -sSf -u $SK: $HOST/v1/plans \ +curl -sSfg -u $SK: $HOST/v1/plans \ -d id=basique-mensuel \ -d product[name]='Abonnement basique (mensuel)' \ -d amount=2500 \ -d currency=eur \ -d interval=month -curl -sSf -u $SK: $HOST/v1/plans \ +curl -sSfg -u $SK: $HOST/v1/plans \ -d id=basique-annuel \ -d name='Abonnement basique (annuel)' \ -d amount=20000 \ -d currency=eur \ -d interval=year -curl -sSf -u $SK: $HOST/v1/plans \ +curl -sSfg -u $SK: $HOST/v1/plans \ -d id=annual-tiered-volume \ -d name='Annual tiered volume' \ -d currency=eur \ @@ -85,7 +85,7 @@ curl -sSf -u $SK: $HOST/v1/plans \ -d tiers[1][unit_amount]=1000 \ -d tiers[1][flat_amount]=1200 -curl -sSf -u $SK: $HOST/v1/plans \ +curl -sSfg -u $SK: $HOST/v1/plans \ -d id=monthly-tiered-graduated \ -d name='Monthly tiered graduated' \ -d currency=eur \ @@ -101,7 +101,7 @@ curl -sSf -u $SK: $HOST/v1/plans \ -d tiers[1][unit_amount]=1000 \ -d tiers[1][flat_amount]=1200 -curl -sSf -u $SK: $HOST/v1/plans \ +curl -sSfg -u $SK: $HOST/v1/plans \ -d id=pro-annuel \ -d product[name]='Abonnement PRO (annuel)' \ -d product[statement_descriptor]='abonnement pro' \ @@ -109,57 +109,57 @@ curl -sSf -u $SK: $HOST/v1/plans \ -d currency=eur \ -d interval=year -curl -sSf -u $SK: $HOST/v1/plans \ +curl -sSfg -u $SK: $HOST/v1/plans \ -d product[name]='Without id' \ -d product[statement_descriptor]='Without id' \ -d amount=30000 \ -d currency=eur \ -d interval=year -curl -sSf -u $SK: $HOST/v1/plans \ +curl -sSfg -u $SK: $HOST/v1/plans \ -d id=delete-me \ -d product[name]='Delete me' \ -d amount=30000 \ -d currency=eur \ -d interval=year -curl -sSf -u $SK: -X DELETE $HOST/v1/plans/delete-me +curl -sSfg -u $SK: -X DELETE $HOST/v1/plans/delete-me -code=$(curl -so /dev/null -w '%{http_code}' -u $SK: $HOST/v1/plans \ +code=$(curl -sg -o /dev/null -w '%{http_code}' -u $SK: $HOST/v1/plans \ -d doesnotexist=1) [ "$code" -eq 400 ] -code=$(curl -so /dev/null -w '%{http_code}' -u $SK: \ +code=$(curl -sg -o /dev/null -w '%{http_code}' -u $SK: \ $HOST/v1/plans?doesnotexist=1) [ "$code" -eq 400 ] -curl -sSf -u $SK: $HOST/v1/products \ +curl -sSfg -u $SK: $HOST/v1/products \ -d name=T-shirt \ -d type=good \ -d description='Comfortable cotton t-shirt' \ -d attributes[]=size \ -d attributes[]=gender -curl -sSf -u $SK: $HOST/v1/products \ +curl -sSfg -u $SK: $HOST/v1/products \ -d id=PRODUCT1234 \ -d name='Product 1234' \ -d type=service -curl -sSf -u $SK: $HOST/v1/products/PRODUCT1234 +curl -sSfg -u $SK: $HOST/v1/products/PRODUCT1234 -curl -sSf -u $SK: $HOST/v1/plans?expand%5B%5D=data.product +curl -sSfg -u $SK: $HOST/v1/plans?expand[]=data.product -code=$(curl -so /dev/null -w '%{http_code}' -u $SK: \ - $HOST/v1/plans?expand%5B%5D=data.doesnotexist) +code=$(curl -sg -o /dev/null -w '%{http_code}' -u $SK: \ + $HOST/v1/plans?expand[]=data.doesnotexist) [ "$code" -eq 400 ] -curl -sSf -u $SK: $HOST/v1/coupons \ +curl -sSfg -u $SK: $HOST/v1/coupons \ -d id=PARRAIN \ -d percent_off=30 \ -d duration=once # This is what a Stripe.js request does: -tok=$(curl -sSf $HOST/v1/tokens \ +tok=$(curl -sSfg $HOST/v1/tokens \ -d key=pk_test_sldkjflaksdfj \ -d card[number]=4242424242424242 \ -d card[exp_month]=12 \ @@ -167,23 +167,23 @@ tok=$(curl -sSf $HOST/v1/tokens \ -d card[cvc]=123 \ | grep -oE 'tok_\w+') -curl -sSf -u $SK: $HOST/v1/customers/$cus/sources \ +curl -sSfg -u $SK: $HOST/v1/customers/$cus/sources \ -d source=$tok # This is what a request from back-end does: -tok=$(curl -sSf -u $SK: $HOST/v1/tokens \ +tok=$(curl -sSfg -u $SK: $HOST/v1/tokens \ -d card[number]=4242424242424242 \ -d card[exp_month]=12 \ -d card[exp_year]=2019 \ -d card[cvc]=123 \ | grep -oE 'tok_\w+') -curl -sSf -u $SK: $HOST/v1/customers/$cus/sources \ +curl -sSfg -u $SK: $HOST/v1/customers/$cus/sources \ -d source=$tok # add a new card card=$( - curl -sSf -u $SK: $HOST/v1/customers/$cus/cards \ + curl -sSfg -u $SK: $HOST/v1/customers/$cus/cards \ -d source[object]=card \ -d source[number]=4242424242424242 \ -d source[exp_month]=12 \ @@ -193,23 +193,23 @@ card=$( # observe new card in customer response res=$( - curl -sSf -u $SK: $HOST/v1/customers/$cus \ + curl -sSfg -u $SK: $HOST/v1/customers/$cus \ | grep -oE $card) [ -n "$res" ] # delete the card -curl -sSf -u $SK: $HOST/v1/customers/$cus/sources/$card \ +curl -sSfg -u $SK: $HOST/v1/customers/$cus/sources/$card \ -X DELETE # observe card no longer in customer response res=$( - curl -sSf -u $SK: $HOST/v1/customers/$cus \ + curl -sSfg -u $SK: $HOST/v1/customers/$cus \ | grep -oE $card || true) [ -z "$res" ] # add a new card card=$( - curl -sSf -u $SK: $HOST/v1/customers/$cus/cards \ + curl -sSfg -u $SK: $HOST/v1/customers/$cus/cards \ -d source[object]=card \ -d source[number]=4242424242424242 \ -d source[exp_month]=12 \ @@ -220,21 +220,21 @@ card=$( # observe name on card name=$( - curl -sSf -u $SK: $HOST/v1/customers/$cus/sources/$card \ + curl -sSfg -u $SK: $HOST/v1/customers/$cus/sources/$card \ | grep -oE '"name": "John Smith",') [ -n "$name" ] # update name on card -curl -sSf -u $SK: $HOST/v1/customers/$cus/sources/$card \ +curl -sSfg -u $SK: $HOST/v1/customers/$cus/sources/$card \ -d name=Jane\ Doe # observe name on card name=$( - curl -sSf -u $SK: $HOST/v1/customers/$cus/sources/$card \ + curl -sSfg -u $SK: $HOST/v1/customers/$cus/sources/$card \ | grep -oE '"name": "Jane Doe",') [ -n "$name" ] -card=$(curl -sSf -u $SK: $HOST/v1/customers/$cus/cards \ +card=$(curl -sSfg -u $SK: $HOST/v1/customers/$cus/cards \ -d source[object]=card \ -d source[number]=4242424242424242 \ -d source[exp_month]=12 \ @@ -242,7 +242,7 @@ card=$(curl -sSf -u $SK: $HOST/v1/customers/$cus/cards \ -d source[cvc]=123 \ | grep -oE 'card_\w+') -code=$(curl -s -o /dev/null -w "%{http_code}" -u $SK: \ +code=$(curl -sg -o /dev/null -w "%{http_code}" -u $SK: \ $HOST/v1/customers/$cus/cards \ -d source[object]=card \ -d source[number]=4000000000000002 \ @@ -253,7 +253,7 @@ code=$(curl -s -o /dev/null -w "%{http_code}" -u $SK: \ # new charges are captured by default captured=$( - curl -sSf -u $SK: $HOST/v1/charges \ + curl -sSfg -u $SK: $HOST/v1/charges \ -d customer=$cus \ -d source=$card \ -d amount=1000 \ @@ -263,7 +263,7 @@ captured=$( # create a pre-auth charge charge=$( - curl -sSf -u $SK: $HOST/v1/charges \ + curl -sSfg -u $SK: $HOST/v1/charges \ -d customer=$cus \ -d source=$card \ -d amount=1000 \ @@ -273,33 +273,33 @@ charge=$( # charge was not captured captured=$( - curl -sSf -u $SK: $HOST/v1/charges/$charge \ + curl -sSfg -u $SK: $HOST/v1/charges/$charge \ | grep -oE '"captured": false,') [ -n "$captured" ] # cannot capture more than pre-authed amount code=$( - curl -s -o /dev/null -w "%{http_code}" \ + curl -sg -o /dev/null -w "%{http_code}" \ -u $SK: $HOST/v1/charges/$charge/capture \ -d amount=2000) [ "$code" = 400 ] # can capture less than the pre-auth amount captured=$( - curl -sSf -u $SK: $HOST/v1/charges/$charge/capture \ + curl -sSfg -u $SK: $HOST/v1/charges/$charge/capture \ -d amount=800 \ | grep -oE '"captured": true,') [ -n "$captured" ] # difference between pre-auth and capture is refunded refunded=$( - curl -sSf -u $SK: $HOST/v1/charges/$charge \ + curl -sSfg -u $SK: $HOST/v1/charges/$charge \ | grep -oE '"amount_refunded": 200,') [ -n "$captured" ] # create a pre-auth charge charge=$( - curl -sSf -u $SK: $HOST/v1/charges \ + curl -sSfg -u $SK: $HOST/v1/charges \ -d customer=$cus \ -d source=$card \ -d amount=1000 \ @@ -309,195 +309,195 @@ charge=$( # capture the full amount (default) captured=$( - curl -sSf -u $SK: $HOST/v1/charges/$charge/capture \ + curl -sSfg -u $SK: $HOST/v1/charges/$charge/capture \ -X POST \ | grep -oE '"captured": true,') [ -n "$captured" ] # none is refunded refunded=$( - curl -sSf -u $SK: $HOST/v1/charges/$charge \ + curl -sSfg -u $SK: $HOST/v1/charges/$charge \ | grep -oE '"amount_refunded": 0,') [ -n "$captured" ] # cannot capture an already captured charge code=$( - curl -s -o /dev/null -w "%{http_code}" \ + curl -sg -o /dev/null -w "%{http_code}" \ -u $SK: $HOST/v1/charges/$charge/capture \ -X POST) [ "$code" = 400 ] sepa_cus=$( - curl -sSf -u $SK: $HOST/v1/customers \ + curl -sSfg -u $SK: $HOST/v1/customers \ -d description='I pay with SEPA debit' \ -d email=sepa@euro.fr \ | grep -oE 'cus_\w+' | head -n 1) -src=$(curl -sSf -u $SK: $HOST/v1/sources \ +src=$(curl -sSfg -u $SK: $HOST/v1/sources \ -d type=ach_credit_transfer \ -d currency=usd \ -d owner[email]='jenny.rosen@example.com' \ | grep -oE 'src_\w+') -curl -sSf -u $SK: $HOST/v1/customers/$sepa_cus/sources \ +curl -sSfg -u $SK: $HOST/v1/customers/$sepa_cus/sources \ -d source=$src # This is what a Stripe.js request does: -src=$(curl -sSf -u $SK: $HOST/v1/sources \ +src=$(curl -sSfg -u $SK: $HOST/v1/sources \ -d type=sepa_debit \ -d sepa_debit[iban]=DE89370400440532013000 \ -d currency=eur \ -d owner[name]='Jenny Rosen' \ | grep -oE 'src_\w+') -curl -sSf -u $SK: $HOST/v1/customers/$sepa_cus/sources \ +curl -sSfg -u $SK: $HOST/v1/customers/$sepa_cus/sources \ -d source=$src # Get a customer source directly: -curl -sSf -u $SK: $HOST/v1/customers/$sepa_cus/sources/$src -code=$(curl -s -o /dev/null -w "%{http_code}" -u $SK: \ +curl -sSfg -u $SK: $HOST/v1/customers/$sepa_cus/sources/$src +code=$(curl -sg -o /dev/null -w "%{http_code}" -u $SK: \ $HOST/v1/customers/cus_doesnotexist/sources/$src) [ "$code" = 404 ] -code=$(curl -s -o /dev/null -w "%{http_code}" -u $SK: \ +code=$(curl -sg -o /dev/null -w "%{http_code}" -u $SK: \ $HOST/v1/customers/$sepa_cus/sources/src_doesnotexist) [ "$code" = 404 ] -tok=$(curl -sSf -u $SK: $HOST/v1/tokens \ +tok=$(curl -sSfg -u $SK: $HOST/v1/tokens \ -d card[number]=4242424242424242 \ -d card[exp_month]=12 \ -d card[exp_year]=2020 \ -d card[cvc]=123 \ | grep -oE 'tok_\w+') -curl -sSf -u $SK: $HOST/v1/customers \ +curl -sSfg -u $SK: $HOST/v1/customers \ -d description='Customer with already existing source' \ -d source=$tok # For a customer with no source, `default_source` should be `null`: -cus=$(curl -sSf -u $SK: $HOST/v1/customers -d email=joe.malvic@example.com \ +cus=$(curl -sSfg -u $SK: $HOST/v1/customers -d email=joe.malvic@example.com \ | grep -oE 'cus_\w+' | head -n 1) -ds=$(curl -sSf -u $SK: $HOST/v1/customers/$cus?expand%5B%5D=default_source \ +ds=$(curl -sSfg -u $SK: $HOST/v1/customers/$cus?expand[]=default_source \ | grep -oE '"default_source": \w+,') [ "$ds" = '"default_source": null,' ] -curl -sSf -u $SK: $HOST/v1/customers/$cus/cards \ +curl -sSfg -u $SK: $HOST/v1/customers/$cus/cards \ -d source[object]=card \ -d source[number]=4242424242424242 \ -d source[exp_month]=12 \ -d source[exp_year]=2020 \ -d source[cvc]=123 -ds=$(curl -sSf -u $SK: $HOST/v1/customers/$cus?expand%5B%5D=default_source \ +ds=$(curl -sSfg -u $SK: $HOST/v1/customers/$cus?expand[]=default_source \ | grep -oE '"default_source": null",' || true) [ -z "$ds" ] # we can charge a customer without specifying the source -curl -sSf -u $SK: $HOST/v1/charges \ +curl -sSfg -u $SK: $HOST/v1/charges \ -d customer=$cus \ -d amount=1000 \ -d currency=usd -curl -sSf -u $SK: $HOST/v1/invoices?customer=$cus +curl -sSfg -u $SK: $HOST/v1/invoices?customer=$cus -code=$(curl -s -o /dev/null -w "%{http_code}" -u $SK: \ +code=$(curl -sg -o /dev/null -w "%{http_code}" -u $SK: \ $HOST/v1/invoices/upcoming?customer=$cus) [ "$code" = 404 ] -curl -sSf -u $SK: $HOST/v1/subscriptions \ +curl -sSfg -u $SK: $HOST/v1/subscriptions \ -d customer=$cus \ -d items[0][plan]=basique-mensuel \ -d expand[]=latest_invoice.payment_intent -res=$(curl -sSf -u $SK: $HOST/v1/subscriptions \ +res=$(curl -sSfg -u $SK: $HOST/v1/subscriptions \ -d customer=$cus \ -d items[0][plan]=basique-mensuel \ -d items[0][tax_rates][0]=$txr1) sub=$(echo "$res" | grep -oE 'sub_\w+' | head -n 1) in=$(echo "$res" | grep -oE 'in_\w+' | head -n 1) -curl -sSf -u $SK: $HOST/v1/invoices?customer=$cus +curl -sSfg -u $SK: $HOST/v1/invoices?customer=$cus -curl -sSf -u $SK: $HOST/v1/invoices/upcoming?customer=$cus +curl -sSfg -u $SK: $HOST/v1/invoices/upcoming?customer=$cus -curl -sSf -u $SK: $HOST/v1/invoices/upcoming?customer=$cus\&subscription_items%5B0%5D%5Bplan%5D=pro-annuel\&subscription_tax_percent=20 +curl -sSfg -u $SK: $HOST/v1/invoices/upcoming?customer=$cus\&subscription_items[0][plan]=pro-annuel\&subscription_tax_percent=20 -curl -sSf -u $SK: $HOST/v1/invoices/upcoming?customer=$cus\&subscription=$sub\&subscription_items%5B0%5D%5Bid%5D=si_RBrVStcKDimMnp\&subscription_items%5B0%5D%5Bplan%5D=basique-annuel\&subscription_proration_date=1504182686\&subscription_tax_percent=20 +curl -sSfg -u $SK: $HOST/v1/invoices/upcoming?customer=$cus\&subscription=$sub\&subscription_items[0][id]=si_RBrVStcKDimMnp\&subscription_items[0][plan]=basique-annuel\&subscription_proration_date=1504182686\&subscription_tax_percent=20 -curl -sSf -u $SK: $HOST/v1/invoices/$in/lines +curl -sSfg -u $SK: $HOST/v1/invoices/$in/lines -cus=$(curl -sSf -u $SK: $HOST/v1/customers \ +cus=$(curl -sSfg -u $SK: $HOST/v1/customers \ -d description='This customer will have a subscription with volume tiered pricing' \ -d email=tiered@bar.com \ | grep -oE 'cus_\w+' | head -n 1) -curl -sSf -u $SK: $HOST/v1/customers/$cus/sources \ +curl -sSfg -u $SK: $HOST/v1/customers/$cus/sources \ -d source=$tok -curl -sSf -u $SK: $HOST/v1/subscriptions \ +curl -sSfg -u $SK: $HOST/v1/subscriptions \ -d customer=$cus \ -d items[0][plan]=annual-tiered-volume \ -d items[0][quantity]=5 -curl -sSf -u $SK: $HOST/v1/invoices?customer=$cus +curl -sSfg -u $SK: $HOST/v1/invoices?customer=$cus -curl -sSf -u $SK: $HOST/v1/subscriptions?customer=$cus +curl -sSfg -u $SK: $HOST/v1/subscriptions?customer=$cus -curl -sSf -u $SK: $HOST/v1/customers/$cus/subscriptions +curl -sSfg -u $SK: $HOST/v1/customers/$cus/subscriptions -cus=$(curl -sSf -u $SK: $HOST/v1/customers \ +cus=$(curl -sSfg -u $SK: $HOST/v1/customers \ -d description='This customer will have a subscription with graduated tiered pricing' \ -d email=tiered@bar.com \ | grep -oE 'cus_\w+' | head -n 1) -curl -sSf -u $SK: $HOST/v1/customers/$cus/sources \ +curl -sSfg -u $SK: $HOST/v1/customers/$cus/sources \ -d source=$tok -sub=$(curl -sSf -u $SK: $HOST/v1/subscriptions \ +sub=$(curl -sSfg -u $SK: $HOST/v1/subscriptions \ -d customer=$cus \ -d items[0][plan]=monthly-tiered-graduated \ -d items[0][quantity]=5 \ | grep -oE 'sub_\w+' | head -n 1) -data=$(curl -sSf -u $SK: $HOST/v1/subscriptions/$sub \ +data=$(curl -sSfg -u $SK: $HOST/v1/subscriptions/$sub \ -d items[0][plan]=annual-tiered-volume) -same_data=$(curl -sSf -u $SK: $HOST/v1/subscriptions/$sub \ +same_data=$(curl -sSfg -u $SK: $HOST/v1/subscriptions/$sub \ -d items[0][plan]=annual-tiered-volume) diff <(echo "$data") <(echo "$same_data") -curl -sSf -u $SK: $HOST/v1/subscriptions/$sub \ +curl -sSfg -u $SK: $HOST/v1/subscriptions/$sub \ -d metadata[toto]=toto -curl -sSf -u $SK: $HOST/v1/invoices?customer=$cus +curl -sSfg -u $SK: $HOST/v1/invoices?customer=$cus -cus=$(curl -sSf -u $SK: $HOST/v1/customers \ +cus=$(curl -sSfg -u $SK: $HOST/v1/customers \ -d description='This customer will switch from a yearly to another yearly plan' \ -d email=switch@bar.com \ | grep -oE 'cus_\w+' | head -n 1) -curl -sSf -u $SK: $HOST/v1/customers/$cus/sources \ +curl -sSfg -u $SK: $HOST/v1/customers/$cus/sources \ -d source=$tok -sub=$(curl -sSf -u $SK: $HOST/v1/subscriptions \ +sub=$(curl -sSfg -u $SK: $HOST/v1/subscriptions \ -d customer=$cus \ -d items[0][plan]=basique-annuel) sub_id=$(echo "$sub" | grep -oE 'sub_\w+' | head -n 1) sub_item_id=$(echo "$sub" | grep -oE 'si_\w+' | head -n 1) -sub=$(curl -sSf -u $SK: $HOST/v1/subscriptions/$sub_id \ +sub=$(curl -sSfg -u $SK: $HOST/v1/subscriptions/$sub_id \ -d items[0][plan]=pro-annuel \ -d items[0][id]=$sub_item_id) -in=$(curl -sSf -u $SK: $HOST/v1/invoices \ +in=$(curl -sSfg -u $SK: $HOST/v1/invoices \ -d customer=$cus) grep -q "Abonnement PRO (annuel)" <<<"$in" grep -q "Abonnement basique (annuel)" <<<"$in" -cus=$(curl -sSf -u $SK: $HOST/v1/customers \ +cus=$(curl -sSfg -u $SK: $HOST/v1/customers \ -d email=john.malkovich@example.com \ | grep -oE 'cus_\w+' | head -n 1) -pm=$(curl -sSf -u $SK: $HOST/v1/payment_methods \ +pm=$(curl -sSfg -u $SK: $HOST/v1/payment_methods \ -d type=card \ -d card[number]=4242424242424242 \ -d card[exp_month]=12 \ @@ -505,46 +505,46 @@ pm=$(curl -sSf -u $SK: $HOST/v1/payment_methods \ -d card[cvc]=123 \ | grep -oE 'pm_\w+' | head -n 1) -curl -sSf -u $SK: $HOST/v1/payment_methods/$pm/attach \ +curl -sSfg -u $SK: $HOST/v1/payment_methods/$pm/attach \ -d customer=$cus -curl -sSf -u $SK: $HOST/v1/customers/$cus \ +curl -sSfg -u $SK: $HOST/v1/customers/$cus \ -d invoice_settings[default_payment_method]=$pm -curl -sSf -u $SK: $HOST/v1/customers/$cus?expand%5B%5D=invoice_settings.default_payment_method +curl -sSfg -u $SK: $HOST/v1/customers/$cus?expand[]=invoice_settings.default_payment_method -curl -sSf -u $SK: $HOST/v1/payment_methods?customer=$cus\&type=card +curl -sSfg -u $SK: $HOST/v1/payment_methods?customer=$cus\&type=card -curl -sSf -u $SK: $HOST/v1/payment_methods/$pm/detach -X POST +curl -sSfg -u $SK: $HOST/v1/payment_methods/$pm/detach -X POST -pm=$(curl -sSf -u $SK: $HOST/v1/payment_methods \ +pm=$(curl -sSfg -u $SK: $HOST/v1/payment_methods \ -d type=card \ -d card[number]=4000000000000002 \ -d card[exp_month]=4 \ -d card[exp_year]=2042 \ -d card[cvc]=123 \ | grep -oE 'pm_\w+' | head -n 1) -code=$(curl -s -o /dev/null -w "%{http_code}" -u $SK: \ +code=$(curl -sg -o /dev/null -w "%{http_code}" -u $SK: \ $HOST/v1/payment_methods/$pm/attach \ -d customer=$cus) [ "$code" = 402 ] -curl -sSf -u $SK: $HOST/v1/payment_methods?customer=$cus\&type=card +curl -sSfg -u $SK: $HOST/v1/payment_methods?customer=$cus\&type=card -res=$(curl -sSf -u $SK: $HOST/v1/setup_intents -X POST) +res=$(curl -sSfg -u $SK: $HOST/v1/setup_intents -X POST) seti=$(echo "$res" | grep '"id"' | grep -oE 'seti_\w+' | head -n 1) seti_secret=$(echo $res | grep -oE 'seti_\w+_secret_\w+' | head -n 1) -curl -sSf -u $SK: $HOST/v1/setup_intents/$seti/confirm -X POST +curl -sSfg -u $SK: $HOST/v1/setup_intents/$seti/confirm -X POST -curl -sSf -u $SK: $HOST/v1/setup_intents/$seti/cancel -X POST +curl -sSfg -u $SK: $HOST/v1/setup_intents/$seti/cancel -X POST -res=$(curl -sSf -u $SK: $HOST/v1/setup_intents -X POST) +res=$(curl -sSfg -u $SK: $HOST/v1/setup_intents -X POST) seti=$(echo "$res" | grep '"id"' | grep -oE 'seti_\w+' | head -n 1) seti_secret=$(echo $res | grep -oE 'seti_\w+_secret_\w+' | head -n 1) # This is what a Stripe.js request does: -curl -sSf $HOST/v1/setup_intents/$seti/confirm \ +curl -sSfg $HOST/v1/setup_intents/$seti/confirm \ -d key=pk_test_sldkjflaksdfj \ -d use_stripe_sdk=true \ -d client_secret=$seti_secret \ @@ -557,7 +557,7 @@ curl -sSf $HOST/v1/setup_intents/$seti/confirm \ # off_session cannot be used when confirm is false code=$( - curl -s -o /dev/null -w "%{http_code}" \ + curl -sg -o /dev/null -w "%{http_code}" \ -u $SK: $HOST/v1/payment_intents \ -d amount=1000 \ -d currency=usd \ @@ -567,7 +567,7 @@ code=$( # card fingerprint fingerprint=$( - curl -sSf -u $SK: $HOST/v1/customers/$cus/cards \ + curl -sSfg -u $SK: $HOST/v1/customers/$cus/cards \ -d source[object]=card \ -d source[number]=4242424242424242 \ -d source[exp_month]=12 \ @@ -577,7 +577,7 @@ fingerprint=$( [ -n "$fingerprint" ] fingerprint=$( - curl -sSf -u $SK: $HOST/v1/customers/$cus/cards \ + curl -sSfg -u $SK: $HOST/v1/customers/$cus/cards \ -d source[object]=card \ -d source[number]=4000056655665556 \ -d source[exp_month]=12 \ @@ -587,7 +587,7 @@ fingerprint=$( [ -n "$fingerprint" ] fingerprint=$( - curl -sSf -u $SK: $HOST/v1/customers/$cus/cards \ + curl -sSfg -u $SK: $HOST/v1/customers/$cus/cards \ -d source[object]=card \ -d source[number]=5555555555554444 \ -d source[exp_month]=12 \ @@ -598,7 +598,7 @@ fingerprint=$( # sepa debit fingerprint fingerprint=$( - curl -sSf -u $SK: $HOST/v1/sources \ + curl -sSfg -u $SK: $HOST/v1/sources \ -d type=sepa_debit \ -d sepa_debit[iban]=DE89370400440532013000 \ -d currency=eur \ @@ -606,7 +606,7 @@ fingerprint=$( [ -n "$fingerprint" ] fingerprint=$( - curl -sSf -u $SK: $HOST/v1/sources \ + curl -sSfg -u $SK: $HOST/v1/sources \ -d type=sepa_debit \ -d sepa_debit[iban]=FR1420041010050500013M02606 \ -d currency=eur \ @@ -614,7 +614,7 @@ fingerprint=$( [ -n "$fingerprint" ] fingerprint=$( - curl -sSf -u $SK: $HOST/v1/sources \ + curl -sSfg -u $SK: $HOST/v1/sources \ -d type=sepa_debit \ -d sepa_debit[iban]=IT40S0542811101000000123456 \ -d currency=eur \ @@ -623,7 +623,7 @@ fingerprint=$( # payment method fingerprint fingerprint=$( - curl -sSf -u $SK: $HOST/v1/payment_methods \ + curl -sSfg -u $SK: $HOST/v1/payment_methods \ -d type=card \ -d card[number]=4242424242424242 \ -d card[exp_month]=12 \ @@ -633,7 +633,7 @@ fingerprint=$( [ -n "$fingerprint" ] fingerprint=$( - curl -sSf -u $SK: $HOST/v1/payment_methods \ + curl -sSfg -u $SK: $HOST/v1/payment_methods \ -d type=card \ -d card[number]=4000056655665556 \ -d card[exp_month]=12 \ @@ -643,7 +643,7 @@ fingerprint=$( [ -n "$fingerprint" ] fingerprint=$( - curl -sSf -u $SK: $HOST/v1/payment_methods \ + curl -sSfg -u $SK: $HOST/v1/payment_methods \ -d type=card \ -d card[number]=5555555555554444 \ -d card[exp_month]=12 \ @@ -654,7 +654,7 @@ fingerprint=$( # create a chargeable source card=$( - curl -sSf -u $SK: $HOST/v1/customers/$cus/cards \ + curl -sSfg -u $SK: $HOST/v1/customers/$cus/cards \ -d source[object]=card \ -d source[number]=4242424242424242 \ -d source[exp_month]=12 \ @@ -664,7 +664,7 @@ card=$( # create a normal charge, verify charge status succeeded status=$( - curl -sSf -u $SK: $HOST/v1/charges \ + curl -sSfg -u $SK: $HOST/v1/charges \ -d source=$card \ -d amount=1000 \ -d currency=usd \ @@ -673,7 +673,7 @@ status=$( # create a pre-auth charge charge=$( - curl -sSf -u $SK: $HOST/v1/charges \ + curl -sSfg -u $SK: $HOST/v1/charges \ -d source=$card \ -d amount=1000 \ -d currency=usd \ @@ -682,23 +682,23 @@ charge=$( # verify charge status pending status=$( - curl -sSf -u $SK: $HOST/v1/charges/$charge \ + curl -sSfg -u $SK: $HOST/v1/charges/$charge \ | grep -oE '"status": "pending"') [ -n "$status" ] # capture the charge -curl -sSf -u $SK: $HOST/v1/charges/$charge/capture \ +curl -sSfg -u $SK: $HOST/v1/charges/$charge/capture \ -X POST # verify charge status succeeded status=$( - curl -sSf -u $SK: $HOST/v1/charges/$charge \ + curl -sSfg -u $SK: $HOST/v1/charges/$charge \ | grep -oE '"status": "succeeded"') [ -n "$status" ] # create a non-chargeable source card=$( - curl -sSf -u $SK: $HOST/v1/customers/$cus/cards \ + curl -sSfg -u $SK: $HOST/v1/customers/$cus/cards \ -d source[object]=card \ -d source[number]=4000000000000341 \ -d source[exp_month]=12 \ @@ -708,7 +708,7 @@ card=$( # create a normal charge, observe 402 response code=$( - curl -s -o /dev/null -w "%{http_code}" \ + curl -sg -o /dev/null -w "%{http_code}" \ -u $SK: $HOST/v1/charges \ -d source=$card \ -d amount=1000 \ @@ -717,7 +717,7 @@ code=$( # create a normal charge charge=$( - curl -s -u $SK: $HOST/v1/charges \ + curl -sg -u $SK: $HOST/v1/charges \ -d source=$card \ -d amount=1000 \ -d currency=usd \ @@ -725,14 +725,14 @@ charge=$( # verify charge status failed status=$( - curl -sSf -u $SK: $HOST/v1/charges/$charge \ + curl -sSfg -u $SK: $HOST/v1/charges/$charge \ | grep -oE '"status": "failed"') [ -n "$status" ] # create a pre-auth charge, observe 402 response code=$( - curl -s -o /dev/null -w "%{http_code}" \ + curl -sg -o /dev/null -w "%{http_code}" \ -u $SK: $HOST/v1/charges \ -d source=$card \ -d amount=1000 \ @@ -742,7 +742,7 @@ code=$( # create a pre-auth charge charge=$( - curl -s -u $SK: $HOST/v1/charges \ + curl -sg -u $SK: $HOST/v1/charges \ -d source=$card \ -d amount=1000 \ -d currency=usd \ @@ -751,6 +751,35 @@ charge=$( # verify charge status failed status=$( - curl -sSf -u $SK: $HOST/v1/charges/$charge \ + curl -sSfg -u $SK: $HOST/v1/charges/$charge \ | grep -oE '"status": "failed"') [ -n "$status" ] + +# list charges +total_count=$( + curl -sSfg -u $SK: $HOST/v1/charges | grep -oE '"total_count": 15') +[ -n "$total_count" ] + +total_count=$( + curl -sSfg -u $SK: $HOST/v1/charges?customer=$cus \ + | grep -oE '"total_count": 6') +[ -n "$total_count" ] + +total_count=$( + curl -sSfg -u $SK: $HOST/v1/charges?customer=$cus\&created[gt]=1588166306 \ + | grep -oE '"total_count": 6') +[ -n "$total_count" ] + +no_more_events=$(curl -sSfg -u $SK: $HOST/v1/events \ + | grep -oE '^ "has_more": false' || true) +[ -z "$no_more_events" ] +last_event=$(curl -sSfg -u $SK: $HOST/v1/events?limit=100 \ + | grep -oE 'evt_\w+' | tail -n 1) +no_more_events=$(curl -sSfg -u $SK: $HOST/v1/events?starting_after=$last_event \ + | grep -oE '^ "has_more": false') +[ -n "$no_more_events" ] +zero_events=$(curl -sSfg -u $SK: $HOST/v1/events?starting_after=$last_event \ + | grep -oE '^ "data": \[\]') +[ -n "$zero_events" ] + +curl -sSfg -u $SK: $HOST/v1/balance