Build an app
An app is a service you run anywhere, in any language, that a store installs. It can read and write through the admin API, receive webhooks, answer Hypha mid-flow (payments, shipping rates, search), and add blocks and pages to the admin and elements to the storefront. Payment providers, search engines, carriers, ERPs and marketplaces are apps.
Choose an app for anything a third party runs as a service, anything not written in Rust, or anything a store should install without rebuilding its API. For code compiled into the API itself, see spores.
The manifest
Section titled “The manifest”An app describes itself in a JSON manifest, served at a public URL. Its URL is the app’s OAuth client ID.
{ "key": "app_reviews", "name": "Reviews", "version": "1.0.0", "app_url": "https://reviews.example.com", "redirect_uris": ["/oauth/callback"], "privacy_url": "https://reviews.example.com/privacy", "scopes": ["products:read", "orders:read"], "webhooks": { "url": "/hypha/webhooks", "events": ["order.placed", "product.*"] }, "extension_points": [], "admin": { "blocks": [{ "id": "summary", "target": "product.details", "url": "/hypha/blocks/product" }] }}Relative URLs resolve against app_url. Hypha checks every rule and reports each problem
with its path; the JSON Schema
lets an editor check it as you type. Besides webhooks and blocks, a manifest can declare
extension_points, admin pages and actions, storefront elements, custom_fields of
its own, and settings staff fill in.
Installing: OAuth 2.1
Section titled “Installing: OAuth 2.1”- Staff click Install app in the admin, which opens your app’s
/install?api=<the store's API>. - Your app sends the browser to the store’s
/oauth/authorizewith PKCE. Staff see the app’s name, its scopes and why it wants each one, and approve. - Your app exchanges the code for tokens: an access token for an hour and a rotating refresh token for 30 days. The first exchange also hands over the app’s signing secret, once.
@hyphacommerce/app does all of it: createAuthorizationUrl, exchangeCode, and a
HyphaClient that refreshes tokens on its own (once, even across processes sharing an
installation) and is typed with the admin API’s paths.
Webhooks
Section titled “Webhooks”Hypha sends events from its outbox, signed with your app’s secret (Hypha-Signature), with
retries on a schedule. Each delivery carries the event’s ID and its own (Hypha-Event-Id,
Hypha-Delivery-Id); give webhookHandler a dedupe store to drop repeats.
import { webhookHandler } from "@hyphacommerce/app";
export default webhookHandler({ // One secret per installation: look it up by the store the delivery comes from. secret: async ({ store }) => secretFor(store), async onEvent(event) { if (event.type === "order.placed") await thankBuyer(event.subject.id); },});An app only gets events about what its scopes let it read, and personal data in them only
with the matching customer_data:* scopes.
Extension points
Section titled “Extension points”An extension point is a synchronous call Hypha makes to your app in the middle of a flow, with a typed request and a typed answer, a timeout and what happens when the app fails:
| Point | When |
|---|---|
payments.start, payments.status, payments.capture, payments.void, payments.refund |
A cart’s payment and what staff do with it |
shipping.rates |
Quoting shipping for a cart |
search.query |
A storefront search, when the store uses the app’s engine |
admin.action |
A button the app added to the admin |
import { defineExtensionHandler, extensionHandler } from "@hyphacommerce/app";
const rates = defineExtensionHandler("shipping.rates", async (request) => ({ rates: [ { service: "express", name: "Express", amount: { amount: 990, currency: request.currency } }, ],}));
export default extensionHandler({ handlers: [rates], secret: SECRET });The types come from the extension points reference. Every call is logged, and staff can see each app’s calls in the admin.
The admin and the storefront
Section titled “The admin and the storefront”- Blocks are small UI trees your app returns as JSON (a documented format, rendered by the admin with its own components) on targets such as an order’s payment card.
- Pages are full pages of yours, embedded in the admin and talking to it through the
app bridge (
@hyphacommerce/app-bridge), with session tokens to know which staff member is looking. - Storefront elements are web components a storefront loads, such as a payment form,
mounted with
@hyphacommerce/storefront-elements.
Examples
Section titled “Examples”- app-stripe: payments through the
payments.*points, a block on orders and a card form on the storefront. - app-meilisearch: the storefront’s
search on Meilisearch, through
search.query.