How Developers Create Invoices With the REST API
· 5 min read
You already have the data. A row in your database says a project closed, or a subscription renewed, or a job finished. You should not open a browser and retype any of it. You should fire one call and have an invoice ready to send.
Here is how that actually goes, step by step, using the automated invoicing API and, if you prefer, the MCP server that lets an assistant drive the same endpoints.
Step 1: Get a key and decide what triggers an invoice
Sign in on the sender side with a magic link or Google, then generate an API key. The recipient never touches any of this. They never get an account, they never log in. That split matters for what you build: your code is always acting as the sender.
Before writing a line, pin down the trigger. A closed deal in your CRM. A webhook from a payment event. A cron job on the first of the month. The API does not care what fires it. It cares that you hand it clean data when it does.
Step 2: Create the draft
The first call creates an invoice in Draft status. You pass the recipient, your line items, pricing, currency, and payment terms. The response gives you back an invoice ID you will use for everything after.
A few fields lock the moment the invoice is issued and never change: the invoice number, the issue date, your sender details, and your bank details. If you want control over how numbers read, set your format before you start issuing. A sequence like INV-2024-0117 that increments cleanly will save you an audit headache later. If you are deciding on a scheme, the notes on invoice numbers that stay sequential are worth a read first.
Step 3: Build the line items
Line items, pricing, discounts, currency, payment terms, and the due date are sender-only fields. Your code owns them. The recipient cannot edit them from the link; if they want a change they comment, and you decide. So get them right in the payload.
Each line item carries a description, quantity, and unit price. If you bill tax, calculate it per line and include it. The API stores what you send; it does not guess a VAT rate for you. If you need the math, the method in calculating tax on a line item maps directly onto what you push through the request.
Step 4: Issue and get the share link
When the draft is correct, issue it. Status moves to Sent, the locked fields freeze, and you get back a private link. That link is the whole point. You hand it to the recipient and they open the invoice directly, no PDF attachment, no sign-up.
From the link the recipient can add a PO number, fix their billing entity and billing address, set an AP contact, forward the invoice to accounts payable, comment, and pay by card if you have connected Stripe. The PO and billing fields are theirs to edit. You get notified, and you can revert anything that looks wrong. This is the collaboration that cuts out the email loop, and it happens whether you created the invoice in a browser or through letting your customers edit their own invoice.
Step 5: Track status without polling blindly
Read the invoice back and you get its current status: Draft, Sent, Viewed, or Paid. Viewed tells you the link was actually opened, which is the signal you want before you send a reminder. Chasing an invoice nobody has looked at just annoys people; checking first is the whole idea behind confirming an invoice was opened before you chase it.
One thing to build around: there is no approve-for-payment button and no formal approve/decline workflow. The recipient cannot mark an invoice approved. They pay, or they report a payment they made outside the card flow, and status moves to Paid. Once it is Paid, recipient edits stop. Design your automation to watch for Paid, not for an approval event that does not exist.
Step 6: Handle edits and versions correctly
Two kinds of change behave differently, and your code should treat them differently.
A content change (a line item, a price, the due date) creates a new version: V1, V2, and so on. A PO number or billing edit is a tracked amendment to the current version, not a new version. So if your logic reads "did the amount change," check the version. If it reads "did the PO arrive," check the amendment, not the version number. The difference is spelled out in versions vs amendments, and getting it wrong is the most common reason an integration double-counts a change.
Driving it from the MCP server instead
If you would rather have an assistant create and manage invoices in plain language, the MCP server exposes the same operations. You describe the invoice, it calls the endpoints, you review before it issues. Same fields, same locked-and-editable rules, same status model. It is the REST API with a different hand on the wheel, not a separate product with different behavior.
What the API does not do
It does not move money. JupiterInvoice is not a payment processor and not a merchant of record. It presents your bank details and tracks the invoice to payment, and if you connect your own Stripe account, card payment runs through that. The API creates and manages invoices; the cash still lands in your account, not ours.
Quotes work through the same surface, with a "valid until" date and an accept step where the recipient types their name to sign. If your flow starts with an estimate, build the quote first and convert once it is accepted.
Ready to wire it up? Read the API and MCP reference, or create one invoice by hand at the invoice builder first to see the fields you will be sending before you automate them.