Developers & APIUpdated 10 Oct 2026

Developers - API keys, webhooks, OAuth & payments

Register products, create scoped API keys (shown once), receive HMAC-signed webhooks, use OAuth for whole products, onboard sub-merchants for payments, and debug with request logs and the live API reference.

Finocket's developer platform lets your own products, scripts and AI tools work your books over a versioned REST API. Everything lives under Developers & API, which you reach from Settings → Developers & API - it is no longer a row in the product menu. Products, scoped API keys, OAuth clients, webhooks, payments onboarding, request logs and a live API reference all live there. Every call is workspace-scoped by row-level security.

The developer portal

Developers is one portal that works on a phone as well as a computer. A row of sections runs along the top: Start, Reference, MCP, Keys, Apps, Logs, Sandbox, Usage, Terms and Support, then the pages you already know: Payments, OAuth clients, Products, Webhooks, API docs and Environment. Every address that worked before still works.

  • MCP gives you the address to point an MCP client at and a client configuration to copy. Send your key as a bearer token. A developer key gets a compact set of three tools - discover, describe and dispatch - unless you ask for the full catalogue. Your key is never filled in for you.
  • Products lists the catalogue by product, generated from the Demystify integration registry, with a page per product, beside the products you register yourself.
  • Apps explains app registration and review and opens the app console (see Publish an app).

Some pages need data that is not switched on yet, and they say so instead of showing a number. Developer accounts are not open, so Sandbox says a sandbox is not available yet, Usage shows nothing rather than a zero, and the MCP page does not yet list which tools your key sees. Terms says the programme terms have not been published. Support helps you prepare a written question to copy into your message; nothing is sent or saved from that page.

How do I get started with the API?

  1. Open Developers - the overview shows your keys, webhooks and recent API activity at a glance.
  2. Register a product under Developers → Products - a named container for what you're building (your app, an internal script, an AI agent). Keys and webhooks hang off it.
  3. Create an API key under Developers → Keys. Pick live or test mode and tick exactly the scopes it needs - from clients:read to tally:write - nothing more.
  4. Copy the key immediately. It is shown once, at creation, then never again. Send it as Authorization: Bearer dmfy_live_… on every request to /api/v1/*.

Writes are idempotent where it matters: creates dedupe on your own external_id or an Idempotency-Key header, so a retried request never acts twice.

What can the API do?

The /api/v1 surface covers the whole business: clients and their ledgers, invoices (create, send, remind, PDF, payments, cancel), payments and refunds, payment links, subscriptions, expenses, items and live stock, sales and purchase orders, CRM (contacts, deals, pipelines, tasks), consent records, partner commissions - plus read-only reports: trial balance, P&L, balance sheet, ageing, GSTR-1/3B/2B/9, day book, Tally XML and more.

Two of those reads are worth knowing the shape of before you build against them. Email engagement returns opens and clicks folded into the same day-by-hour grid the report screen draws, so a dashboard you build yourself cannot disagree with the screen. Opens arrive in a field named opens_unverified, and the reason travels with them in the response rather than living only in our help pages: Apple Mail and company mail scanners fetch a tracking pixel without anyone reading the message, so an open is a hint and a click is the fact. The busiest hour is described, not recommended. No IP address is returned, because none is stored, and nothing is per-recipient - it is an aggregate.

Connected credentials answers which providers a workspace has connected, how each one was connected, whether it is verified and when it was last checked. It never returns a key, a fragment of one, its length or a fingerprint - there is no argument for another workspace, and one with nothing connected answers exactly like one that does not exist. Running several companies? Send X-Company-Id to pick one per request, or pin the key to a company at creation.

Practice records, for workspaces with the services pack switched on, are read-only: /api/v1/practice/bookings (30 days back to 30 days ahead, with each booking's status, service and the draft invoice it was billed on), /api/v1/practice/service-plans (plans and each client's sessions left) and /api/v1/practice/retainers (each retainer with its monthly schedule or deposit drawdown), on the reports:read scope. A booking names its client by id, never by name, email or phone. Billing a booking, selling a pack and starting a retainer's billing stay on the screen. While the pack is off these calls answer not found, and before its setup step they answer that the records are not available, which is different from an empty list.

How do webhooks work, and how do I verify them?

  1. Register an HTTPS endpoint under Developers → Webhooks and pick events - invoice.created, payment.recorded, stock.low and more, or all.
  2. Finocket POSTs JSON with the event name, timestamp and data. Failed deliveries retry with exponential backoff (up to six attempts).
  3. Verify every delivery: read the X-Demystify-Signature header (t=<timestamp>,v1=<signature>), recompute HMAC-SHA256(secret, timestamp + "." + rawBody) with your endpoint's secret, compare in constant time, and reject stale timestamps to block replays.

Events fire however the record was written - through the API, in Finocket itself, on a phone that was offline at the time, from a bank reconciliation, from the till, or when a payment provider confirms one. So a system you have connected learns that a customer paid even when your accounts team typed it in here, which is what lets it lift a suspension on its own. A payment waiting on an approval sends nothing until it is approved; a rejected one never sends.

Developers → Webhooks also shows Recent deliveries: every event handed over, whether it arrived, what the endpoint answered, and how many attempts it took. A delivery that keeps failing stops retrying after about six hours - if the other system was down longer than that, press Resend on the row once it is back.

When should I use OAuth instead of an API key?

When a whole product - not one script - needs access. Create an OAuth2 client under Developers → OAuth clients; it uses the client-credentials grant: exchange client id and secret at POST /api/oauth/token for a short-lived bearer token carrying only the scopes you granted. Revoke the client and its tokens stop working.

Can I collect payments for my own customers?

Yes - Developers → Payments onboards sub-merchants under the aggregator model (powered by Razorpay). Register a sub-merchant, and money settles directly to their bank account - it never passes through your books or Finocket's. You get payment links and status webhooks per sub-merchant.

Where do I debug and explore?

  • Developers → Logs - every API request and webhook delivery attempt, with status and timing.
  • Developers → Reference - a live Swagger playground: authorize with your key and fire real requests from the browser. The OpenAPI spec is at /api/v1/openapi.json.
  • Developers → API docs - the guided walkthrough, including MCP setup so AI agents (like Claude) can use your books as tools.
  • Developers → Environment - the reference list of configuration names the platform uses (names only, never values).

On the phone and tablet apps these pages open in your browser rather than inside Finocket. They are built for a keyboard and a wide screen - keys, webhook URLs and request logs - so the app hands them to the browser instead of squeezing them in.

What are the inbound lead-capture webhooks?

Alongside the outbound webhooks above, Finocket exposes inbound endpoints that turn provider events into leads: telephony (calls and missed calls), inbound SMS, inbound email and WhatsApp. Each endpoint stays switched off - answering “not found” - until its token is configured; the Developers page lists the URL per channel to paste into your provider’s dashboard. See Inbox & capture for the user-side story.

What can the AI/MCP tools reach?

The MCP tool registry covers your whole business - books, GST, invoicing, inventory - and, since the growth release, the CRM chain too: leads, accounts, marketing campaigns, campaign ROI, lead funnel by source, partner earnings, team activity and activation history, plus commission-rule management. It also reads open work-in-progress per work order, and your GST notice register with how far each reply has got. Same permissions as the signed-in user; every write proposes before it commits.

With the services pack on, get_practice_bookings, get_service_plans and get_retainers give your assistant the same read-only view of bookings, service plans and retainers. There is no tool that bills or sells from them.

For outreach audits there is also list_attested_sends: the messages that went out on consent you declared rather than consent a contact recorded themselves. It answers the first question any data-protection review asks - which sends relied on an unverified claim - without reconstructing it from the message log by hand. Blocked sends on a lapsed declaration are included, because those are exactly what you want to see.

Support cases through the API and your AI assistant

Two scopes reach your workspace's support cases. With cases:read a key can list your cases and read one with its public replies and links. With cases:write it can add a public reply, link a case to an issue or a pull request, and reopen a case that was released or is waiting on you, for example when a fix did not hold. Every other status move is made by our support team, and a key can never close, decline or mark a case as a duplicate: those stay human decisions.

What comes back is masked. Reporter names, email addresses and phone numbers are never returned, and neither are internal notes. Your AI assistant gets the same abilities through the MCP tools, with the same limits: it can list and read your cases, reply, link and reopen, and it can never close one. These two scopes are not on the Keys screen's list of boxes yet. Until cases are switched on for your workspace, these calls answer that cases are not available yet.

What the tools deliberately cannot do

Some things are reachable in the app and are not exposed as tools, on purpose - because a tool call has no confirm card and no named human behind it:

  • Approving anything an assistant drafted. Growth-agent campaigns and GST notice replies are approved in the app, by a person. A tool would put a model on both sides of that review.
  • Changing how much an assistant may do unattended. The autonomy setting is not tool-reachable, so an agent cannot widen its own limits.
  • Committing a Tally import, or undoing a completed action. Both are large writes that exist behind a review step. Exporting to Tally is exposed, because it changes nothing.
  • Your personal tax figures. API keys carry business scopes, and there is no tax scope - so your rent, premiums and investment rows are never reachable with a key issued for the books. Ask Mysty inside the app instead.

Nothing here files a return, moves money, or sends a message without the same consent and quiet-hours checks the rest of Finocket applies.

Related: Modules & plans, Usage & activity.

Why doesn't my counter-sales total match the till's Z-report?

It should, and now it does - but only if you add up the right column. A refund at the counter is a credit note, and a credit note carries a positive total, because that is what the document says: it is a real credit for a real amount. It also carries the terminal of the bill it reverses, so it appears in /v1/pos/sales alongside the sales.

So every row carries two fields you should read together. direction is "sale" or "return", and signed_total is the same money with that direction applied - negative for a return. Sum signed_total, never total. Summing total adds refunds to takings instead of subtracting them, so a day is overstated by twice what you refunded.

Cancelled bills are not in the list at all. An exchange that fails part-way cancels its credit note rather than deleting it, so the trail survives - but a reversal that never happened is not money, on this list or on the Z-report. Drafts are excluded for the same reason: nothing was rung up.

Filter by from, to and terminal_id for a date range at one till. For a single register session, take the rows whose cash_session_id is that session: their signed_total adds up to exactly the net figure the Z-report shows for it. The two are built from one definition of what a counter sale is, so they cannot drift apart.

My key was refused. Do I need to upgrade?

Not necessarily, and the response tells you which of three things happened rather than making you guess. All three are a 403, and they need three different fixes.

  • The key was never given that scope. The message names the missing scope. Fix it by issuing a new key with the right scopes ticked - scopes cannot be added to a key after it is made.
  • The plan no longer includes that area. The error code is plan_upgrade_required and the message names the area. The key is fine; the workspace moved to a plan that does not carry it. Changing plan restores it.
  • An administrator switched that area off for the workspace. The code is the plain forbidden and the message says so: no plan change lifts this. Buying a bigger plan will not help, and we will not suggest it. Ask whoever administers the workspace to switch the area back on.

A workspace owner simply hiding an area from their own menu does not refuse your key. Tidying a menu and cutting off an integration are different acts, and only the second one is deliberate.

The AI/MCP tools answer the same way, in the same three flavours, for the same reasons - so a tool call and a REST call cannot disagree about whether you are allowed in.

Paise or rupees?

Money fields are not all the same unit, and getting it backwards overstates an amount a hundredfold. The reference states, in one place, which fields are whole paise and which are rupees - check it before you write the first integer.

The reference is checked against the API itself on every build, address by address and call by call. A call shipped without documentation, or documented without being shipped, stops the build rather than reaching you.

Does this work offline?

Frequently asked questions

Is the API key shown again after I create it?

No. The key is displayed exactly once, at creation, and only a masked prefix is kept for display. Copy it into your secret manager immediately. If you lose it, create a new key with the same scopes and revoke the old one.

What's the difference between live and test keys?

Test-mode keys let you build and verify your integration without touching production behaviour; live keys operate on your real books. Both respect the same scopes and row-level security. Start in test mode, switch the key when your integration is ready.

How do I know a webhook really came from Finocket?

Every delivery carries X-Demystify-Signature. Recompute the HMAC-SHA256 of timestamp.rawBody with your endpoint's secret and compare it to the v1 value using a constant-time comparison. Also reject timestamps older than a few minutes to stop replays.

Where can I see my webhook's signing secret again?

You can't. The secret is shown once, when you add the endpoint, and is stored encrypted afterwards. Copy it then. If you lose it, delete the endpoint and add it again to get a new one.

Can an AI assistant use my books through this API?

Yes, and there is a one-tap way to do it. On the API keys screen, Connect Claude or Connect ChatGPT issues a key for you and shows the address to paste in - no choosing scopes. The same API is also exposed as an MCP server at /api/mcp if you would rather wire it up yourself with a key you built.

What can a connected assistant actually do with my books?

It can read, and only read: your clients, invoices, payments, expenses, items, stock, orders, reports and GST figures. It cannot create an invoice, change a record, record a payment, or message a customer - those permissions are not on the key at all, so there is nothing to switch off. Some things stay private even from a connected assistant: your inbox, your saved logins for other services, staff and payroll records, and partner payouts.

How do I disconnect an assistant?

Revoke its key on the API keys screen. It stops working on the assistant's very next question - there is no waiting period and nothing cached. The connection is listed there with what it can see and when it last looked, so you can tell whether an assistant is still being used before you remove it.

Why can I not give Claude permission to send invoices?

Deliberately. A one-tap connection is meant to be safe to grant without reading a permissions list, so it never includes anything that changes your books or reaches your customers. If you genuinely need an integration that can write or send, build a key yourself further down the same screen, choose those scopes on purpose, and name it so you recognise it later.

Can my API key read another company's data?

No. Every request is bound to your workspace by row-level security, and within it to one company - the pinned one, your default, or the X-Company-Id you send. A company the key can't reach is refused.

Does every tool actually check my key's permissions?

Now it does. Two of them did not: partner earnings and marketing campaign returns carried no permission at all, so any key of yours could read them regardless of what you granted it - including a key you had issued to an outside integration for something unrelated. Partner earnings now needs the partners permission and campaign returns needs the reports permission. If a key you already issued reads either one, grant it that permission or the call will be refused. Nothing else changed, and no data was ever reachable outside your own workspace.

Can my existing key read online baskets and checkouts?

No, and that is deliberate. Online baskets and checkouts sit behind their own permission - a separate pair for reading and for writing - so no key issued before they existed can reach them. A basket carries the shopper it belongs to, the delivery address they picked and the way they chose to pay, and a key you issued for something else should not quietly acquire all of that. If you want an integration or a shopping agent to work a basket, issue it a key with those permissions on purpose.

Can an integration bring a customer's old books in for them?

Yes. There is now an imports API: start an import, ask for upload links and write the file straight to storage, then poll the import to watch it move from received to reviewed to imported, and read every row with what became of it. Nothing is ever sent through the API itself, so a 60 MB export is fine, and an upload that drops picks up where it stopped rather than starting again. It sits behind its own pair of permissions, so no key issued before today can reach it.

Can a key approve what an import puts in my books?

Only if you gave it that permission by name. Reading imports and starting one are two permissions; approving rows is a third, and the first two do not include it - so a key you issued to an outside integration to bring files in cannot decide what those files end up putting in your books. A key without it is told so up front: when it reads an import, approving is reported as unavailable rather than left to fail. A row flagged as needing a person is never approved by a key at all, whatever permissions it holds, and every approval is recorded as having been made by a key rather than by you.

Can an assistant approve an import?

No, and it cannot be given that permission either - it is refused for connected assistants outright, not merely left switched off. An assistant can be told what an import is waiting on; deciding what lands in your books stays with you or with a key you issued on purpose.

Can an integration mark an online order as paid?

No. Starting a payment, confirming one, failing one and completing an order are refused on this API by name, whatever permissions the key holds - only a verified message from the payment provider can say that money arrived, and the order is created by the step that also checks the books balance. What a key with the write permission can do is the shopper's own progress: set the delivery address, choose a delivery option, choose how to pay, and cancel. A checkout that already has a payment in flight refuses even those.

How does a payroll run from ashr.work get into my books?

As one balanced journal entry, posted through this API with a key that has the journals write permission. The run's lines can put gross salary, employer PF and ESI, the PF, ESI, professional tax and TDS you deducted, and net pay each on its own ledger. The entry carries the source product and the run's own id, so if the same run is sent again Finocket returns the entry it already posted instead of booking the salaries twice. Employees can be kept as a directory that names each person on a run; they are records, not Finocket logins.

Related articles