Systems that answer later

A quote gets priced. A van gets scheduled. A page gets built. The customer's message was answered minutes ago.

Most connected systems are a question with an answer: Jabee calls, waits a few seconds, uses what comes back. This is the contract for the ones that are not.

Turning it on

Add the system under Setup → Systems as usual, and tick this one answers later. The same page shows the token to post back with, and can replace it.

1. Jabee calls you

POST https://yourservice.example/api/quotes
{
  "vehicle": "Corolla",
  "callback_url": "https://api.jabee.ai/api/callbacks/8f14e45f-ceea-...",
  "callback_ref": "8f14e45f-ceea-467a-9f3b-1c0a2d3e4f56"
}

Your own fields, plus those two. The field names come from the intent and the owner can rename them in the dashboard, so read what you recognise and ignore the rest. A rename should never need a deploy on your side.

Answer in a few seconds. Somebody is holding a phone. This call accepts the job rather than doing it. Any 2xx is taken as accepted; anything else and the customer is told a person will pick it up.

What you return here is discarded. The answer is step two.

2. You post the result back

POST <the callback_url you were given>
Authorization: Bearer <the token from the Systems page>
Content-Type: application/json

{
  "status": "ok",
  "data": { "price": "450 AED", "valid_until": "19 November" },
  "callback_id": "job-8821-attempt-1"
}
FieldNotes
statusok, failed, or needs_person.
dataWhat the job produced, as plain fields. Any JSON. Send it on a failure too.
reasonOn a failure or needs_person. Logged for the owner, never read to the customer.
callback_idStable across retries of one result, different for a new one.

A failure can still carry facts

data is used whatever the status, and this is the part worth getting right. If a rebuild failed and the previous version is still live, send it:

{ "status": "failed", "data": { "url": "https://..." } }

The customer is then told their thing is unchanged at that link, rather than that it is gone. With no data they are told it did not work and that a person is picking it up.

needs_person takes the same shape and is relayed the same way, with the thread put in front of a person.

You send the result. Jabee writes the words.

There is no message field. {"price": "450 AED"} becomes "Your quote is ready, 450 AED." A link appears in the sentence exactly as written.

Two reasons, and both get more important the more systems a business connects. Every one of them then sounds like the same assistant. And a connected service cannot put arbitrary words on somebody else's WhatsApp number.

What you get back

200  { "relayed": true }                      sent to the customer
200  { "relayed": false, "duplicate": true }  already had this one
200  { "relayed": false, "reason": "..." }    the job is no longer open
401                                           wrong or missing token
404                                           a reference we do not have
410                                           it arrived too late

A reference is one-time and scoped to one job, so it cannot be used to post into any other conversation.

Questions

How long do I have to post the result back?

Long enough for real work, and not forever. Past the window you get a 410 and the customer has already been told a person is picking it up.

What if I post the same result twice?

Nothing happens the second time. Keep callback_id stable across retries of one result and you get relayed: false with duplicate: true.

Can I send the customer my own wording?

No. Send fields and Jabee writes the sentence. A link you include appears exactly as you wrote it.

What if the job fails?

Send status failed, and send any data you still have. A failed rebuild that leaves the old version live should say so, because the customer can act on that.