Create a proposal by pasting JSON
The proposal JSON format: start a proposal or starter from a pasted document, replace a draft's content, or add prices to the price list.
A proposal can be written as one JSON document and pasted into Magpie. New proposal → Paste JSON starts a proposal from it; Import JSON in a draft's File menu replaces the draft's content with it; New starter on the Starters page adds a team starter. Export JSON, in a draft's File menu or a sent proposal's More menu, downloads a proposal in the same format, and an export imports back unchanged.
Use Copy the prompt in the import box to copy these instructions for an assistant you use. It asks you what it needs, then writes the document.
Importing is all or nothing. The whole document is checked before anything is saved, and a mistake is named by its place in the document, such as "sections[2].lines[0].unitPrice" must be an amount. An imported proposal is a draft: nothing reaches a client until someone sends it, and the send check shows its totals first.
The document
{
"schema": "magpie.proposal",
"version": 1,
"title": "Website design and build",
"currency": "USD",
"language": "en",
"validForDays": 30,
"sections": [],
"discount": null,
"schedule": [],
"startWorkWhen": "deposit_paid",
"recurringStart": { "on": "acceptance", "endAfter": 12 }
}
| Field | Type | Notes |
|---|---|---|
schema |
string, optional | "magpie.proposal". |
version |
number, optional | 1. |
title |
string, required | The proposal's title. |
currency |
string, optional | A three-letter code such as USD, EUR or GBP. USD if left out. |
language |
string, optional | The client page's language: en, fr, es or de. en if left out. What you write is not translated. |
validForDays |
number, optional | How many days the proposal can be accepted for. Proposals settings decides if left out. |
sections |
array, required | The sections in order. See below. |
discount |
object or null, optional | { "type": "percent", "value": "10" } or { "type": "amount", "value": "250" }, on one-time lines only. |
schedule |
array, optional | The payments. See below. Empty for one final payment. |
startWorkWhen |
string, optional | "signed" or "deposit_paid". "deposit_paid" needs a deposit. |
recurringStart |
object, optional | When recurring invoices start. See below. |
Every id is optional: letters, digits, - or _, different from every other id in the document. Magpie makes one when it is left out.
Sections
Every section has type and may have id, title and hidden (true keeps it out of the client's page).
type |
Fields |
|---|---|
cover |
subtitle, imageUuid |
text, terms |
markdown or blocks |
pricing |
markdown or blocks for an introduction, then lines, or choice: "package" and packages |
timeline |
markdown or blocks, and phases: { "name", "description", "start", "end", "days" } with dates as YYYY-MM-DD |
team |
members: { "name", "role", "bio", "imageUuid" } |
testimonials |
items: { "quote", "name", "role" } |
faq |
items: { "question", "answer" } |
images |
images: { "imageUuid", "alt", "caption" } |
video |
video: { "url", "caption" } for a YouTube, Vimeo or Loom address |
files |
files: { "fileUuid", "name" } |
Pictures and files are uploaded in Magpie, not in the document: leave out imageUuid and the images, video and files sections, and add them in the editor.
Text
markdown takes Markdown: #, ## and ### headings, - bullets, 1. numbered items, > quotes, **bold**, *italic* and [links](https://example.com). Fields such as {{client.firstName}} are filled in for the client.
blocks is the exact form an export uses: a list of { "type", "level", "runs" }, where type is paragraph, heading (with level 1 to 3), bullet-list, numbered-list or quote, and each run is { "text", "marks" } with marks bold, italic, underline or link (with href). A run with "placeholder": true is text the writer must replace before sending.
Pricing lines
{ "name": "Design", "description": "Page designs for desktop and phone", "quantity": "1", "unit": "", "unitPrice": "2500.00", "taxRate": "none", "billing": "once" }
| Field | Type | Notes |
|---|---|---|
name |
string, required | The line's name. |
description |
string, optional | Shown under the name. |
quantity |
string or number, optional | Up to 4 decimal places. 1 if left out. |
unit |
string, optional | Such as hour. |
unitPrice |
string or number, required | Typed as on an invoice: 2500, 2500.00 or 2,500.00. |
taxRate |
string, optional | The name of one of your tax rates in Invoicing, or "none". |
billing |
string, optional | once, monthly, quarterly or yearly. once if left out. |
optional |
boolean, optional | The client adds or removes it. Not allowed in a package. |
selected |
boolean, optional | Whether an optional line starts added. |
adjustable |
object, optional | { "min": "1", "max": "10", "step": "1" }: the client chooses the quantity. |
example |
boolean, optional | An example price the writer must replace before sending. |
A package is { "name", "description", "recommended", "lines" }. A package choice has 2 to 4 packages and at most one recommended.
Payments
{ "kind": "deposit", "label": "Deposit", "percent": "50" }
kind is deposit (first only), date, milestone or final (last only). Give percent or amount; the final payment may leave both out and takes what is left. A date payment has date (YYYY-MM-DD) or daysAfter (days after acceptance). Percentages are of the one-time total before tax and add up to 100 at most.
recurringStart is { "on": "acceptance" }, { "on": "date", "date": "2026-11-01" } or { "on": "days_after", "days": 30 }, with an optional endAfter: how many invoices to send.
A complete example
A website proposal with two packages, an optional line, a monthly line and a deposit:
{
"schema": "magpie.proposal",
"version": 1,
"title": "New website for Northwind Bakery",
"currency": "USD",
"validForDays": 30,
"sections": [
{ "type": "cover", "title": "New website for Northwind Bakery", "subtitle": "Prepared for {{client.company}} by {{business.name}}" },
{ "type": "text", "title": "The project", "markdown": "A new website for Northwind Bakery that shows the menu, takes cake orders and works well on phones.\n\n## What you will provide\n\n- Photos of the shop and the cakes\n- The menu and prices" },
{ "type": "pricing", "title": "Website", "choice": "package", "packages": [
{ "name": "Essential", "description": "Up to 5 pages.", "lines": [
{ "name": "Design", "unitPrice": "2500" },
{ "name": "Build and launch", "unitPrice": "3000" }
] },
{ "name": "Complete", "description": "Up to 12 pages, with online cake orders.", "recommended": true, "lines": [
{ "name": "Design", "unitPrice": "3500" },
{ "name": "Build and launch", "unitPrice": "4500" },
{ "name": "Online cake orders", "unitPrice": "1500" }
] }
] },
{ "type": "pricing", "title": "Extras and care", "lines": [
{ "name": "Copywriting", "description": "Text for every page", "quantity": "1", "unit": "page", "unitPrice": "120", "optional": true, "adjustable": { "min": "1", "max": "12", "step": "1" } },
{ "name": "Hosting and updates", "unitPrice": "150", "billing": "monthly" }
] },
{ "type": "timeline", "title": "Timeline", "phases": [
{ "name": "Discovery and design", "days": 10 },
{ "name": "Build", "days": 15 },
{ "name": "Launch", "days": 2 }
] },
{ "type": "faq", "title": "Questions", "items": [
{ "question": "Can I update the menu myself?", "answer": "Yes. You can change the menu and prices at any time." }
] },
{ "type": "terms", "title": "Terms", "markdown": "The deposit is due on acceptance and the rest on completion. Hosting is billed monthly and can be cancelled with 30 days' notice." }
],
"schedule": [
{ "kind": "deposit", "label": "Deposit", "percent": "50" },
{ "kind": "final", "label": "On completion" }
],
"startWorkWhen": "deposit_paid",
"recurringStart": { "on": "days_after", "days": 30 }
}
Price list
Import prices on the Price list takes a document of prices to add. It only adds; prices already in the list are not changed.
{
"currency": "USD",
"prices": [
{ "name": "Design", "unit": "hour", "unitPrice": "95", "taxRate": "none" },
{ "name": "Hosting and updates", "unitPrice": "150", "billing": "monthly" }
]
}
Each price has name (required), description, unit, unitPrice (required), taxRate (the name of one of your tax rates, or "none") and billing (once, monthly, quarterly or yearly). currency applies to every price, and is Proposals settings' currency if left out.
For more help, Contact support.
Ask Magpie support
Send Magpie staff a question about anything this article does not answer.