Can someone help me with webhooks

So, there’s a website that parses your emails for online orders, like Grubhub, and packs it into JSON format and can send it as a webhook to a destination of your choice.
How do I format the “Target URL” so that the JSON reaches the Graphql API? Do I need headers? If so, should I use username:password over tokens?

image

Edit: this is what the JSON payload looks like.

{
  "getSwiftTemplate": "rightguy's restaurant",
  "pickupPhone": "(123) 456-7890",
  "confirmationCode": "3361",
  "reference": "91001280 — 1508420",
  "orderType": "DELIVERY",
  "dateTime": "Sep 15, 2020, 12:24 PM",
  "itemCount": "3",
  "items": [
    {
      "quantity": "1",
      "description": "Goat Cheese Omelet Platter",
      "price": "$12.60"
    },
    {
      "quantity": null,
      "description": "* Substitute for Butter Bagel\n* Add Red Onion",
      "price": null
    },
    {
      "quantity": "1",
      "description": "Hot Coffee",
      "price": "$2.95"
    },
    {
      "quantity": null,
      "description": "* Large\n* NO Milk\n* NO Sugar",
      "price": null
    },
    {
      "quantity": "1",
      "description": "Pastrami Melt Hero Instructions: NO tomato please. Thanks!",
      "price": "$10.35"
    },
    {
      "quantity": null,
      "description": "* Add Jalapeno",
      "price": null
    }
  ],
  "dropoffDescription": "Include napkins and utensils? YES",
  "subTotal": "$25.90",
  "customerFee": "$1.00",
  "serviceFee": "$0.00",
  "tax": "$2.39",
  "tip": "$6.08",
  "grandTotal": "$35.37",
  "paymentMode": "PREPAID DO NOT CHARGE",
  "confirmationLink": "https://orderemails.grubhub.com/xxxx-xxx-xxx-xxxxxx",
  "dropoffName": "Example Customer Name",
  "dropoffAddress": "12-33 90th street",
  "unitNumber": "6G",
  "dropoffCity": "Queens",
  "dropoffState": "NY",
  "dropoffZip": "00010",
  "dropoffPhone": "Customer's Phone#",
  "deliveryInstructions": "For Apt. 6G - press the bell button. Leave at the front door of my apt.",
  "source": "grubhub",
  "ParentID": null,
  "Sender": "orders@eat.grubhub.com",
  "Recipient": "klemail@in.parseur.com",
  "To": "xxx@gmail.com"
}

Short answer, you don’t.

Long answer, you need something on the other end, your webhook, that will accept the order data from the service, verify it, store it, and respond back to the service within a certain amount of time that the order(s) is/are accepted.

Then, you’ll need something to process the data into various parts to be passed on to the SambaPOS API. Off the top of my head there are close to 10 separate API calls to compete a ticket.

1 Like

This part, I can do without hiccup.

I just don’t know what address I need to send the webhook to (if it even needs headers at all) and what port I should set the express node to listen to.

Do I just set the “Target URL” to my server’s IP address and choose any port and have a express node listen to that port?

The GraphQL API engine has no native support for anything but the defined queries and mutations. It has no webhook ability.

Your webhook URL is whatever script is living on a web server to receive the data.

1 Like

OK gonna try this first thing in the morning.

Graph api of samba is a receiving api, apis in nature are a fixed endpoint with a consistent format for various systems to communicate to samba, a Web hook is a way for a system to reach out to other systems on a specific event. Like api endpoints they usually have a consistent format to allow receiving system to process the data.
With both any one system are not directly made to communicate in the same format given different data types and sets unless specifically programed to as there is no real standards to the communications in way of the data itself, just the code type used, ie json or xml etc.
A Web hook of one system unless specifically created to communicate with another system isnt going to directly communicate in the expected format to be amble to directly post to another systems api.
On a side note the closest thing to a webhook in samba is a script triggered from a rule event that posts out to an external system.
Generally an api referees to an receiving system and Web hook to a outgoing system.
What you need is a intermediary system that receives the Web hook, translates to the format expected by samba and posts to samba.
I have worked with samba quite extensively on the outgoing side with my PMS intergration. Since the PMS doesn’t have webhooks I had to make scripts to query the PMS api on a routine and work out the updates to impliment.

A comparason to what your doing although not samba related was for hotels finance director who was using powerbi to render reports.
Although powered likely supports it neither of us could get it to successfully use the post type request for the PMS as the default api option uses get url.
What I did was create a simple ‘api relay’ which receives the powerbi get url request, processes the get variables and converts them into a post request compatible with the PMS api, then passes the json response back to power bi, luckily for which powerbi is able to process directly without any processing by the relay.

In essence a basic comparason would be that samba api listens in English but your Web hook speaks in French. Options are, samba learns French, webhook learns English or you get a translator.
Ideally one or other would learn the others language, that comes in form of an official intergration you could say. Although in theory its not that either are learning the others language but more that the developers make a built in translator. This can be time consuming and costly so developers need to choose the systems they do this for carefully as moreso that translating language an intergration needs maintinance and development as some systems are less controlled with backwards compatability of updates which can quickly break the intergrations.
Referring back to the json/xml reference in this context while api and webhook are talking and speaking language, the data format ie json could be compared to the alphabet. This at least makes translation easier vs of you compared it to learning mandarin or a language using a different alphabet.

The alternative is to use your own translator as described above which puts you in control of your own intergration.

Samba is quite special on this front in that with its customisable system we are able to customise the outgoing method using scripts, while we have less control over incoming listening side. This is the seccond reason I took the route of a ‘polling’ type intergration, yes the hotel PMS doesn’t have webhooks but also have the inbuilt control to make scheduled requests to PMS and do the ‘translation’ within the scripts I made in samba.
If I did again now there would be the option to have the translation happen elsewhere like you would need to do but at the time samba didn’t have the graph api, plus the type of intergration meant most communication is samba to pms and the data that samba needs from pms was generally stuff that was more than suitable for scheduled poll/update.

2 Likes

So, what you said cleared up my misunderstanding. I was thinking that my webserver had to be the same port as SambaPOS’s messaging server, which caused problems.

This is what I have so far:

const express = require("express");
const bodyParser = require("body-parser");
const app = express();
const PORT = 3000;

app.use(bodyParser.json());
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
app.post("/", (req, res) => {
    console.log(req.body); 
    res.status(200).end(); 
  })

I exposed my webhook port to the internet and sent a test order and my console log showed the JSON payload that the email parser is supposed to show! So, I’m off to a good start now.

1 Like

And you’re off to the races! Good luck!

1 Like

Can someone show me how to set up a POST request using a username/password granttype, instead of using access tokens?

POSTing to http://localhost:9000/api/graphql

EDIT:
Nevermind, I found out.

'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Basic base64EncodedUsernameAndPassword'

Are there any downsides of using basic authentication?

I never knew it accepted just basic credentials. I’ll have to see if there’s any change in processing time.

If it works, it works.

Yes! This will save me from getting a headache.
And it’s only going to be two local servers communicating together, so not using tokens shouldn’t be a big deal.

It’s not a headache with an access token. Store your access token and expiration date. Before starting a transaction see if the expiration date is after now (I pad the expiration date by 5 mins just to be safe) and if not, get a new token, update the stored token.

Have you tried registering a terminal, creating a ticket, etc. using basic authentication? Plain text, base64 both return http 401.

Heads-up, GraphQL doesn’t like line feeds. Be sure to parse ‘\n’ from your order responses.

Is there any way to enable Basic Authorization?

If your going to the effort, do it right…

I agree. The one thing I didn’t do was use refresh tokens.

One thing that absolutely blows in javascript, for me, is date handling. I would make a wrapper method/function that checks your expiration date. I like how C# does it with DateTime.Compare() - the method returns 1 if it’s in the past, 0 if it’s today, and -1 if it’s the future.

I often resort to working with the timestamp ms since 1970 or whenever it was as makes comparasons easier.

That’s all well and good, but what are you going to do after 0314 on 19/1/2038?

Howso? Whats happening then?

Unix timestamp is a 32bit integer. It can’t hold anything larger than 2,147,483,647.

Oh, and that’s assuming we all make it to 2038 :wink:

Thank you, I will use x.split(‘\n’) before it even reaches a gql mutation.