Return a leave balance to an employee
A customer asks “How many vacation days do I have left?” Your application checks their session, sends the question to your activated Studio flow, and reads their balance from your HR service. If that service returns 17 days for 2026, the customer sees “You have 17 vacation days remaining for 2026.” The number comes from the returned employee record. The model selects the action; it does not invent the balance or authorize access to another employee.
Prepare the flow in Studio
Follow Studio first decision to import the browser demo's leave tools and activate your project flow. The example supports get_leave_balance with one leave_type: vacation, sick, parental, or unpaid. It deliberately does not execute other tools, including leave writes.
Open Ship and choose Download customer application. Save the file as leave-assistant.mjs. It includes your current project, flow and engine address. It contains no key, user session or fictional employee database. The same source is in the repository at platform/sdk/examples/leave-assistant/server.mjs.
Connect your existing customer services
Run the example with Node.js 20 or newer on your backend. Set these variables through your secret manager or local shell; keep credentials out of browser code, source control and logs:
| Variable | Value |
|---|
SILIQUN_ROTOR_KEY | Your project's API key |
CUSTOMER_SUPABASE_URL | The Supabase host that authenticates your customers |
CUSTOMER_SUPABASE_ANON_KEY | That application's publishable/anon key, not its service-role key |
CUSTOMER_HR_URL | Your HR service's HTTPS base URL |
SILIQUN_ROTOR_CLIENT | A downstream customer reference registered in this Studio project, when required |
If using the repository file instead of Ship's download, also set SILIQUN_ROTOR_URL, SILIQUN_ROTOR_PROJECT and SILIQUN_ROTOR_FLOW. The optional client reference is selected by your backend configuration, not supplied by the employee. Engine usage remains attributed to the project key and, when configured, that registered customer reference.
Your HR service must implement this read-only endpoint:
GET /me/leave-balance?leave_type=vacation
Authorization: Bearer <the customer's access token>
It must verify the session and enforce employee and employer permissions. Return 401/403 when the customer cannot access this balance. A successful response has this shape (illustrative values, not live employee data):
{"employee_user_id":"<authenticated user id>","leave_type":"vacation","remaining_days":17,"period":"2026"}
Use /me, with identity from the verified session. Do not accept an employee or employer ID from the model. The application also checks that the returned employee matches the verified user. Adapt the readBalance function to your existing authorized data layer if your service uses another contract.
Run the complete application
node leave-assistant.mjs
It listens only on 127.0.0.1:8791. Connect it behind your application's existing authenticated backend. From a local terminal with your customer's access token in CUSTOMER_ACCESS_TOKEN:
curl --fail-with-body http://127.0.0.1:8791/ask \
-H "Authorization: Bearer $CUSTOMER_ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
--data '{"question":"How many vacation days do I have left?"}'
Render the response's text as text in your chat or employee portal. An answered response includes the balance and engine usage for your backend. Keep usage details in your operator view; the employee needs the answer.
Handle missing details and refusals
An ask response contains a question to show the customer. Their next request must include the missing leave type, for example “Show my vacation balance.” A refused or unresolved response returns a readable message without calling HR. Invalid arguments, extra calls, unsupported tools, mismatched employee records and customer permission failures also stop the handler.
The project key goes only to the engine. The customer token goes only to your identity service and HR service. HTTPS is required for remote service addresses; loopback HTTP is supported for local development. This example does not connect Slack, perform a write, or register an MCP server on the hosted engine.