Quaderno MCP server
48 operations0 webhooks
Calculate tax, issue invoices and credit notes, and manage customers, products and webhooks.
Try Quaderno with your agent
Connect Quaderno, then paste this into Claude, ChatGPT or Cursor. For ideas from other apps, see the use cases.
Using Corsair, show me what you can do in Quaderno on my account, then run one read-only example and show me the result.
Quaderno tools and triggers
Tools are what your agent can do in Quaderno through Corsair's MCP server. Triggers are the Quaderno events a routine can start from.
Proformas
- AcceptWrite
Marks a proforma accepted. A state change the customer would normally trigger; reversible with `proformas.revert`.
proformas.accept
- ConvertWrite
Converts an accepted proforma into a real invoice, which **consumes an invoice number and cannot be undone**. Only a proforma in the accepted state can be converted. Returns the new invoice under `invoice`.
proformas.convert
- CreateWrite
Creates a proforma. Unlike an invoice this is not a tax document, so it does not consume an invoice number.
proformas.create
- DeclineWrite
Marks a proforma declined. Reversible with `proformas.revert`.
proformas.decline
- DeliverWrite
Emails the proforma to the address on file for its contact. A GET that mutates, so it is a write and is never replayed. Answers `delivered: true`.
proformas.deliver
- GetRead-only
One proforma by id, with its lines and the state it was accepted or declined in.
proformas.get
- ListRead-only
Proforma invoices, newest first, as a bare array. A proforma is not a tax document, so it carries no invoice number.
proformas.list
- RevertWrite
Puts an accepted or declined proforma back to its open state.
proformas.revert
- UpdateWrite
Changes a proforma. Only the id is required. An accepted or invoiced proforma cannot be changed. It stays a proforma until `proformas.convert` issues a real invoice.
proformas.update
Invoices
- CreateWrite
Issues an invoice and **allocates a document number**, which is not recoverable: invoices cannot be deleted, only voided. Passing `payment_method` records a full payment immediately and marks it paid. Needs a `contact` id and at least one line item.
invoices.create
- DeliverWrite
Sends the invoice by email to the address on file for its contact, using the account template. A **GET that mutates**, so it is a write here and never replayed: delivering twice emails twice. The contact needs a valid email. Answers no document, only `delivered: true`.
invoices.deliver
- GetRead-only
One invoice with its lines, taxes and payments. An unknown id answers 401 rather than 404.
invoices.get
- ListRead-only
Invoices, newest first, as a bare array. Filter by date, state, contact or processor id, search with `q`, and page with `created_before`.
invoices.list
- Mark UncollectibleWrite
Marks an unpaid invoice as bad debt. Reversible by recording a payment later, unlike a void.
invoices.markUncollectible
- Record PaymentWrite
Records a payment against an invoice; reaching the total marks it paid. This creates a real financial record, not a note.
invoices.recordPayment
- UpdateWrite
Changes an invoice. Only the fields you send are changed. An issued invoice is legally immutable: Quaderno then accepts only `notes`, `payment_details` and `tag_list`, so correct anything else by voiding it and issuing a new one.
invoices.update
- VoidDestructive
Reverses an invoice the way tax law requires. It cannot be deleted: voiding records an `offset` payment for the full amount and issues a credit note beside it. `void_reason` is required and the API answers 422 without it.
invoices.void
Credits
- CreateWrite
Issues a credit note against an existing invoice, by `invoice_id`, and records the refund. It credits the whole invoice unless `credited_amount` is given. It consumes a document number and cannot be deleted, only voided.
credits.create
- DeliverWrite
Emails the credit note to the address on file for its contact. A GET that mutates, so it is a write and is never replayed. Answers `delivered: true`.
credits.deliver
- GetRead-only
One credit note by id, with its lines, payments and the document it credits.
credits.get
- ListRead-only
Credit notes, newest first, as a bare array. A voided invoice leaves one of these beside it.
credits.list
- UpdateWrite
Changes the administrative fields of a credit note: `notes`, `payment_details` and `tag_list`. Amounts, lines and the customer are immutable once it is issued.
credits.update
- VoidDestructive
Voids a credit note. `void_reason` is required, exactly as for an invoice.
credits.void
Contacts
- CreateWrite
Adds a customer. `first_name` is required, and holds the company name for a `company`. Give an `email` if documents will be delivered to this contact.
contacts.create
- DeleteDestructive
Removes a customer. Quaderno refuses with 422 while the contact still has documents attached, so invoices must be voided first. Answers 204 with no body.
contacts.delete
- GetRead-only
One customer by id. An unknown id answers **401**, not 404, with “Unauthorized access or contact does not exist”; the plugin reports it as `not_found_or_denied`.
contacts.get
- ListRead-only
Customers, newest first, answered as a bare array. Search with `q` and page with `created_before`; `next_created_before` carries the next cursor.
contacts.list
- UpdateWrite
Changes a customer. Fields left out are left unchanged by the API, not cleared.
contacts.update
Products
- CreateWrite
Adds a product. `name`, `code` and `unit_cost` are required, and `kind` is `one_off` or `subscription`, not the value the spec’s example suggests.
products.create
- DeleteDestructive
Removes a product. Existing documents keep the line they were issued with, so past invoices are unaffected.
products.delete
- GetRead-only
One product by id, with its price, tax class and the currency it is sold in.
products.get
- ListRead-only
Your product catalogue, newest first, from the `/items` route. A bare array; page with `created_before`.
products.list
- UpdateWrite
Changes a product. Existing documents keep the line they were issued with, so past invoices are unaffected.
products.update
Receipts
- CreateWrite
Issues a receipt for a sale that is already paid, so `payment_method` is required. Like an invoice, it consumes a document number and cannot be deleted or updated, only voided.
receipts.create
- DeliverWrite
Emails the receipt to the address on file for its contact. A GET that mutates, so it is a write and is never replayed. Answers `delivered: true`.
receipts.deliver
- GetRead-only
One receipt by id, with its lines, payments and the invoice it settles.
receipts.get
- ListRead-only
Receipts, newest first, as a bare array. Filter by a `date` range or `contact`, and page with `created_before`.
receipts.list
- VoidDestructive
Voids a receipt. `void_reason` is required, as for an invoice.
receipts.void
Jurisdictions
- GetRead-only
One tax jurisdiction by id, naming the country and any region whose tax rules apply.
jurisdictions.get
- ListRead-only
Every tax jurisdiction Quaderno knows, about 290 rows, as a bare array. Verified live: this route ignores `limit` and always returns the full list.
jurisdictions.list
Tax Codes
- GetRead-only
One tax code by its identifier, such as `standard`.
taxCodes.get
- ListRead-only
The tax codes available on the account, as a bare array. This route honours `limit`, unlike `jurisdictions.list`.
taxCodes.list
Authorization
- AuthorizationRead-only
Which account this key belongs to: `identity.href` is that account’s base URL, so this is how a caller finds the subdomain to pass as `account`. Also returns the default API version.
authorization
Ping
- PingRead-only
Checks that the key and account name are valid. The docs say it does not consume an API call. Answers `{"status":"OK"}`.
ping
Tax Ids
- ValidateRead-only
Checks a VAT or tax number against the country’s registry. `valid` is true or false, or null when the registry could not be reached, which does not mean the number is invalid.
taxIds.validate
Tax Rates
- CalculateRead-only
The tax rate Quaderno would charge for a customer country and tax code, with the resulting total. `tax_code` and `amount` are required from API version 20210316, which this plugin targets.
taxRates.calculate
Transactions
- CreateWrite
Records a sale or a refund in one call: it creates the document and its payment together, which is what distinguishes it from `invoices.create`. The body is not an invoice body: the buyer is `customer`, each line carries its total as `amount`, and `payment.method` is required. A real financial record.
transactions.create
Webhooks
- ListRead-only
The webhook subscriptions on the account, with the events each one receives. Read only here: this plugin registers no inbound handler. The signing secret (`auth_key`) is left out of the result.
webhooks.list
Connect Quaderno to Claude, ChatGPT or Cursor
- 1
Connect Quaderno in Corsair
Add your Quaderno API key once in Corsair. Corsair stores the credential encrypted and makes the Quaderno API calls for your agent, so it never goes into a prompt or a config file. Connect Quaderno
If your link lets the agent add apps, you can skip this: it gives you a sign-in link the first time it needs Quaderno. On a ChatGPT personal plan, connect Quaderno here first.
- 2
Add Corsair's MCP server to your agent
Every client uses the same address:
https://mcp.corsair.dev/mcpOpen Customize → Connectors → Add custom connector, paste the address, then select Connect.Add a custom MCP server with the address and choose OAuth. Personal plans get read tools only.Add to CursorOr add this to~/.cursor/mcp.json. Cursor opens Corsair to sign in the first time it connects.{ "mcpServers": { "corsair": { "url": "https://mcp.corsair.dev/mcp" } } }Run this, then run/mcpin Claude Code to sign in.claude mcp add --transport http corsair https://mcp.corsair.dev/mcpCodex, Gemini CLI, VS Code, Zed and other clients with OAuth sign-in work the same way. Clients without it, such as GitHub Copilot's coding agent, use a link's own address and an API key. Setup for every client
- 3
Sign in and choose what needs your approval
Your client opens Corsair to sign in. Pick a link: the apps your agent can use and a mode that decides what it may do without asking. In the default Cautious mode, Quaderno's read and write operations run right away and its 5 destructive operations wait for your approval. Strict mode asks before every write and refuses destructive operations, and Read mode allows reads only.
FAQ
Install corsair and @corsair-dev/quaderno, add the Quaderno plugin, and connect with an API key. Then call methods like corsair.quaderno.api.authorization() from your app. Corsair keeps each tenant isolated.
Yes. Quaderno requires an API key from your Quaderno account or developer dashboard. Create credentials with access that matches what you automate, then paste them into Corsair or connect through managed auth in Hub.
Yes. One Corsair client can hit Quaderno, GitHub, Notion, Stripe, and the rest. Trigger Quaderno from a webhook, push updates to Slack, or chain actions across plugins. Same tenant context across integrations, plain TypeScript.
Teams use Corsair for calculate tax, issue invoices and credit notes, and manage customers, products and webhooks. Common builds include sync jobs, admin tooling, and agents that call Quaderno APIs from your backend.
The SDK is open source. Self-host and you pay Corsair nothing for the integration layer. Hub bills for hosted auth and execution, not per Quaderno API call. Hub has a generous free tier. For hobby projects you can probably run the whole thing on free. Paid plans start to matter with more tenants or heavier traffic.
We maintain @corsair-dev/quaderno in the open repo. When Quaderno ships API changes, upgrade the package. Your call sites stay typed. You should not need to rewrite the integration layer each time.
No. Corsair does not read your Quaderno data or hold individual access credentials. Credentials stay in your database. API calls run on your instance. We do not store Quaderno data on your behalf.
Yes. Add https://mcp.corsair.dev/mcp as a custom connector or MCP server in Claude, ChatGPT, Cursor, VS Code, Claude Code, Codex or any client that supports remote MCP servers with OAuth sign-in, then sign in to Corsair. On ChatGPT personal plans, custom servers currently get read tools only.
Yes. Put Quaderno on a link in Strict mode and every write waits for your approval, while destructive actions are refused. The default Cautious mode asks only before the 5 destructive Quaderno operations. You can change a link's mode at hub.corsair.dev/me.