本文へスキップ

このページはまだお使いの言語では用意されていません。英語の文章をご覧いただいています。

Glossary

Webhook

Without one your program has to ask again and again whether anything changed, and the answer is almost always no. With one your own server learns about a profile, a proxy or a key in the same second the account does.

A webhook is a call one server makes to another the moment something happens, instead of waiting to be asked.

A call instead of a question

Polling is a program knocking on a door every few seconds. It costs both sides traffic, and the news that matters still arrives late.

A webhook turns that around. Your server stays quiet until something happens, and then it is the one being knocked on.

  • You give an address

    Any address of yours that answers over the open web. A page that lives only inside your own network cannot be reached from ours.

  • You tick the events

    Only the kinds you ticked are sent, so a receiver built for one job is not buried under the rest.

  • You get a secret

    The same secret signs every call, and it is what lets you tell our call from anyone else's.

What one call carries

The call is a plain post with a small body. The headers name the event and carry the proof that the body is ours.

Method
POST, Content-Type application/json
X-Armanos-Event
profile.start
X-Armanos-Timestamp
Unix seconds, also part of the signature
X-Armanos-Signature
sha256=... of the timestamp and the body
Body
{ id, event, createdAt, data }
Delivery
At least once. Keep the id and drop repeats

A redirect is not followed. An answer pointing back at loopback would otherwise undo the whole address check, which is why the answer has to come from the address you gave.

Events you can subscribe to

One list serves the whole account: the same names are offered to you, checked when you save and used when something is sent.

  • Profiles

    profile.create, profile.update, profile.delete, profile.start, profile.stop

  • Proxies

    proxy.create, proxy.update, proxy.delete

  • Keys

    apikey.create, apikey.revoke

  • Team

    team.invite, team.remove

  • Money

    plan.change

A second list would mean a promise nobody keeps

An event you can subscribe to but which is never sent looks exactly like a working subscription until the day you need it, so there is one list and nothing outside it.

Proving the call came from us

The signature is a hash of the timestamp and the body together, made with the secret only the two of you hold. Repeat the same recipe on your side and compare.

Compare in constant time. A check that stops at the first wrong character quietly tells whoever is guessing how far they got.

The timestamp is inside the signature

A call captured yesterday cannot be replayed today with a fresh time, because changing the time breaks the signature. Refuse anything older than a few minutes and you are done.

When your server does not answer

A call is tried three times with a widening pause, and each attempt waits ten seconds for an answer. A repeat is only worth making when the failure was on your side of the wire.

When the attempts are over the outcome is written onto the subscription: the code of the last attempt, the reason in plain words and the time. After fifteen failures in a row the subscription switches itself off and names why.

  • Server error or a wait

    Tried again, because the same call may well go through a second later.

  • Not found or refused

    Not tried again. The address will still be wrong in a second, and hammering it helps nobody.

  • Silence

    Counted as a failure after the wait, with no answer to record.

What this does not do

  • Delivery is at least once, not exactly once, and dropping repeats by the id on each call is your side of the bargain. A call that fails every attempt is not kept for a later try.
  • A call is not the object itself. Fields whose names look like a credential are stripped before sending, so an invite code or a reset link never leaves for a third party server.
  • Events are born on our server. Work done on your own computer that never reaches us raises no call at all.
  • A subscription is made by a person signed in with a password, never by a key, and it belongs to the account rather than to one folder. Filtering down to a folder happens on your side.

Check it

Each claim above points at the file that carries it out and the stand that guards it.

The body is signed, and the same code verifies a signature the way you would
apps/server/src/webhooks/webhook-dispatch.service.ts
An address pointing inside a private network is checked before every send
apps/server/src/webhooks/webhook-guard.ts · apps/server/test/webhooks.js
One list of events, and fields that carry a way in are stripped from it
apps/server/src/webhooks/webhook-events.ts
A failed delivery is visible in the account instead of silent
apps/web/test/webhooks-web.js

Questions

What should my receiver answer?
Anything in the two hundreds, as quickly as it can. Do the real work after answering, because a slow reply looks like a failure and earns a repeat.
Can I test without waiting for a real event?
Yes. A test call goes to your address on demand and is marked as a test, so your system does not invent a profile that never existed.
Why did my subscription switch itself off?
Fifteen failures in a row. The reason is written on the subscription, and switching it back on starts the count from zero again.
Does a dead receiver break my work?
No. Sending happens in the background after the action is already done, so a profile that started stays started while your server is down.
How many subscriptions can I keep?
Ten. Each one is our server knocking on an outside address on your behalf, which is the same reason there is a ceiling on keys.

Point one at your own server

Give an address, tick the events and send a test call before anything real happens.