XF 2.1 How to use the API

AndyB

Well-known member
In regards to the new API and the introduction here:

https://xenforo.com/community/threads/rest-api.155632/

What are the first steps to using the API? In the Admin control panel I created an API key.

I assume I should be able to put in the address bar of my browser the following example to retrieve information about thread_id 123:

https://www.domain.com/api/threads/123/?key={my api key}

But this results in the standard error message:

189384

Thank you.
 
In regards to the new API and the introduction here:

https://xenforo.com/community/threads/rest-api.155632/

What are the first steps to using the API? In the Admin control panel I created an API key.

I assume I should be able to put in the address bar of my browser the following example to retrieve information about thread_id 123:

https://www.domain.com/api/threads/123/?key={my api key}

But this results in the standard error message:

View attachment 189384

Thank you.

I haven't tested this or really looked at the API use here but I use this for another project and may be a good start.

PHP:
// Curl Function
function execute_curl($data_string) {

    $service_url = 'https://www.domain.com/api/ ';
    $curl = curl_init($service_url);
    $data_string = json_encode($data_string);
    //set the url, number of POST vars, POST data
    curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST");
    curl_setopt($curl, CURLOPT_POSTFIELDS, $data_string);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_POST, true);
    curl_setopt($curl, CURLOPT_HTTPHEADER, array(
        'X-API-KEY: <your-key>',
        'Content-Type: application/json',
        'Content-Length: ' . strlen($data_string))
    );
 
    //execute post
    $curl_response = curl_exec($curl);
    $result = json_decode($curl_response, true);
    curl_close($curl);
    unset($curl);
    //close connection
    return $result;
}
 
In case you're wondering, guys, the API will be documented and is a work in progress at this point.

But, yes, the posts above are correct, it's passed as a header rather than in the URL. The header name is XF-Api-Key.
 
Thank you, Jaxel, Brent and Chris.

Got it to work using this:

PHP:
<?php

$headers = array(
    'Content-type: application/json',
    'XF-Api-Key: <your-key>',
);

$url = 'https://www.domain.com/api/threads/123/';

$ch = curl_init();
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_URL, $url);
$json = curl_exec($ch);

echo $json;
 
Can someone please show me how to use Guzzle. Perhaps show how the cURL above can be converted to Guzzle.

Thank you.
 
You should be able to adapt what's in this post for your needs:
 
Thank you, Snog.

Here's my attempt but it doesn't work:

PHP:
<?php

namespace Andy\Test\Pub\Controller;

use XF\Pub\Controller\AbstractController;

class Test extends AbstractController
{
    public function actionIndex()
    {   
        $client = \XF::app()->http()->client([
            'headers' => ['Accept' => 'application/json'],
            'auth' => ['XF-Api-Key' => '<your-key>']
        ]);

        $response = $client->get("https://www.domain.com/api/threads/123/");

        $yourInfo = \GuzzleHttp\json_decode($response->getBody(), true);
        print_r($yourInfo);

        exit();
    }
}

I get the following error with it:

189413
 
You are setting up HTTP authentication with username XF-Api-Key and the key as password.; the API-Key needs to be passed as Header XF-Api-Key just like you are passing Header Accept
 
Thank you, Jake and Kirby.

Unfortunately I'm not having any luck. I tried this but got the same error message:

PHP:
<?php

namespace Andy\Test\Pub\Controller;

use XF\Pub\Controller\AbstractController;

class Test extends AbstractController
{
	public function actionIndex()
	{	
		$client = \XF::app()->http()->client([
			'headers' => [
				'Accept' => 'application/json',
				'XF-Api-Key' => '<your-key>']
		]);

		$response = $client->get("https://www.doman.com/api/threads/365/");

		$yourInfo = \GuzzleHttp\json_decode($response->getBody(), true);
		print_r($yourInfo);

		exit();
	}
}
 
@AndyB I'm not trying to be an idiot here, but you really need to read documentation when it's available. What I gave was a base example in that other thread.

There is a debug option in Guzzle, so I tested the base example with it:
$response = $client->get("http://192.168.32.39/api/threads/1924/", ['debug' => true]);

The result was this:
  • Hostname 192.168.32.39 was found in DNS cache
  • Trying 192.168.32.39...
  • TCP_NODELAY set
  • Connected to 192.168.32.39 (192.168.32.39) port 80 (#0)
GET /api/threads/1924/ HTTP/1.1
Host: 192.168.32.39
User-Agent: XenForo/2.x (http://192.168.32.34)

< HTTP/1.1 400 Bad Request
< Date: Fri, 30 Nov 2018 13:26:03 GMT
< Server: Apache/2.4.29 (Ubuntu)
< XF-Latest-Api-Version: 1
< XF-Used-Api-Version: 1
< XF-Request-User: 0
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: private, no-cache, max-age=0
< X-XF-Debug-Stats: {"time":0.0339,"queries":1,"memory":2.72}
< Content-Length: 181
< Connection: close
< Content-Type: application/json; charset=utf-8
<
* Closing connection 0

That told me immediately the API Key wasn't being set.

So I tried setting the header a different way:
$response = $client->get("http://192.168.32.39/api/threads/1924/", ['headers' => ['XF-Api-Key' => '<My Key>'],'debug' => true]);

Lo and behold, the correct response came:
  • Hostname 192.168.32.39 was found in DNS cache
  • Trying 192.168.32.39...
  • TCP_NODELAY set
  • Connected to 192.168.32.39 (192.168.32.39) port 80 (#0)
GET /api/threads/1924/ HTTP/1.1
Host: 192.168.32.39
XF-Api-Key: <MY Key>
User-Agent: XenForo/2.x (http://192.168.32.34)

< HTTP/1.1 200 OK
< Date: Fri, 30 Nov 2018 13:27:54 GMT
< Server: Apache/2.4.29 (Ubuntu)
< XF-Latest-Api-Version: 1
< XF-Used-Api-Version: 1
< XF-Request-User: 0
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: private, no-cache, max-age=0
< X-XF-Debug-Stats: {"time":0.0553,"queries":10,"memory":3.55}
< Content-Length: 3164
< Content-Type: application/json; charset=utf-8
<
* Connection #0 to host 192.168.32.39 left intact
Array
(
[thread] => Array
(
[thread_id] => 1924
[node_id] => 2
[title] => Add-on Update to XF 2.0 Schedule
[reply_count] => 27
[view_count] => 1737

With that info, you could have figured out that this should be your request:
Code:
try
{
    $client = \XF::app()->http()->client();
    $response = $client->get("https://www.doman.com/api/threads/365/", ['headers' => ['XF-Api-Key' => '<Your API Key>']]);
}
catch (\GuzzleHttp\Exception\RequestException $e)
{
    if (null !== $e->getResponse())
    {
        $error = 'Tracker Error ' . $e->getResponse()->getStatusCode() . ': ' . $e->getResponse()->getReasonPhrase();
    }
    else
    {
        $error = $e->getMessage();
    }

    return $this->error($error);
}

if(\XF::options()->currentVersionId >= '2010031')
{
    // XF 2.1
    $yourInfo = \GuzzleHttp\json_decode($response->getBody(), true);
}
else
{
    // XF 2.0
    $yourInfo = $response->json();
}

print_r($yourInfo);

die();
 
Thank you, Snog.

I really appreciate your help.

This code now works perfectly:

PHP:
<?php

namespace Andy\Test\Pub\Controller;

use XF\Pub\Controller\AbstractController;

class Test extends AbstractController
{
	public function actionIndex()
	{
		$client = \XF::app()->http()->client();
		$response = $client->get("https://www.domain.com/api/threads/123/", ['headers' => ['XF-Api-Key' => '<Your API Key>']]);
		$array = \GuzzleHttp\json_decode($response->getBody(), true);
		print_r($array);
		exit();
	}	
}
 
Thank you, Snog.

Here's the code with the error detection added:

PHP:
<?php

namespace Andy\Test\Pub\Controller;

use XF\Pub\Controller\AbstractController;

class Test extends AbstractController
{
    public function actionIndex()
    {
        try
        {
            $client = \XF::app()->http()->client();
            $response = $client->get("https://www.domain.com/api/threads/123/", ['headers' => ['XF-Api-Key' => '<Your API Key>']]);
        }
        catch (\GuzzleHttp\Exception\RequestException $e)
        {
            if (null !== $e->getResponse())
            {
                $error = 'Error ' . $e->getResponse()->getStatusCode() . ' - ' . $e->getResponse()->getReasonPhrase();
            }
            else
            {
                $error = $e->getMessage();
            }

            return $this->error($error);
        }
        $array = \GuzzleHttp\json_decode($response->getBody(), true);
        print_r($array);
        exit();
    }   
}
 
Last edited:
Hey I don't want to hijack this thread but since this is also API related I would like to give it a try here before creating my own thread. So I am currently using XF as my main all-round solution what I mean by this is that my nuxtjs admin panel is powered by lumen which accesses the xenforo DB and also implements some of the controllers. A couple of weeks ago I thought about moving away from my php rest API and go with golang instead. So I was wondering if there is a way of managing user upgrades through the API. Like upgrading users or extend subscriptions and so on. Regards Artur
 
Hey I don't want to hijack this thread but since this is also API related I would like to give it a try here before creating my own thread. So I am currently using XF as my main all-round solution what I mean by this is that my nuxtjs admin panel is powered by lumen which accesses the xenforo DB and also implements some of the controllers. A couple of weeks ago I thought about moving away from my php rest API and go with golang instead. So I was wondering if there is a way of managing user upgrades through the API. Like upgrading users or extend subscriptions and so on. Regards Artur

Doesn't look to be supported, unless it's hidden away in a controller that isn't labelled as UserUpgrades. They have the following API controllers:

Code:
Attachment(s)
Auth
Conversation(s)
ConversationMessage(s)
Error
Forum
Index
Me
Node(s)
Post(s)
ProfilePost(s)
ProfilePostComment(s)
Thread(s)
User(s)
 
Doesn't look to be supported, unless it's hidden away in a controller that isn't labelled as UserUpgrades. They have the following API controllers:

Code:
Attachment(s)
Auth
Conversation(s)
ConversationMessage(s)
Error
Forum
Index
Me
Node(s)
Post(s)
ProfilePost(s)
ProfilePostComment(s)
Thread(s)
User(s)

Alright, thanks for your help. Is there any public docu available? I might just move my code to an xenforo addon and emulate the api endpoint.
 
Alright, thanks for your help. Is there any public docu available? I might just move my code to an xenforo addon and emulate the api endpoint.

Not currently, Chris had mentioned that they plan on thoroughly documenting it though
 
Top Bottom