Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.usehasp.com/llms.txt

Use this file to discover all available pages before exploring further.

What is a Hasp App?

A Hasp app is a static HTML/JS bundle that runs in the browser and calls the Hasp Data API to read and write structured data. There are two app types:
  • Utility Apps — static tools with no server-side data (calculators, converters, reference tools)
  • Workflow Apps — data-driven apps that store records via entities and the Data API
This documentation covers Workflow Apps.

Architecture

Your app runs on the same origin as Hasp — no CORS needed. Authentication is handled by Hasp — your app never implements login. The SDK reads appId from window.__HASP__ — never hardcode it. All Data API calls go through the SDK — never use raw fetch() for those.

Two identifiers: appId and app URL

Hasp uses two different identifiers for the same app, and each has a specific purpose:
IdentifierExampleWhere you see itWhen to use it
appId (ULID)01JA7QG2...window.__HASP__.appId, X-Hasp-AppId header, outbound webhook app_id fieldSDK requests, webhook handlers, anywhere the API contract requires a stable machine identifier
App slugtask-trackerThe /apps/task-tracker/... URL in the admin UI, shared links, bookmarksNavigation, linking, anything a human reads
The ULID is frozen per app — it never changes, even if the owner renames the app. The slug can change when an admin renames the app. Old URLs (both the previous slug AND the ULID form /apps/{ulid}/...) continue to resolve automatically.
Common mistakes:
  • ❌ Storing the admin URL in your integration database — store appId instead
  • ❌ Passing the slug to the SDK — the SDK reads appId from the bootstrap
  • ❌ Parsing the URL to extract an identifier — use window.__HASP__.appId

Building Your First App

1. Design your schema

Decide what data your app needs to store. Each concept becomes an entity (like a database table), and each property becomes a field. For example, a task tracker might have one entity:
EntityKeyFields
Taskstaskstitle (text, required), status (select: open/done), due_date (date)
See Field Types for all available types.

2. Write your app

Load the SDK and use it to read/write records:
<!DOCTYPE html>
<html>
<head>
  <title>My App</title>
</head>
<body>
  <script src="https://sdk.usehasp.com/v1.js"></script>
  <script>
    const sdk = new HaspSDK();

    async function init() {
      const bootstrap = await sdk.getBootstrap();
      const canEdit = ['editor', 'admin'].includes(bootstrap.role);

      const result = await sdk.listRecords('tasks', { sort: 'due_date:asc' });
      console.log(result.data);
    }

    init();
  </script>
</body>
</html>
See SDK: Records for the full CRUD reference.

3. Set up your schema in Hasp

  1. Log in to app.usehasp.com
  2. Click New App, give it a name, and choose Workflow App
  3. Open the Schema Builder and create each entity with its fields

4. Upload your app

Drop your HTML/JS/CSS files directly into the upload area (or zip them first). Your app must have an index.html at the root.

5. Publish

Click Publish to make your app live.

What NOT to Do

  • Never hardcode appId — the SDK reads it from window.__HASP__ automatically
  • Never call fetch() directly for Data API requests — always use the SDK
  • Never implement authentication — Hasp handles login/session
  • Never use offset pagination — always use cursor-based pagination
  • Never include a backend — Hasp apps are static; the Data API is your backend