Having spent a whole morning fighting Facebook to change a phone number, it was a relief to get back to the issue. Creating an Instagram Post via the API.
The documentation is daunting, and the process is long-winded, but as I discovered the actual solution is straightforward.
Create the App
The first thing you need to do is create an Instagram App via the Meta App Dashboard. There is a detailed set of instructions in the developer documentation. My experience is that for our specific use case several of these steps are not necessary.
https://developers.facebook.com/docs/instagram-platform/create-an-instagram-app
Step one, yes you need to create an App. Step two, you don’t need to connect a business. Steps three to seven are all necessary (select the use case, app type, add the app details, and add Instagram as a product to the app). This gives you access to the basic interface. For a API that posts to your own business account only, you don’t need web hooks, a verified business login or to complete the app review. Nor, surprisingly, do you need to make your app live!
Get the User ID and Access Tokens
You do need to authenticate the app, and as I alluded to last time this is the kicker.
The API Endpoints you need to create an Instgram post are media and media_publish. The calls for these are as follows:
POST https://graph.facebook.com/v23.0/<YOUR_APP_USERS_IG_USER_ID>/media
?image_url=<IMAGE_URL>
&is_carousel_item=<TRUE_OR_FALSE>
&alt_text=<IMAGE_ALTERNATIVE_TEXT>
&caption=<IMAGE_CAPTION>
&location_id=<LOCATION_PAGE_ID>
&user_tags=<ARRAY_OF_USERS_FOR_TAGGING>>
&product_tags=<ARRAY_OF_PRODUCTS_FOR_TAGGING>
&access_token=<USER_ACCESS_TOKEN>
POST https://graph.facebook.com/v23.0/<YOUR_APP_USERS_IG_USER_ID>/media_publish
?creation_id=<CONTAINER_ID>
&access_token=<USER_ACCESS_TOKEN>HTTPAs you can probably spot both of them require two authentication items <YOUR_APP_USERS_IG_USER_ID> and <USER_ACCESS_TOKEN>.
The User Access Token is easy to locate. In the Meta App Dashboard you need to go to the API Setup with Instagram Login option (near the bottom the left hand panel). This gives you the option to generate an access token (and may ask you to log in to your instagram account in order to do it).
Before you can log in to Instagram, however, you need a tester set up. To do this head over to the App Roles option, click Add People, and add your Instagram account as an Instagram Tester. Once this is done you can generate the access token. Keep it secret, keep it safe. If you are going to write it into a script put the script somewhere outside of your web-servers public html directories!
I found the User ID rather harder to locate. What actually is Your App Users IG User ID?
- It is not your Instagram username.
- It is not the App ID that the App dashboard helpfully displays clearly for you to see when you generate the access token (also given if you use the Token Debugger)
- It is not even your users id which you can find publically by looking up your user ID on a number of look-up sites (eg https://commentpicker.com/instagram-user-id.php).
After an hour or so of pulling my hair out I stumbled upon it entirely by accident on the API Integration Helper page in the App Dashboard. There is a field that requests the Access Token and a button to validate it. After a short delay it gives you a number in blue. This is YOUR_APP_USERS_IG_USER_ID. Thanks for making it obvious. I probably missed it somewhere obvious (correct me in the comments!)
Write the code
With these two pieces of information in my possession it was easy to knock up a piece of PHP to post to instagram.
As I mentioned before, there are actually two api calls required. The media endpoint returns a container id, which we then use in the media_publish endpoint to publish the post. Note that I have not implemented the location_id, user_tags or product_tags fields in the media call.
class instAPI {
// I am using instagram authentiction. If you use a facebook account id
// change the prefix to https://graph.facebook.com/v23.0/
private $prefix = "https://graph.instagram.com/v23.0/";
private $userId = "xxx"; //YOUR_APP_USERS_IG_USER_ID
private $token = "xxxx"; // USER_ACCESS_TOKEN - keep it safe!
private $status = 0;
function call($endpoint, $post=true) {
// build the url from all the components
$url = $this->prefix . $this->userId . $endpoint . "&access_token=" . $this->token;
// send the API call using curl
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
if ($post) curl_setopt($ch,CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$output = curl_exec($ch);
$this->status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($this->status==200) return $output;
else return "";
}
function postImage($img, $cptn) {
$caption = url_encode($cptn); // url encode to cope with spaces, quotation marks etc
$result = $this->call ("/media?image_url=$img&is_carousel_item=false&caption=$caption");
// If the first call worked, then publish the post with the id returned
if ($this->status == 200) {
$container = json_decode($result, true);
$this->call("/media_publish?creation_id=" . $container["id"]);
}
}
}
$image = "???"; // The URL of the image you want to post
$caption = "???"; // The caption you want to go with the Image
$api = new instAPI();
$api->postImage($image, $caption);
PHPNot much to show for a day’s work, but surprisingly satisfying when the post appeared in the Instagram timeline…
For those who need more than just the media post calls there is a comprehensive API Integration SDK on GitHub as well as a lot of videos by Justin Stolpe. I looked into these but ended up not using it because it seemed overkill for my purposes. I also couldn’t work out which of his many videos told me how to get the user id I needed.
Postscript: Dealing with subcode 2207027
After this code had been running error free for a couple of months I started getting an occasional HTTP Status 400 error on the media_publish call
{"error":
{"message":"Media ID is not available",
"type":"OAuthException",
"code":9007,
"error_subcode":2207027,
"is_transient":false,
"error_user_title":"Cannot publish",
"error_user_msg":"The media is not ready to be published. Please wait a moment.",
"fbtrace_id":"ARhk2xssq5hk7AFqcPD5axT"
}
}BashA quick search for the error code turns up the graph api error code page which doesn’t really say much more about the error than the user message already tells us. The recommended action is to check the container status and post when the media publish is finished.
As the image publish nearly always worked instantly, it looks like the processing occasionally takes a little longer than normal. As I am calling the post from a cron job, there is no particular hurry to call the publish command, so I simply added a sleep(10) command in the code to wait for ten seconds between the first and second call. This solves the issue.
// If the first call worked, then publish the post with the id returned
if ($this->status == 200) {
set_time_limit(30); // extend script timelimit to prevent timing out
sleep(10);
$container = json_decode($result, true);
$this->call("/media_publish?creation_id=" . $container["id"]);
}PHP

Leave a Reply