Trust

Security and data handling

ProcureOS holds the most commercially sensitive records a manufacturer has: what every supplier quoted, what you last paid, and what you are about to order. This page is written to be forwarded to whoever signs off on new software. Every control described here is one the product actually implements — and the last section is an honest list of what it does not.

Last reviewed July 24, 2026 · SIGNALSTACKS TECHNOLOGIES PRIVATE LTD

Decisions are human, and so is every send

Nish drafts, computes and chases. It does not decide, and it does not transmit.

Nothing reaches a supplier without a click

Every external email — the RFQ invitation, an addendum, a chase reminder, the covering note on a purchase order — is written into a staged-email record and left queued. A person opens the draft, reads it, edits it if they want, and clicks Send. Nish holds no tool that transmits to a vendor; the tool it does hold explicitly refuses to send and says so in its own description.

Budget and award are separate human acts

Raising a case, approving the budget against a budget head, awarding the order and approving the purchase order are four decisions taken by named people, routed by your approval policy and its value bands. There is no auto-award setting, so there is nothing to leave switched on by mistake.

Every action the agent takes is on the record

Each tool call is written as its own row carrying your organisation, the person who asked for it, the tool, the arguments it ran with, the result it returned, its status and the timestamp — and, if it was undone, when. The record is per-organisation and indexed by time, so “who changed this and when” is a query, not an investigation.

Where it is enforced

Staged sends: rfq-service and the shared staged-email path · agent actions: the AgentToolCall record, org-scoped

The maths is computed, not generated

No language model sits anywhere in the compute path for the evaluated comparison or the cost sheet.

Same quotes, same deck, every time

The comparison engine is ordinary code. Normalisation runs in a fixed order — unit basis first, then freight allocated across lines by value, then the vendor’s offered credit priced at your cost of capital, then GST treatment — because each step compounds on the one before it. Run it twice on the same quotes and you get the same ranking, the same evaluated totals and the same L1.

The engine flags rather than guesses

A quote that does not state its payment terms produces a gap to chase the vendor about, never an assumed number. A GST rate that differs from your organisation’s norm is flagged for a human, and the rate the vendor actually stated is the one that applies. Lines the case never asked for do not silently enter a ranking.

Where a model is used, and where it stops

A model is used to read a supplier’s PDF or email into structured quote lines, and to write prose — RFQ text, an email draft, a summary. Once a line is structured, every rupee after that is arithmetic in code. Drafts are for your team to check against the supplier’s original document, which always governs over our summary of it.

Where it is enforced

comparison-service and costing-service import the database and each other — no model client is reachable from either

Your records are scoped to your organisation

Isolation is a property of the schema and the query layer, not a filter someone remembered to add.

Every domain row carries an organisation

Vendors, items, price points, budget heads, rate bases, playbook versions and rows, purchase cases, RFQs, invited vendors, vendor quotes, quote lines, comparison decks, cost sheets, purchase orders, deviation records, agent threads, agent messages, agent tool calls, staged emails, email logs and action tokens all carry the owning organisation as a column, and are read back through that scope.

A new table cannot quietly skip it

The list of organisation-owned models is declared in one file and asserted by a test in the same directory. Adding a table to the schema without placing it in an ownership bucket fails that test, so the isolation rule is enforced at build time rather than by code review.

The scope comes from the session, never the request

The operation wrapper resolves the caller’s organisation and role from their server-side session before any handler runs, and the handler receives that context. An organisation identifier supplied in a request body is not what a query is scoped by.

Where it is enforced

ORG_OWNED_MODELS_INJECTOR in server/injectors/model-injectors.ts, with its own test · credentials resolved in server/framework/authorised-operation.ts

Requesters never see prices

Retrieval respects the seat, on every surface — chat, page and notification alike.

Three seats, one table

A person holds one of three seats. A purchaser runs the desk. A finance approver decides budgets and purchase orders and manages approval policy. A requester raises and tracks their own requests, answers technical questions on their own case and confirms receipt — and that is all. The capabilities of each seat come from a single table, so what the agent offers, what its help lists and what the server will actually run cannot drift apart.

The gate is on the server, before the arguments are read

Whatever is proposed, a caller can only execute the tools their seat holds; the check runs ahead of argument parsing and returns a plain refusal. Ask “where is my bearing order?” as a requester and you get the stage and the dates. The prices are not redacted out of the answer — they are not fetched for that seat, so they never reach the wire.

Where it is enforced

seat table and assertSeatMayUseTool in server/services/nish/tool-kit.ts · priced fields withheld at the service boundary in po-service and case-service

Every figure names its source

A number you cannot trace is a number you cannot defend in a review meeting.

Four sources, and each line says which one it used

Every line on a cost sheet declares where its number came from: an earlier cost sheet, a commodity index anchor, your organisation’s own rate basis, or a stated assumption. A comparison line points back to the supplier’s quote line it was computed from.

Assumptions are labelled and counted

Where the engine had no precedent it says so, marks the line as an assumption, and widens the confidence band accordingly. The sheet reports how many assumptions are still open so nobody signs one without noticing. When a person puts a real number on a line, the generated provenance comes off with it — the sheet does not keep claiming a source that no longer describes the figure.

Where it is enforced

per-line source and confidence bands in server/services/procurement/costing-service.ts

Sub-processors

The named list, not a category list. If a vendor is not here, your data does not reach it.

Sub-processorWhat it doesData it receivesProcessing location
VercelApplication hosting, CDN and serverless compute. Also collects page-performance metrics.Every request to the application: HTTP metadata, IP address, and any request or response body that passes through the app.United States, plus a global edge network.
SupabaseManaged PostgreSQL database and S3-compatible object storage for uploaded documents.All of your records — vendors, items, cases, RFQs, quotes, comparison decks, cost sheets, purchase orders — and the source files you upload.The single region chosen for your deployment.
OpenRouterRoutes drafting and document-reading prompts to the underlying model provider.Prompt text, document excerpts and PDF quote files sent for parsing or drafting, and the model's response.United States.
ResendDelivers transactional mail and the outbound procurement email a person has approved.Recipient address, subject and body of sent emails, plus delivery events.United States.
Trigger.devRuns background work — quote parsing, deadline chases, delivery watch, scheduled digests.Job payloads: record identifiers and the case context a job needs to run.United States.
UpstashRedis used for rate limiting. Optional — the app runs with it switched off.Short-lived counters keyed by identifier and route. No procurement content.The region chosen for your deployment.
GoogleGoogle sign-in (OAuth), where your organisation uses it.Email address, name and profile image returned by the OAuth consent screen.Global.
Microsoft ClarityProduct analytics, heatmaps and session replay.Page views, clicks, mouse movement and rendered page content on the pages it records.United States.
LangfuseTracing for model calls, so a bad draft can be traced to the exact prompt. Optional — disabled when not configured.Prompt and response text for traced calls, with an organisation identifier.United States, unless self-hosted.

Regions are set per deployment and we will confirm in writing which ones your contract runs in. Payments are not listed because billing is switched off — no card details reach us or a payment processor today. We will give notice before adding a sub-processor that receives your procurement content, and this page is where the change appears. To ask what is held about a specific person, or to request deletion, write to privacy@trynishai.com.

Authentication and access

Accounts are provisioned by us, one organisation at a time. There is no public sign-up.

How an account comes into being

You send us the people and the seat each of them should hold, and we seed those accounts. A stranger who finds the login page cannot create one, and an unknown address cannot bootstrap itself into your organisation. Sign-in is Google OAuth or work email and password, whichever your IT prefers.

Passwords

A password is never stored. What is stored is a scrypt-derived key with a random per-user salt, compared in constant time on every sign-in, and repeated failed attempts against an address are throttled.

Sessions

Sessions are rows in the database, not self-contained tokens, so deleting one ends that session on the next request rather than waiting for a token to expire. In production the session cookie carries the browser-enforced __Secure- prefix and is restricted to same-site navigations.

Machine access

Programmatic access uses bearer tokens that are hashed with a server-side secret before storage — the raw token is shown once and never held. Each token carries explicit scopes, belongs to one person in one organisation, expires (ninety days by default, a year at most), and can be revoked. Every call made with one is written to the same per-organisation audit record as any other action.

Browser hardening

Responses are served with content-type sniffing disabled, framing denied outright, and a strict cross-origin referrer policy.

Where it is enforced

scrypt hashing in server/services/password-auth.ts · database sessions in server/auth/session-policy.ts · peppered token hashes in server/services/mcp-token-service.ts · headers in next.config.js

Reporting a vulnerability

If you have found something, we would rather hear it from you than from a customer.

Write to

support@trynishai.com

Put “Security” in the subject. Include what you did, what you saw, and roughly when.

What we commit to

We acknowledge a report within three working days, come back with an assessment and an intended fix window within ten, and tell you when it has shipped. If we disagree that it is a vulnerability we will say why rather than go quiet.

What we ask

Give us a reasonable window before publishing. Stop at proof — enough to demonstrate the issue, not a copy of someone’s quote book. No denial-of-service testing, no social engineering of our staff or our customers’ staff, and no testing against a customer’s live organisation without their written consent. We will not pursue good-faith research that stays inside those lines. There is no bounty; there is credit here if you want it.

Where we are today

The list below is what we do not have. It is here because you would find out anyway, and because a page that only lists strengths is not worth reading.

  • We are not SOC 2 Type I or Type II certified, and no audit is in progress.

  • We are not ISO 27001 certified.

  • No third party has run a penetration test against the product.

  • There is no contractual uptime SLA, and no public status page.

  • There is no data-residency guarantee. Most of the stack above processes outside India, and we will not tell you otherwise to win a pilot.

  • There are no customer-managed encryption keys. Traffic to the site and to every sub-processor is HTTPS, and storage-level encryption is whatever our hosting and database providers apply by default — we have not independently verified it, so we do not name a standard for it.

  • There is no organisation-enforced multi-factor authentication and no configurable idle timeout. Sessions are long-lived and roll forward while you keep using the product; revoking one at the database is the way to end it.

  • Session replay runs on the public site and inside the app without a consent banner today. If that is a problem for your pilot, say so and we will switch it off for your organisation.

  • We do not publish a standard data processing agreement yet. Send us yours and we will work from it.

  • There is no bug bounty programme.

None of this is permanent, and some of it is closer than the rest. If one of these lines is the gate on your pilot, tell us which one and we will tell you honestly whether it is weeks away or quarters away — and put that in writing.

Security questions

support@trynishai.com

Data requests and grievances

privacy@trynishai.com