You have a template, and you would like to say “make this month’s invoice for Acme” and get a file back. There are two ways to let Claude do that with iReceipt PRO. They differ in who holds the credential and who runs the loop.
| How they differ | Connector (MCP) | Claude Code with a network secret |
|---|---|---|
| Where | A chat in Claude, or Claude Code | Claude Code in the cloud |
| What Claude calls | MCP tools at mcp.ireceipt.pro | The REST API, directly or through the SDK, at api.ireceipt.pro |
| Credential | OAuth: you sign in and approve once. There is no key to paste | An API key stored on the environment. Claude never sees it |
| One call makes | One document, returned in the conversation | Whatever your code loops over |
| Reach for it when | You want one document, or want a template written or fixed | It is a batch, a schedule, or anything that belongs in a script |
Both spend the same monthly request allowance as a call you make yourself.
Route 1: the connector
iReceipt PRO runs a remote MCP server at https://mcp.ireceipt.pro/mcp.
It uses OAuth 2.1 with dynamic client registration, so the client registers itself and
sends your browser to the dashboard. You sign in, see who is asking and for what, and
press Allow or Deny. The scopes are:
templates:read— list and read your private templates and the public gallery.templates:write— create, update and delete your private templates.templates:render— render, which counts against your monthly requests.offline_access— stay connected without asking you again.
A client that asks for no scope gets templates:read and
templates:render. Administrators have one more, for the public gallery.
Connect it
In claude.ai (custom connectors are on the Free, Pro, Max, Ultra, Team and
Enterprise plans): Customize, then Connectors, then + Add, then
Add custom connector. Give it a name, paste https://mcp.ireceipt.pro/mcp,
and sign in when asked. If the dialog asks which OAuth client to use, choose
Register automatically: dynamic client registration is the mode this server
implements. On Team and Enterprise
an Owner adds it first, under Organization settings, Connectors, Add, Custom, Web. The
steps are Anthropic’s, in
their help article.
In Claude Code:
claude mcp add --transport http ireceipt https://mcp.ireceipt.pro/mcp
claude mcp login ireceipt
claude mcp login runs the OAuth flow from your shell. The /mcp
panel inside a session does the same.
To take access back, open the dashboard’s Agents tab. Each connected agent is listed with its scopes and when it was last used, and Forget revokes the grant and every token issued under it. The agent’s next call is refused and it has to ask for your consent again.
What Claude can do with it
list_templates, get_template, create_template,
update_template, delete_template, validate_template,
get_template_guide, preview_template and
generate_document. The first group is for authoring: Claude can write a
template, render a draft of it and look at the picture, and save it only when it is right.
generate_document is the one that makes the document itself.
It looks like preview_template, and it is deliberately stricter:
- A saved template only. It takes an
id, not raw HTML. -
The data is required.
variableshas no default. A template’s sample arguments are never used as a fallback, so “I forgot to pass the customer” cannot turn into a real invoice for the sample customer. - Gaps are refused, not rendered. Mustache turns a missing value into an empty string. If the template draws a value the data lacks, nothing is rendered and nothing is counted:
The data is missing 1 value that "invoice" draws, so those places would be
blank in the document:
- customer.name
Add them to variables and call again. If you have checked the document yourself, or a
blank is intended, pass allowMissing: true. Nothing was rendered and nothing was counted against the quota.
-
Optional sections are not gaps. A
{{#discount}}…{{/discount}}block the data leaves out is simply not drawn, and the result says so. -
PDF by default. It comes back as an attached file. PNG, JPG and WEBP come
back as an image. The page is the template’s own size unless you pass
formatorsize.
A request in plain words is enough: “Generate the invoice template for Acme Trading,
INV-2026-0187, three lines.” Claude reads the template with get_template
to see which fields it expects, asks you for what is missing, and then calls
generate_document.
One call makes one document. For a hundred of them, use the second route and let code do the looping. Know the difference before you do: the REST API and the SDK have no missing-data check. A value your data lacks is rendered as an empty string, so a script that loops should check its data first.
Renders through the connector are also rate-limited, to 60 in a minute by default, so a looping agent cannot spend a month’s allowance in one go.
Route 2: Claude Code in the cloud, with a network secret
A Claude Code session in the cloud runs in an environment. You can store an API key on it as a network secret. Anthropic’s agent proxy adds the key to requests for the hosts you list, after each request has left the session’s VM, so the key is not in an environment variable and not in a file. Claude can call the API without ever seeing it.
Set it up
- In the dashboard, create an API token. Make it a dedicated one for this environment, so you can revoke it on its own.
- At claude.ai/code, open the environment for editing and select its Network secrets row, then Add secret.
-
Keep the secret type Bearer. Allowed websites:
api.ireceipt.pro. Custom headers: one row. The header name is alreadyAuthorizationand the prefixBearer, and the value is the token. - Select Add. The value cannot be viewed again; to change it, delete the secret and add it again.
Network secrets are available on Pro, Max, Ultra, Team and Enterprise plans. On Team and Enterprise without an organization admin role the form is shorter: one host and a token field. Two things in Anthropic’s documentation are worth acting on. The secret applies in every session that runs in the environment, whoever started it, so do not put it on a shared environment unless everyone who uses that environment may generate documents on your allowance. Once saved it cannot be read back, so keep the token in the dashboard, where you can revoke it. Two smaller points from the same page: a host that has a secret stays reachable even when the environment’s network access is restricted, and requests the environment’s setup script makes never get the secret, because the proxy is only attached after the script has run.
Check that it works
Start a session in that environment and ask Claude to call the API with curl.
Anthropic’s documentation says the API will answer as if the key were in the request.
Note that the command below carries no Authorization header at all. Replace
YOUR_TEMPLATE_ID with the id of one of your own private templates; this makes
one real request, and with a single field filled in the PDF will be mostly blank:
curl -sS -X POST https://api.ireceipt.pro/v1/pdf/private/YOUR_TEMPLATE_ID \
-H 'Content-Type: application/json' \
-d '{"variables":{"invoice":{"number":"INV-2026-0187"}},"size":{"width":796,"height":1126}}' \
-o invoice.pdf -w '%{http_code}\n'
The success status is 201, not 200, and the body is the PDF. With
this curl, a 401 means no key reached the server and a
403 means one did and was not accepted. A 400 “Invalid
template name” means the id does not exist among your private templates.
The authentication guide and
errors and retries go through each status.
From the SDK
npm i @ireceipt.pro/js
The SDK will not run without a key: an empty one throws, and it sends whatever it is given
as Authorization: Bearer …. The real key is not in the sandbox, so give it
a placeholder and let the proxy set the header on the way out:
Save it as render.mjs (it uses ES modules and top-level await) and run node render.mjs:
import { IReceiptPRO } from '@ireceipt.pro/js';
import { writeFile } from 'node:fs/promises';
// Not a real key. The proxy attaches the one stored on the environment.
const irp = new IReceiptPRO('placeholder');
const pdf = await irp.createPdfFromPrivateTemplate(
'invoice',
{ invoice: { number: 'INV-2026-0187' } },
{ width: 796, height: 1126 }
);
await writeFile('invoice.pdf', pdf);
The SDK always sends the placeholder, so through it a missing or misconfigured secret does
not look like the curl case: the API sees a key it does not know and answers
403 “Token invalid”. A 403 can also mean the
monthly allowance is used up or the plan needs an upgrade, so check the dashboard before
you debug the secret.
Wrap that in a loop and one session can render a month of invoices. The SDK retries only what a retry could fix (transport errors, 5xx, 408 and 429); a bad template id or a used-up allowance fails on the first attempt.
The page size differs between the two routes.
generate_document renders at the template’s own page box. The REST API
and the SDK render at A4 portrait, 796 × 1126, unless you pass a
size (the REST API also takes a named format; the SDK does not). A landscape certificate saved at
1126 × 796 comes out right in chat and wrong from a script until the
script sends its size.
Allowed domains on your account are a browser check (CORS), and a script or
curl ignores them, so they do not stand in the way of a cloud session. They are
also not a reason to put a key in frontend code; the authentication guide explains why.
Choosing, and taking it back
Use the connector when a person is in the loop: a document now, or a template to write, look
at and fix. Use the network secret when code is. Splitting the job is ordinary: author the
template in chat with preview_template, then let a cloud session render the
month’s documents from a script.
Neither route hands Claude your key. To take the connector back, press Forget on the Agents tab. To take the cloud route back, delete the network secret from the environment and the token in the dashboard.
generate_document and preview_template each count as one request. A
document that is refused before rendering — missing data, a template that does not
parse, an id that does not exist — costs nothing. A render that fails after it started
is refunded.
What we have not verified. We have not clicked through the claude.ai
connector dialog for this server from start to finish; the steps above are Anthropic’s.
The server implements dynamic client registration (RFC 7591), and we read the dialog’s
Register automatically option as that, but we have not tried every option in it.
For the SDK placeholder, Anthropic’s public documentation says the proxy “adds
the key to requests” for your hosts. We saw a placeholder Authorization
header replaced on another host that had a secret, with both curl and the
HTTP client the SDK uses, but not on api.ireceipt.pro itself. Run the
curl check once before building on it.