Build on JuhJuh
Developers

Build on JuhJuh

Build software that watches work happen and takes part in it. Events, permissions, delivery and rich messages for third-party apps.

Build on JuhJuh

JuhJuh is where work is described, worked on and shipped: tickets, chat, agent runs, repositories, pull requests. The platform API lets your own software watch that happen and take part in it.


What you can build

Notifiers. Tell a room, a pager, or a spreadsheet when a ticket moves, a build breaks, or an agent finishes. The stream covers the whole lifecycle, so you can answer "what happened to this piece of work" end to end rather than stitching together three separate feeds.

Assistants in chat. Post a card with buttons, handle the click, update the card in place. The round-trip is a few lines and the result looks native.

Two-way integrations. Mirror tickets into another tracker, open a pull request when something is approved, comment back when a deploy lands. Your app gets its own identity, so its writes are attributed to it — not to whichever employee's credential it borrowed.

Reporting and audit. Read tickets, pull requests and reviews over the API on your own schedule and build whatever view your organisation needs.

Pick a transport

Both transports carry the identical JSON body, and an app can hold subscriptions on both. Choose on how your service is deployed, not on what it does.

Socket Webhook
Who dials whom your app connects out to us we POST to your URL
Needs a public URL no yes, HTTPS
Needs an inbound firewall rule no yes
How you trust the payload the connection is authenticated verify the HMAC signature per request
While your app is down frames are missed retried for about 4 hours
Buttons on cards handled on the same connection needs a separate response path
Best for long-running services, anything that can hold a connection serverless functions, restricted egress, existing webhook plumbing

Start with the socket. It has less to get wrong: no certificate, no public endpoint, no signature to verify, and card interactions come back on the same connection you are already reading. Move to webhooks when your app cannot hold a connection open — a function that only exists while it is handling a request, for example.

Neither transport is a database. Delivery is at-least-once and unordered. Events tell you that something happened; the REST API tells you what is true now. Every reliable integration reconciles against the API. See delivery semantics.

Five-minute quickstart

1. Get a token

An admin of your workspace opens Settings → Apps & Bots, creates an app, grants it scopes, and copies the token. It starts with jjb_ and is shown once — there is no way to read it again, only to issue a new one.

Grant the fewest scopes that work. An app that only posts to chat and reads tickets asks for chat:write, tickets:read and events. Read never implies write and there is no wildcard — see scopes.

2. Install the SDK

bash pip install juhjuh

The SDK is optional. Everything below is plain HTTPS and a WebSocket, and the raw shapes are documented so you can implement them in any language.

3. Say hello

```python from juhjuh import JuhJuhClient

api = JuhJuhClient("jjb_example_not_a_real_token") print(api.me()) ```

You should see the app's own identity and the scopes it was granted. If this returns a 401, the token is wrong or was revoked; a 403 means the token is fine but lacks the scope for the call.

4. Listen

```python from juhjuh import SocketApp

app = SocketApp("jjb_example_not_a_real_token")

@app.on("ticket.status_changed") async def moved(event): ticket = event.data["ticket"] print(ticket["key"], "is now", ticket["status"])

app.run() ```

Nothing arrives until you subscribe:

python api.create_subscription(events=["ticket.status_changed"], transport="socket")

An empty event list means no events, never all of them. Name what you want.

5. Say something

```python from juhjuh import cards

api.post_message( channel_id, card=cards.card( cards.header("Ready for review"), cards.section("JUJU-412 moved to review."), cards.actions(cards.button("Approve", action_id="approve", value="JUJU-412")), ), ) ```

Your app only sees channels it has been added to, and can only update messages it posted itself. Handling the button press is in cards.

Limits

Limit Value
Requests per app 120 / minute
Events per app 10,000 / hour

Over the request limit you get 429 with a Retry-After header — wait the number of seconds it names rather than retrying immediately. These numbers may go up without notice; a reduction gets 90 days' notice.

Getting help

  • developers@juhjuh.com — contract questions and breakage reports. Ask to join the breaking-change notification list.
  • Delivery health is on the workspace's Apps & Bots page. It is the first place to look when deliveries stop: a subscription that failed for a full day is switched off automatically, and it says so there.