LinkedIn API UGC post success but not showing? - php

I believe I am successfully posting a new post to the endpoint
https://api.linkedin.com/v2/ugcPosts
using (similar to)
{
"author": "urn:li:organization:1234567",
"lifecycleState": "PUBLISHED",
"specificContent": {
"com.linkedin.ugc.ShareContent": {
"shareCommentary": {
"attributes": [],
"text": "Some share text"
}
}
},
"visibility": {
"com.linkedin.ugc.MemberNetworkVisibility": "PUBLIC"
}
}
The response I get is
{"id":"urn:li:share:01234567890123456789"}
But then when I go to the company page, the post is not visible. Note that the IDs are redacted here. Is there another step I have to take?
edit: I went to verify the post with the endpoint https://api.linkedin.com/v2/ugcPosts/[redacted URN]?viewContext=AUTHOR and my post is a success
{
"lifecycleState": "PUBLISHED",
"specificContent": {
"com.linkedin.ugc.ShareContent": {
"shareCommentary": {
"inferredLocale": "en_US",
"attributes": [],
"text": "Test article sharing article on LinkedIn API , please ignore"
},
"media": [
{
"media": "urn:li:digitalmediaAsset:XXXXXXXXXXXXXX",
"title": {
"attributes": [],
"text": "image"
},
"thumbnails": [],
"status": "READY"
}
],
"shareFeatures": {
"hashtags": []
},
"shareMediaCategory": "IMAGE"
}
},
"visibility": {
"com.linkedin.ugc.MemberNetworkVisibility": "PUBLIC"
},
"created": {
"actor": "urn:li:person:XXXXXXXXXXXXXX",
"time": 1649285262053
},
"author": "urn:li:organization:XXXXXXXXXXXXXX",
"clientApplication": "urn:li:developerApplication:XXXXXXXXXXXXXX",
"versionTag": "0",
"id": "urn:li:share:XXXXXXXXXXXXXX",
"firstPublishedAt": 1649285262053,
"lastModified": {
"actor": "urn:li:csUser:7",
"time": 1649285262122
},
"distribution": {
"externalDistributionChannels": [],
"distributedViaFollowFeed": true,
"feedDistribution": "MAIN_FEED"
},
"contentCertificationRecord": "{\"spamRestriction\":{\"classifications\":[],\"contentQualityClassifications\":[],\"systemName\":\"MACHINE_SYNC\",\"lowQuality\":false,\"contentClassificationTrackingId\":\"073BB82AD64A7608E3F142B6D0362E3D\",\"contentRelevanceClassifications\":[],\"spam\":false},\"originCountryCode\":\"ca\",\"modifiedAt\":1649285262024,\"contentHash\":{\"extractedContentMd5Hash\":\"0725A7E31B109EB4CFB84D2648CE3EC8\",\"lastModifiedAt\":1649285262023}}"
}
What am I missing here?? Why is it now showing on LinkedIn??
edit2 : went ahead and tried to share the post again, now all the posts are gone from the company page when viewed as admin, but showing (except the API posts) as a member.... How broken is this API ??????

I will answer my own post. Uploads using CurlFile DO NOT WORK, you have to use Guzzle... Once the upload & publishing are done, the feed will unbreak itself.. The company page will be broken if the endpoint is still waiting for upload while you post.
$client = new \GuzzleHttp\Client();
$res = $client->request('PUT', $__url, [
'headers' => [
'Authorization' => 'Bearer ' . $__token
],
'body' => fopen($__file, 'r')
]
);
if($res){
$res = json_decode($res->getBody());
}

Related

PHP Quickbooks SDK - Batch requests and handling failures

I've building out a small app that connects to a Quickbooks API via an SDK. The SDK provides batch operations to help reduce the number of API requests needed.
However, I'm hoping to make a large amount of requests (ie: bulk deletes, uploads in the 100s/1000s). I've gotten the deletes to work, however, now I'm hoping to integrate Laravel's Queue system so that any items in the $batch that fail (due to these business-rules or other reasons) are sent to a worker who will reattempt them after waiting a minute .
Below is an example of a delete request.
class QuickBooksAPIController extends Controller
{
public function batchDelete(Request $request, $category)
{
$chunks = array_chunk($request->data, 30);
foreach ($chunks as $key => $value) {
$batch[$key] = $this->dataService()->CreateNewBatch();
foreach ($value as $id) {
$item = $this->dataService()->FindById($category, $id);
$batch[$key]->AddEntity($item, $id, "delete");
}
$batch[$key]->Execute();
}
return response()->json(['message' => 'Items Deleted'], 200);
}
}
The documentations are a bit sparse for my scenario though. How can I get the failed batch items on order to try again?
Is using batches even the right choice here? Because I have to hit the API anyway to get the $item... which doesn't make sense to me (I think I'm doing something wrong there).
EDIT:
I intentionally sent out a request with more then 30 items and this is the failure message. Which doesn't have the values that didn't make the cut.
EDIT#2:
Ended up using array_chunk to separate the payload into 30 items (which is the limit of the API). Doing so helps process many requests. I've adjusted my code above to represent my current code.
How can I get the failed batch items on order to try again?
If you look at Intuit's documentation, you can see that the HTTP response the API returns contains this information. Here's the example request they show:
{
"BatchItemRequest": [
{
"bId": "bid1",
"Vendor": {
"DisplayName": "Smith Family Store"
},
"operation": "create"
},
{
"bId": "bid2",
"operation": "delete",
"Invoice": {
"SyncToken": "0",
"Id": "129"
}
},
{
"SalesReceipt": {
"PrivateNote": "A private note.",
"SyncToken": "0",
"domain": "QBO",
"Id": "11",
"sparse": true
},
"bId": "bid3",
"operation": "update"
},
{
"Query": "select * from SalesReceipt where TotalAmt > '300.00'",
"bId": "bid4"
}
]
}
And the corresponding response:
{
"BatchItemResponse": [
{
"Fault": {
"type": "ValidationFault",
"Error": [
{
"Message": "Duplicate Name Exists Error",
"code": "6240",
"Detail": "The name supplied already exists. : Another customer, vendor or employee is already using this \nname. Please use a different name.",
"element": ""
}
]
},
"bId": "bid1"
},
{
"Fault": {
"type": "ValidationFault",
"Error": [
{
"Message": "Object Not Found",
"code": "610",
"Detail": "Object Not Found : Something you're trying to use has been made inactive. Check the fields with accounts, customers, items, vendors or employees.",
"element": ""
}
]
},
"bId": "bid2"
},
{
"Fault": {
"type": "ValidationFault",
"Error": [
{
"Message": "Stale Object Error",
"code": "5010",
"Detail": "Stale Object Error : You and root were working on this at the same time. root finished before you did, so your work was not saved.",
"element": ""
}
]
},
"bId": "bid3"
},
{
"bId": "bid4",
"QueryResponse": {
"SalesReceipt": [
{
"TxnDate": "2015-08-25",
"domain": "QBO",
"CurrencyRef": {
"name": "United States Dollar",
"value": "USD"
},
"PrintStatus": "NotSet",
"PaymentRefNum": "10264",
"TotalAmt": 337.5,
"Line": [
{
"Description": "Custom Design",
"DetailType": "SalesItemLineDetail",
"SalesItemLineDetail": {
"TaxCodeRef": {
"value": "NON"
},
"Qty": 4.5,
"UnitPrice": 75,
"ItemRef": {
"name": "Design",
"value": "4"
}
},
"LineNum": 1,
"Amount": 337.5,
"Id": "1"
},
{
"DetailType": "SubTotalLineDetail",
"Amount": 337.5,
"SubTotalLineDetail": {}
}
],
"ApplyTaxAfterDiscount": false,
"DocNumber": "1003",
"PrivateNote": "A private note.",
"sparse": false,
"DepositToAccountRef": {
"name": "Checking",
"value": "35"
},
"CustomerMemo": {
"value": "Thank you for your business and have a great day!"
},
"Balance": 0,
"CustomerRef": {
"name": "Dylan Sollfrank",
"value": "6"
},
"TxnTaxDetail": {
"TotalTax": 0
},
"SyncToken": "1",
"PaymentMethodRef": {
"name": "Check",
"value": "2"
},
"EmailStatus": "NotSet",
"BillAddr": {
"Lat": "INVALID",
"Long": "INVALID",
"Id": "49",
"Line1": "Dylan Sollfrank"
},
"MetaData": {
"CreateTime": "2015-08-27T14:59:48-07:00",
"LastUpdatedTime": "2016-04-15T09:01:10-07:00"
},
"CustomField": [
{
"DefinitionId": "1",
"Type": "StringType",
"Name": "Crew #"
}
],
"Id": "11"
}
],
"startPosition": 1,
"maxResults": 1
}
}
],
"time": "2016-04-15T09:01:18.141-07:00"
}
Notice the separate response object for each request.
The bId value is a unique value you send in the request, which is then echo'd back to you in the response, so you can match up the requests you send with the responses you get back.
Here's the docs:
https://developer.intuit.com/app/developer/qbo/docs/api/accounting/all-entities/batch#sample-batch-request
Is using batches even the right choice here?
Batches make a lot of sense when you are doing a lot of things all at once.
The way you're trying to use them is... weird. What you should probably be doing is:
Batch 1
- go find all your items
Batch 2
- delete all the items
Your existing code doesn't make sense because you're trying to both find the item and delete the item in the exact same batch HTTP request, which isn't possible via the API.
I intentionally sent out a request with more then 30 items and this is the failure message.
No, it's not. That's a PHP error message - you have an error in your code.
You need to fix the PHP error, and then look at the actual response you're getting back from the API.

How to get an email address and other info like name and phone together after getting access token LinkedIn signup API with PHP

I am able to gent email using https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~)) and able to get name and profile pic using https://api.linkedin.com/v2/me.My question is that how can i get it together.Is there any single API to call and get all profile info together?
The documentation says something about lite and basic profile permissions but unfortunately there doesn't seem to be a way to get both in one query.
Profile Json Response:
{
"firstName":{
"localized":{
"en_US":"Bob"
},
"preferredLocale":{
"country":"US",
"language":"en"
}
},
"localizedFirstName": "Bob",
"headline":{
"localized":{
"en_US":"API Enthusiast at LinkedIn"
},
"preferredLocale":{
"country":"US",
"language":"en"
}
},
"localizedHeadline": "API Enthusiast at LinkedIn",
"vanityName": "bsmith",
"id":"yrZCpj2Z12",
"lastName":{
"localized":{
"en_US":"Smith"
},
"preferredLocale":{
"country":"US",
"language":"en"
}
},
"localizedLastName": "Smith",
"profilePicture": {
"displayImage": "urn:li:digitalmediaAsset:C4D00AAAAbBCDEFGhiJ"
}
}
Contact Json Response:
{
"elements": [
{
"handle": "urn:li:emailAddress:3775708763",
"handle~": {
"emailAddress": "ding_wei_stub#example.com"
},
"primary": true,
"type": "EMAIL"
},
{
"handle": "urn:li:phoneNumber:6146249836070047744",
"handle~": {
"phoneNumber": {
"number": "158****1473"
}
},
"primary": true,
"type": "PHONE"
}
]
}
The reason might be that there are separated APIs, Contact API and Profile API.

How to change normal urls to SparkPost Custom URL in SparkPost API using PHP?

Im trying to send a email template along with a URL whose click count should be tracked using SparkPost APIs?
Example: if I give www.google.com its has to change to
http://go.sparkpostmail1.com/f/a/EgvUoS2LdGPzMx-AURKwZA~~/AABUGAA~/RgRZK0BSP0EIAGukLuGW3OxXA3NwY1gEAAAAAFkGc2hhcmVkQgoAAVK7SFdpNVEbUhFuaWNvbGFzQGR1cmFuZC5jaAlRBAAAAABEUWh0dHBzOi8vZGlzaGx5Lm1lbnUvZC9XYXNoaW5ndG9uL1JlZ2VudF9UaGFpL0Jhc2lsX0phZS81NjBmMzk5MmQ0YWUxNTAzMDBmZWZmMGIiLEcCe30.
POST /api/v1/transmissions?num_rcpt_errors=3
{
"options": {
"start_time": "now",
"open_tracking": true,
"click_tracking": true,
"transactional": false,
"sandbox": false,
"ip_pool": "sp_shared",
"inline_css": false
},
"description": "Christmas Campaign Email",
"campaign_id": "christmas_campaign",
"metadata": {
"user_type": "students",
"education_level": "college"
},
"substitution_data": {
"sender": "Big Store Team",
"holiday_name": "Christmas"
},
"recipients": [
{
"address": {
"email": "wilma#flintstone.com",
"name": "Wilma Flintstone"
},
"tags": [
"greeting",
"prehistoric",
"fred",
"flintstone"
],
"metadata": {
"age": "24",
"place": "Bedrock"
},
"substitution_data": {
"customer_type": "Platinum",
"year": "Freshman"
}
}
],
"content": {
"from": {
"name": "Fred Flintstone",
"email": "fred#flintstone.com"
},
"subject": "Big Christmas savings!",
"reply_to": "Christmas Sales <sales#flintstone.com>",
"headers": {
"X-Customer-Campaign-ID": "christmas_campaign"
},
"text": "Hi \nSave big this Christmas in your area ! \nClick http://www.example.com and get huge discount\n Hurry, this offer is only to \n ",
"html": "<p>Hi \nSave big this Christmas in your area ! \nClick http://www.example.com and get huge discount\n</p><p>Hurry, this offer is only to \n</p><p></p>"
}
}
To enable "click tracking", set options.click_tracking=true field in your request. You have already done this but it looks like your links in the content.html are not HTML anchors (<a> tags) but just plain text links.
SparkPost will only track HTML anchors so I suggest changing this:
http://www.example.com
to this:
www.example.com

Gmail API return chats with "SENT" label

Using the Gmail API call
https://www.googleapis.com/gmail/v1/users/userId/messages/id
return chats with label SENT
I have used the following code for getting the message content
$url = "https://www.googleapis.com/gmail/v1/users/$useremail/messages/$messageid?format=full";
$response = $gmailInstance->performHttpRequest($gmailAuthObj, $useremail, $url);
$responseBody = json_decode($response->getResponseBody(), TRUE);
I got the following response for the above API call
{
"id": msgid,
"threadId": threadid,
"labelIds": [
"CHAT",
"SENT"
],
"snippet": "sometext",
"historyId": 7 digit numeric,
"internalDate": "1371160444361",
"payload": {
"partId": "",
"mimeType": "text/html",
"filename": "",
"headers": [{
"name": "From",
"value": "Test User \u003ctuser#tdom.com\u003e"
}],
"body": {
"size": 20,
"data": somerandomstring
}
},
"sizeEstimate": 100
}
Does anybody know why the API response return chat message with SENT label in it? Is there a way to avoid this (SENT label from chat response)?

Facebook - Get & Display me/og.likes in Video application

Have built an video app that publish user actions towards Facebook.
In this app i have implemented an "Favorite" function that i have hooked up towards a basic open graph action "og.like"
I want to be able to display video's that user liked and apply my own styling to that.
Basically i want to display "Title" "Url" & "Image"
So i use the PHP-SDK towards authored user with active access token and execute
$response = $facebook->api(
'me/og.likes',
'GET'
);
// handle the response
How do i now sort out my correct fields and display them ?
Am not hardcore at either php or javascript but will be able to sort this out if i just can get a little push in the right direction. Like just showing the raw data
Update
Finally a little progress, adding
print_r ($response);
Will write out the raw data, Now i know that am on the right way.
Array returned
{
"data": [
{
"id": "123",
"from": {
"name": "Mathias",
"id": "APP_ID"
},
"start_time": "X",
"end_time": "X",
"publish_time": "X",
"application": {
"name": "APP_Name",
"namespace": "",
"id": "321"
},
"data": {
"object": {
"id": "139",
"url": "Url to like",
"type": "video.tv_show",
"title": "title"
}
},
"type": "og.likes",
"no_feed_story": false,
"likes": {
"count": 0,
"can_like": true,
"user_likes": false
},
"comments": {
"count": 0,
"can_comment": true,
"comment_order": "chronological"
}
},
And then the next..
From every app "like" i would like to display Url ,Title & Image
From what i understand so far my main problem is that this is nested arrays, Did try with single level arrays and there i did manage to display correct data just by
echo $response[name];
So how do i digg in and loop this around, All tips are welcome,
{
"id": "139",
"url": "url",
"type": "video.tv_show",
"title": "titke",
"image": [
{
"url": "image_URL",
"secure_url": "image_URL",
"type": "image/jpg",
"width": 1024,
"height": 576
}
Here's an example:
<?php foreach ( $response['data'] as $data ): ?>
<?php $Object = $data['data']['object']; ?>
<?php echo $Object['title']; ?><br />
<?php endforeach; ?>

Categories