Struggling with syntax for a really simple REST command payload

I have read the RESTful Command document page and searched through the various community posts on getting RESTful commands working. Most of the posts seemed to be trying to solve much more complex problems than mine and imply background knowledge I don’t have. So, unfortunately I’m still not able to get my config working.

I’m struggling to understand the meaning of the various characters used in defining the payload for the command. This is what I think I know cobbled together from reading all the discussion posts…

’ ’ is used to encapsulate the whole payload to denote it as a string that get concatenated with the contents of the url defined.
{ } is used to encapsulate HA entity values
" " is used to encapsulate plan or literal text
~ is used to concatenate all the above together.

I am aiming to create a barcode lookup command. The output of the command needs to look like.

https://api.upcdatabase.org/product/0111222333446?apikey=THISISALIVEDEMOAPIKEY19651D54X47

I want to replace the value 0111222333446 with the contents of a defined text input called ‘barcode’.

I need to replace everything after “apikey=” with the API Key stored as a secret.

I defined a RESTful command as follows.

rest_command:
  barcode_lookup:
    url: "https://api.upcdatabase.org/product/"
    method: get
    payload: '{input_text.barcode}~"?apikey="~!secret upcdb_apikey'

When I call this Service from Developer Tools, it returns an error that the API key is invalid. It seems my understanding of the syntax here is flawed.

I was hoping turning on debug tools would allow me to see the exact URL being passed out the door by Home Assistant so I could see what my current syntax is actually generating, but that didn’t do what I was expecting. Is there anywhere that logs the generated URL?

Thanks!

There are two problems with your template.

  1. you need to access the state of the entity:
payload: "{{ states('input_text.barcode'}}~ etc...
  1. you can’t use secrets in templates. The way around this is to put the entire template in the secret.

secrets.yaml

barcode_payload: "{{ states('input_text.barcode') ~ '?apikey=your key here' }}"

configuration.yaml

rest_command:
  barcode_lookup:
    url: "https://api.upcdatabase.org/product/"
    method: get
    payload: !secret barcode_payload
1 Like

Thanks @tom_l

So less an issue with my lack of understanding the syntax characters and more to do with my lack of understanding of how to access the value I need. Your explanation makes complete sense.

Thanks for taking the time to respond.

1 Like

TIL I can use templates in my secrets file! I must’ve missed this for years now.

The guidance here has helped tremendously in progressing this but I’m still not quite there… Looking again at the authentication documentation for the API, it recommends having the API key in the header. So I’ve revised the definition to be:

rest_command:
  barcode_lookup:
    url: https://api.upcdatabase.org/product/
    method: get
    payload: 4005808705481
#    payload: "{ states('input_text.barcode') }"
    headers:
      Authorization: !secret upcdb_apikey

So now I’m not getting authentication errors. But the response is reporting that the code supplied “does not contain all digits”.

content:
  success: false
  error:
    code: 403
    message: Bad Request. The code you are trying to enter does not contain all digits.
status: 400

As you can see in the command definition, as a troubleshooting measure, I’ve substituted the lookup of the text field for a hard coded value which is all digits. So the error has me confused.

I also tried changing the field that holds the barcode value from an input_text to an input_number but still received the same error.

Still feel like I’m missing something obvious and basic in defining the payload…

Now you likely revert because the template itself is returning the whole API string. Now you only need the secret key. Go to a webbrowser and execute what you need that works. Access the headers in the developer console and see what was sent.

This tells you everything you need:

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://api.upcdatabase.org/product/0111222333446',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => '',
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 0,
  CURLOPT_FOLLOWLOCATION => true,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => array(
    'Authorization: Bearer THISISALIVEDEMOAPIKEY19651D54X47'
  ),
));

Your call should be https://api.upcdatabase.org/product/{{product_id}}
And your header should be Authorization: Bearer THISISALIVEDEMOAPIKEY19651D54X47
So the product ID is not part of the payload, it is part of the URL:

Definition
https://api.upcdatabase.org/product/{id}
{id} is the UPC or EAN number
1 Like

Success! Thanks to @kbrown01 and @tom_l !

Working config if anyone else is looking to use the same service.

rest_command:
  barcode_lookup:
    url: https://api.upcdatabase.org/product/{{ states('input_text.barcode') }}
    method: get
    headers:
      Authorization: !secret upcdb_apikey

Format of the secret is

upcdb_apikey: "Bearer <Your API Key>"
1 Like