This was working for me on one account and today I added my listener to a new Stripe account and now it is no longer working. When a customer adds a new payment method to their account, the event customer.source.created is fired. Here is my code that WAS working (this is an excerpt):
<?php
if($event->type == 'customer.source.created') {
$cardID = $event_json->data->object->id;
$customerID = $event_json->data->object->customer;
$brand = $event_json->data->object->brand;
$last4 = $event_json->data->object->last4;
$exp_month = $event_json->data->object->exp_month;
$exp_year = $event_json->data->object->exp_year;
}
?>
Here is a sample Stripe JSON response:
{
"id": "evt_1DLkAh2Y54K5YG39Lku1hJ1G",
"object": "event",
"api_version": "2018-09-24",
"created": 1539664123,
"data": {
"object": {
"id": "card_1DLkAf2Y54K5YG39C0jMpCOj",
"object": "card",
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": null,
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": null,
"brand": "JCB",
"country": "JP",
"customer": "cus_DnCcf39Nqp4RwF",
"cvc_check": "pass",
"dynamic_last4": null,
"exp_month": 12,
"exp_year": 2024,
"fingerprint": "t56gZmsPg6ztkHFH",
"funding": "credit",
"last4": "0000",
"metadata": {
},
"name": null,
"tokenization_method": null
}
},
"livemode": false,
"pending_webhooks": 2,
"request": {
"id": "req_L9pvt2RR3VSZoG",
"idempotency_key": null
},
"type": "customer.source.created"
}
The Stripe response code is 200. I have other events in my listener like charge.succeeded that are working just fine with pretty much the same coding methods. Right now, I can't get the $cardID to echo. So I'm wondering if Stripe changed something recently. I am running the latest version in Webhooks. I did try to revert to an older version but that didn't work either.
Ok this was a very stupid issue I didn't catch. The stripe account that I set up today was in an older version and there was an update available. I didn't catch that because I was working in test mode and you can only upgrade in live mode.
So, after upgrading, everything works perfectly. Hours of wasted time and something so simple.
Related
I'm trying to interface a Swift app with the Stripe API, using Alamofire, but I'm having trouble with the returned results. I was expecting valid JSON, but I am getting the following:
Stripe\SetupIntent JSON: {
"id": "seti_1Go**************g4qyJgp",
"object": "setup_intent",
"application": null,
"cancellation_reason": null,
"client_secret": "seti_1Go***************gp_secret_HM*******************ObpHy7Mk",
"created": 1590784053,
"customer": "cus_H*********Tna",
"description": null,
"last_setup_error": null,
"livemode": false,
"mandate": null,
"metadata": [],
"next_action": null,
"on_behalf_of": null,
"payment_method": null,
"payment_method_options": {
"card": {
"request_three_d_secure": "automatic"
}
},
"payment_method_types": [
"card"
],
"single_use_mandate": null,
"status": "requires_payment_method",
"usage": "off_session"
}
I'm using the following PHP code:
$customer = \Stripe\Customer::create();
$setupIntent = \Stripe\SetupIntent::create([
'customer' => $customer->id
]);
$this->response($setupIntent, 200);
How can I get at the JSON inside this object? I tried converting it to json, but then I get nothing. Alamofire doesn't like it the way it is now. Do I need to somehow strip off the "Stripe\SetupIntent JSON:"?
You can access the json object body that came back from the API with getLastResponse():
$setupIntent->getLastResponse()->body
edit. You can also use json_encode() to produce the json from the object yourself:
json_encode($setupIntent)
I am working with Stripe Payment Gateway and everything is working so far, except the option, that my users can download their invoice on my website. It is possible to download an invoice inside the stripe dashboard but that is not what I need. After my users made a payment, they should be able to download their invoices to my system.
Currently I am working with stripe webhooks. A user makes a payment and the data is saved inside my database. This is how my code looks like:
\Stripe\Stripe::setApiKey("$stripe_secret_key_test");
// Retrieve the request's body and parse it as JSON:
$input = #file_get_contents('php://input');
$event_json = json_decode($input);
// Update database with new billing entry
if ($event_json->type == 'invoice.payment_succeeded') {
$invoice_id = $event_json->data->object->id;
$customer = $event_json->data->object->customer;
$date = $event_json->data->object->date;
$price = $event_json->data->object->amount_paid;
$user = $event_json->data->object->lines->data[0]->metadata->userid;
$stripe_sub_id = $event_json->data->object->lines->data[0]->id;
$plan_id = $event_json->data->object->lines->data[0]->plan->id;
$stamp_created = $event_json->data->object->lines->data[0]->plan->created;
$comments = $event_json->data->object->lines->data[0]->plan->nickname;
$period_start = $event_json->data->object->lines->data[0]->period->start;
$period_end = $event_json->data->object->lines->data[0]->period->end;
$content=array("invoice"=>$invoice_id,
"user"=>$user,
"stripe_cust_id"=>$customer,
"stripe_sub_id"=>$stripe_sub_id,
"idea_id"=>0,
"billing_date"=>$date,
"plan"=>$plan_id,
"price"=>$price,
"stamp_created"=>$stamp_created,
"period_start"=>$period_start,
"period_end"=>$period_end,
"status"=>'paid',
"printed"=>0);
insertGWInfo('billing',$content);
$content=array("user"=>$user,
"trans_time"=>date("Y-m-d H:i:s"),
"ip"=>$_SERVER['REMOTE_ADDR'],
"trans_type"=>1,
"cash_amount"=>$price,
"comments"=>"Subscription for ".$comments."",
"idea_id"=>0);
insertGWInfo('user_accounting',$content);
}
Now I´ve created a table where I fetch those entries from my database and display them to my customer. I would like to have a button now with "Download Invoice" where my customers can download the subscription invoice which appears monthly.
Any idea how I can do this? I have the invoice_id but where do I get the URL to download an invoice? I wasn´t able to find anything inside the stripe docs. Any help would be really appreciated.
EDIT:
Here is the JSON outcome for invoice.payment_suceeded:
"{
"created": 1326853478,
"livemode": false,
"id": "evt_00000000000000",
"type": "invoice.payment_succeeded",
"object": "event",
"request": null,
"pending_webhooks": 1,
"api_version": "2018-02-28",
"data": {
"object": {
"id": "in_00000000000000",
"object": "invoice",
"amount_due": 1000,
"amount_paid": 1000,
"amount_remaining": 0,
"application_fee": null,
"attempt_count": 1,
"attempted": true,
"billing": "charge_automatically",
"charge": "_00000000000000",
"closed": true,
"currency": "eur",
"customer": "cus_00000000000000",
"date": 1526455801,
"description": null,
"discount": null,
"due_date": null,
"ending_balance": 0,
"forgiven": false,
"lines": {
"data": [
{
"id": "sub_Cs4DUPJKcAJ7cg",
"object": "line_item",
"amount": 1000,
"currency": "eur",
"description": "1 standard-inv × Standard Investor (at €10.00 / month)",
"discountable": true,
"livemode": false,
"metadata": {
},
"period": {
"end": 1531726201,
"start": 1529134201
},
"plan": {
"id": "3",
"object": "plan",
"aggregate_usage": null,
"amount": 1000,
"billing_scheme": "per_unit",
"created": 1526375755,
"currency": "eur",
"interval": "month",
"interval_count": 1,
"livemode": false,
"metadata": {
},
"nickname": "Standard Plan for Investors",
"product": "prod_CrihTVfgRHgImD",
"tiers": null,
"tiers_mode": null,
"transform_usage": null,
"trial_period_days": null,
"usage_type": "licensed"
},
"proration": false,
"quantity": 1,
"subscription": null,
"subscription_item": "si_Cs4DrvYN2FlCbS",
"type": "subscription"
}
],
"has_more": false,
"object": "list",
"url": "/v1/invoices/in_1CSK5FDsOByhb3e8m8Z1BooY/lines"
},
"livemode": false,
"metadata": {
},
"next_payment_attempt": null,
"number": "774C629-0001",
"paid": true,
"period_end": 1526455801,
"period_start": 1526455801,
"receipt_number": null,
"starting_balance": 0,
"statement_descriptor": null,
"subscription": "sub_00000000000000",
"subtotal": 1000,
"tax": null,
"tax_percent": null,
"total": 1000,
"webhooks_delivered_at": 1526455810
}
}
}"
Stripe DOES support this now. The PDF link is available by listing the invoices via the API and accessing the invoice_pdf attribute of an invoice.
Here's how you can get an array of invoices with their PDF links:
const invoicesResponse = await stripe.invoices.list({ customer: customerStripeId });
const invoices = invoicesResponse.map(invoice => ({
invoiceId: invoice['id'],
pdf: invoice['invoice_pdf'],
}));
return invoices;
Here's the API docs:
https://stripe.com/docs/api/invoices/object#invoice_object-invoice_pdf Thanks #avelis for the suggestion.
Stripe does not support downloading the invoice as a PDF at the moment via the API and it is only available in the dashboard instead.
For now, the best solution is to build your own invoice receipt/pdf instead. You can retrieve the Invoice object via the API which tells you what the invoice is for: period, amount, when it was paid, what's in that invoice, etc. And you can then generate your own receipt for your customers on your end.
it is posible :) works like a charm with the Python API.
import stripe
import requests
stripe_keys = {'secret_key': 'XXXxxxx','publishable_key': 'XXXxxxx'}
stripe.api_key = stripe_keys['secret_key']
stripe_subscription_id = 'XXXXXXX'
invoices = stripe.Invoice.list(subscription=stripe_subscription_id)
for inv in invoices:
pdf = inv.invoice_pdf
invoice_file = requests.get(pdf)
open('C://User//XXXXX//Desktop//invoice.pdf', 'wb').write(invoice_file.content)
There is a much easier way now. Following are the steps I follow to use Stripe's default method to download the invoice pdf.
Find the customer for which I want to download the invoice in pdf format
const findCustomerByEmail = async (email) => {
try {
const customer = await stripe.customers.list({
email,
limit: 1,
});
if (customer.data.length !== 0) {
return customer.data[0].id;
}
} catch (e) {
return (e);
}
};
Now that I have the customer, I then find all the invoices of the user:
exports.getInvoices = async (req, res, next) => {
const cusStripeId = await findCustomerByEmail(req.user.email);
const invoices = await stripe.invoices.list({
limit: 3000,
customer: cusStripeId,
});
res.status(httpStatus.OK).json(invoices);
};
Now I have a list of the invoices for this user. I can traverse through all the invoices.
invoices.data[0].invoice_pdf
invoices object is an array, and the data[0].invoice_pdf has a link that will download pdf. As an alternative we can also see the invoice as an html page without the need to download it, as follows.
invoices.data[0].hosted_invoice_url
I'm using Symfony 3.3 serializer. This code:
$serialized = $this->serializer->serialize($input, "json");
returns:
{
"title": "dsd",
"description": null,
"source": null,
"tags": null,
"objectId": null,
"attributes": {
"sdffds": "sdffsdfsd",
"fsfdsfd": "sdfsdfsdf"
},
"features": [],
"lifecycleStart": null,
"lifecycleEnd": null,
"attachments": {
"20170625194534-595012dee26c8": {
"original": "favicon (1).ico",
"filename": "favicon (1).ico",
"size": "318",
"title": null,
"description": null,
"reader": null
}
}
}
Unforutnately, running
$serialized = $this->serializer->serialize($input, "xml");
will throw an exception:
Uncaught PHP Exception DOMException: "Invalid Character Error" at /www/site/ui/vendor/symfony/symfony/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php line 454
I'm pretty sure I didn't include any funny character. Do you have any idea whether I'm doing anything wrong or could it be a symfony bug?
It's probably because of 20170625194534-595012dee26c8. XML element name cannot start with number. See: The Naming of Parts article on XML.com.
A webhook is sending me some data to the URl I have provided. I am trying to catch the data. This is the code I am using:-
if ($this->input->server('REQUEST_METHOD') == 'POST')
{
file_put_contents('test.txt', file_get_contents('php://input'));
......................
}
The data which got saved in the txt file is this:-
{
"created_at": "2017-04-04 12:03:07 UTC",
"href": "http://api.groovehq.com/v1/tickets/131",
"links": {
"customer": {
"id": "0454984580",
"href": "http://api.groovehq.com/v1/customers/ncc2017customer#gmail.com"
},
"drafts": {
"href": "http://api.groovehq.com/v1/tickets/131/drafts"
},
"state": {
"href": "http://api.groovehq.com/v1/tickets/131/state"
},
"messages": {
"href": "http://api.groovehq.com/v1/tickets/131/messages"
}
},
"number": 131,
"priority": "low",
"resolution_time": null,
"state": "unread",
"title": "gh",
"updated_at": "2017-04-04 12:03:07 UTC",
"system_updated_at": "2017-04-04 12:03:07 UTC",
"assigned_group_id": null,
"assigned_group": null,
"closed_by": null,
"tags": [
],
"mailbox": "Inbox",
"mailbox_id": "1923237790",
"message_count": 1,
"summary": "Complaint Date: 2017-4-22 Service Provider: Airtel Type of Complaint: Billing NCC need to do: Investigate and resolve the issue Complaint Details: Vb",
"type": "API",
"snoozed_until": null,
"last_message": "Complaint Date: 2017-4-22<br />\nService Provider: Airtel<br />\nType of Complaint: Billing<br />\nNCC need to do: Investigate and resolve the issue<br />\nComplaint Details: Vb",
"assignee": null,
"app_url": "https://matrixdroid.groovehq.com/groove_client/tickets/44746020",
"app_customer_url": "https://matrixdroid.groovehq.com/groove_client/contacts/customers/17295897",
"customer_name": "ncc2017customer#gmail.com",
"last_message_plain_text": "Complaint Date: 2017-4-22\nService Provider: Airtel\nType of Complaint: Billing\nNCC need to do: Investigate and resolve the issue\nComplaint Details: Vb"
}
Now, I need to get the links->customer->href data
How can I get this?
I tried this:-
$json_data = file_get_contents('php://input');
$json_decode_data = json_decode($json_data);
file_put_contents('test.txt', $json_decode_data['links']['customer']['href']);
Nothing getting written in the txt file. How can I parse the href data?
json_decode() will produce a StdClass by default. If you want an array, add a true parameter. Then use the correct variable, being $data, when referencing it:
$data = json_decode(file_get_contents('php://input'), true);
To get data of the href, you need to do something like this
<?php
$data = json_decode(file_get_contents('test.txt'));
echo '<pre>';
print_r($data->links->customer->href);
?>
I have a nested json file
{
"event_type": "INCOMING_BTC",
"event_uid": "5515c5601f7b3",
"datetime": "2015-03-27 21:02:37",
"resources": [
{
"resource_type": "transaction",
"resource": {
"id": 105062,
"datetime": "2015-03-27 21:02:23",
"description": "Money from Xapo Tip",
"order_type": "payment_received",
"from": {
"type": "btc_address",
"id": "1AqF787aPHgPRZ81kdQSeEwW46yjyrAaxR"
},
"to": {
"destination_type": "btc_address",
"destination_id": "1N65Bz88zKUDPKhUUsx8f9Qwsuo96Hqz7S",
"to_account": 1276
},
"generic_type": "credit",
"amount": "0.0000001",
"currency": "BTC",
"status": "completed",
"txConfidence": 1,
"rejection_reason": null,
"notes": null,
"base_currency": "USD",
"exchange_rate": null,
"exchange_amount": null
}
},
{
"resource_type": "address",
"resource": {
"id": "1N65Bz88zKUDPKhUUsx8f9Qwsuo96Hqz7S",
"address": "1N65Bz88zKUDPKhUUsx8f9Qwsuo96Hqz7S",
"meta_data": null,
"label": null,
"total_received": "0.00000350",
"created_at": "2015-03-08 14:50:59",
"address_type": "multisig",
"id_account": "1276"
}
}
]
}
And I have saved this file in public folder with name xapojson.txt
In my routes file I have done json_decode to decode this data to a variable 'transaction' and passed it to view
Route::get('/', function () {
$transaction = json_decode(file_get_contents('xapojson.txt'));
return view('transaction', compact('transaction'));
});
Now in transaction view I have to display the data from this nested json.
I have tried out lots of variation and searched on google and stackoverflow but nothing worked.
I found this somewhat helpful Check this out. But it also do not get into more nesting.
In the view I have to display these datas:-
resources[0]->resource->from->type
resources[0]->resource->id
resources[0]->resource->from->id
resources[0]->resource->status
resources[0]->resource->amount
resources[0]->resource->currency
resources[0]->resource->to->destination_id
datetime
Please help me on displaying the above fields.
Try using
$transaction = json_decode(file_get_contents('xapojson.txt'), true);
Well when I made this code work in simple php, I extracted the data by
$xapo_json = file_get_contents('xapojson.txt');
$xapo_json_decoded = json_decode($xapo_json);
$from_type = $xapo_json_decoded->resources[0]->resource->from->type;
$transacid = $xapo_json_decoded->resources[0]->resource->id;
$from = $xapo_json_decoded->resources[0]->resource->from->id;
$status = $xapo_json_decoded->resources[0]->resource->status;
$amount = $xapo_json_decoded->resources[0]->resource->amount;
$currency = $xapo_json_decoded->resources[0]->resource->currency;
$to = $xapo_json_decoded->resources[0]->resource->to->destination_id;
$datetime = $xapo_json_decoded->datetime;
Then in the routes file i changed
return view('transaction', compact('transaction'));
to
return View::make('transaction')->with('transaction',$transaction);
And in view I used this
{{ $transaction->resources[0]->resource->from->id }}
Voila, It works
you can do it with the below code ( am taking div as example you can change it to table or whatever
#foreach($transaction->resources as $resource)
#if(is_set($resource->from))
<div>{{$resource->from->type}}</div>
#endif
<div>{{$resource->id}}</div>
#if(is_set($resource->from))
<div>{{$resource->from->id}}</div>
#endif
<div>{{$resource->status}}</div>
<div>{{$resource->amount}}</div>
<div>{{$resource->currency}}</div>
<div>{{$resource->to->destination_id}}</div>
#endforeach