SOLVED: Issues with Invalid Authorization header, ch:service

This is now solved! Thanks to @voracityemail for their response. I’ve added some tweaks and it is now fully working. If you have any similar issues please find the working code below.

------ WORKING CODE ------

// Replace with the company number you want to search
$compno = "04176976";

$URL = "https://api.company-information.service.gov.uk/company/" . $compno . "/persons-with-significant-control";
$apikey = "___________________"; // API Key goes here
$acceptTypes = [ "application/json" ]; // any types you support - not strictly necessary here

$ch = curl_init();

$headers = [ 'Accept:' . implode(', ', $acceptTypes) ];

curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_URL => $URL,
    // Our API key is the username - we need username:password
    CURLOPT_USERPWD => $apikey . ":",
    CURLOPT_HTTPHEADER => $headers,
    // Make security explicit!
    CURLOPT_SSL_VERIFYPEER => true, // default true per cURL 7.1
    CURLOPT_SSL_VERIFYHOST => 2, // Should be the default e.g. secure.
]);

$result = curl_exec($ch);
if (!curl_errno($ch)) {
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    // If request was successful
    if ($http_code == "200") {
        $decodedResult = json_decode($result);
    
        // For each item from the result (each item corresponds to an individual PSC)
        foreach ($decodedResult->items as $PSC) {
              // echo $PSC->whichever field you want to collect
              echo $PSC->name;
        }
        //  View the entire response in a nice format
        // echo "<pre>" . print_r($decodedResult, true) . "</pre>";
    }
    else {
         echo "Http code: " . $http_code;
    }
}
else {
    echo curl_error($ch);    
}
curl_close($ch);

---- ORIGINAL POST -----

Hey, sorry i’m sure i’m doing something really obviously wrong but I can’t see what it is and i’ve looked at some similar articles and haven’t found any solutions so I thought I’d give posting here a go.

I’ve just started working with the API today and tried to follow the example at

I’m working in PHP however so I’ve written it as follows:

$URL = "https://api.company-information.service.gov.uk/company/01234567/persons-with-significant-control"; 

$ch = curl_init();

$header = array();
$header[] = "Content-Length: 0";    
$header[] = "Content-type: application/json; charset=utf-8";
$header[] = "Authorization: Basic ---API KEY----";

curl_setopt($ch, CURLOPT_POST,true);
curl_setopt($ch, CURLOPT_URL, $URL);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);

$request = curl_exec($ch);    
curl_close($ch);

var_dump($request);

where the —API KEY— is obviously replaced with my API key. I’m getting the repsonse back as:

{    
   "error": "Invalid Authorization header", 
   "type": "ch:service"
}

I’ve also tried doing this directly through Postman Canary and I’m getting the same response.

If anyone has any advice or could point me in a certain direction to figure it out myself I’d be immensely grateful. Again I’m sure i’m just missing something obvious and that this is a trivial issue so apologies in advance.

For extra detail incase it is somehow relevant, I have no restricted IP’s or specified my own IP/added a host and Javascript access disabled for the Application.

Thanks in advance.

You haven’t said exactly how you put in the “API KEY” part but I’m guessing this is just your plain text API key. If so, that’s the first issue - solution below.

2nd point - you mentioned you’ve “no restricted IP’s or specified my own IP/added a host and Javascript access disabled for the Application”. You need to either:
a) to be running the PHP on a server that you’ve registered with Companies House or
b) (special case of above restriction) you can run on a “localhost” server if you follow the workaround in the following thread:
https://forum.aws.chdev.org/t/allow-localhost-javascript-domain/83

So just running your PHP code on some computer that Companies House doesn’t know won’t work - you’ll likely get a 403 Forbidden.

Back to point 1 - since this is http basic authorization you need to supply a) a username and password and b) this needs to be base64 encoded. In this case the “username” is your API key, the password is blank. You can do this yourself of course but there’s a CURLOPT in PHP exactly for this - CURLOPT_USERPWD.
Other things to make it simpler - since you’re not actually passing any JSON to Companies House you can skip the header for this, and you don’t need the content-length either. If you really wanted to spell things out you could pass an “Accept:” header with the mime types that you can accept. PHP also provides curl_setopt_array() to make this simpler too. I don’t know which version of PHP you have but since about PHP 5.4 there’s the shorter array syntax. So a final assumption that you’re on an older version of PHP suggests you might need to spell out that you’re actually checking certificates with https. Note that this needs up-to-date certificates to be present - you can use CURLOPT_CAPATH / CURLOPT_CAINFO options to point the system to these if required.

So that would give you something like (not tested):

$URL = "https://api.company-information.service.gov.uk/company/01234567/persons-with-significant-control"; 
$apikey = "the ch api key here";
$acceptTypes = [ "application/json" ]; // any types you support - not strictly necessary here

$ch = curl_init();

$headers = [ 'Accept:' . implode(', ', $acceptTypes) ];

curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_URL => $URL,
    // Our API key is the username - we need username:password
    CURLOPT_USERPWD => $apikey . ":",
    CURLOPT_HTTPHEADER => $headers,
    // Make security explicit!
    CURLOPT_SSL_VERIFYPEER => true, // default true per cURL 7.1
    CURLOPT_SSL_VERIFYHOST => 2, // Should be the default e.g. secure.
]);

$request = curl_exec($ch);
if (!curl_errno($ch)) {
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    echo "Response code $http_code\n";
    var_dump($request);
}
else {
    echo curl_error($ch);
}
curl_close($ch);

hey @voracityemail you have no idea how grateful i am for you taking the time to reply. I’m going to look through all of this now and hopefully I can work towards a resolution. If not i’ll likely drop you a mention with any further details and see if you can help.

Seriously thanks again for making the effort i’m on a deadline to get this working so i’ve been rather stressed.

Happy new year and stay safe.