[{"data":1,"prerenderedAt":82},["ShallowReactive",2],{"doc-figures":3},{"blocks":4,"markdown":81},[5,72,75,79],{"kind":6,"method":7,"path":8,"operation":9,"response":34,"errors":37,"authErrors":54},"endpoint","POST","\u002Fv1\u002Ffigures\u002Frender",{"method":7,"path":8,"summary":10,"description":11,"parameters":12,"body":13,"responses":30},"Render Figure","Draw a figure this API already vouched for.\n\nFREE. A figure is a picture of something already paid for; charging again\nfor looking at it would make the price depend on which client you used.\n\nHere rather than on the renderer's own hostname because this surface is\nalready public, already behind an API key, and already the process that\nminted the token — so abuse is attributable to a key that can be revoked,\nrather than to whoever happens to be holding an unexpired token.",[],[14,23],{"name":15,"type":16,"required":17,"description":18,"enum":19,"default":20,"constraints":21},"token","string",true,"The `figure.token` from an answer.",[],null,[22],"min length 1",{"name":24,"type":16,"required":25,"description":26,"enum":27,"default":28,"constraints":29},"format",false,"`svg` or `png`.",[],"svg",[],[31],{"status":32,"description":33},"200","The drawn figure.",{"status":32,"description":35,"binary":17,"fields":36},"The drawn figure: `image\u002Fsvg+xml`, or `image\u002Fpng` when you ask for `png`.",[],[38,42,46,50],{"status":39,"code":40,"when":41},400,"SIGNATURE_INVALID","The token is malformed, altered or expired",{"status":43,"code":44,"when":45},422,"VALIDATION_FAILED","The body is missing `token`, the `format` is unknown, the answer names data it does not carry, or the figure contains something Forma does not produce",{"status":47,"code":48,"when":49},501,"UNSUPPORTED","Nothing draws this target",{"status":51,"code":52,"when":53},503,"UPSTREAM_UNAVAILABLE","A figure could not be drawn because of a problem on our side, or drawing is briefly unavailable. The answer is unaffected; retry after a short wait",[55,59,62,65,68],{"status":56,"code":57,"when":58},401,"KEY_MISSING","No `Authorization` header",{"status":56,"code":60,"when":61},"KEY_UNKNOWN","The key is not one we issued",{"status":56,"code":63,"when":64},"KEY_REVOKED","The key was revoked in the console",{"status":56,"code":66,"when":67},"KEY_EXPIRED","The key is past its expiry",{"status":69,"code":70,"when":71},403,"ORG_DISABLED","The key is fine; its organisation is not active",{"kind":73,"html":74},"html","\u003Cp>Some answers can be drawn. When one can, its response carries a \u003Ccode>figure\u003C\u002Fcode> block:\u003C\u002Fp>\n",{"kind":76,"lang":77,"code":78},"code","json","{\n  \"status\": \"valid\",\n  \"result\": { \"mark\": \"bar\", \"data\": { \"values\": [] } },\n  \"figure\": {\n    \"drawable\": true,\n    \"target\": \"vega-lite\",\n    \"token\": \"v2.dmVnYS1saXRlADE3OTAx…\"\n  }\n}",{"kind":73,"html":80},"\u003Cp>Send that \u003Ccode>token\u003C\u002Fcode> here and you get the picture back.\u003C\u002Fp>\n\u003Ch2 id=\"why-a-token-and-not-an-id\">Why a token and not an id\u003C\u002Fh2>\n\u003Cp>Nothing is stored. The token \u003Cstrong>carries\u003C\u002Fstrong> the artifact — it is the answer plus a\nsignature proving we produced it — so there is no record to look up and no copy\nof your output kept on our side. It expires an hour after the answer.\u003C\u002Fp>\n\u003Cp>It also means you never have to rebuild anything. Pass the token through\nunchanged; reconstructing the source yourself would have to match the signed\nbytes exactly, and a single space in the wrong place is indistinguishable from a\nforgery.\u003C\u002Fp>\n\u003Ch2 id=\"formats\">Formats\u003C\u002Fh2>\n\u003Cdiv class=\"doc-table\">\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>\u003Ccode>format\u003C\u002Fcode>\u003C\u002Fth>\n\u003Cth>\u003C\u002Fth>\n\u003Cth>\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>svg\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the default\u003C\u002Ftd>\n\u003Ctd>vector — what a browser or a document wants\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>png\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>raster\u003C\u002Ftd>\n\u003Ctd>what a model can look at; SVG is not something an agent can read\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003C\u002Fdiv>\n\u003Cp>The MCP \u003Ccode>show_figure\u003C\u002Fcode> tool defaults to \u003Ccode>png\u003C\u002Fcode> for that reason: its reader is a\nmodel.\u003C\u002Fp>\n\u003Ch2 id=\"what-draws\">What draws\u003C\u002Fh2>\n\u003Cp>\u003Ccode>vega-lite\u003C\u002Fcode>, \u003Ccode>tikz\u003C\u002Fcode>, \u003Ccode>pictex\u003C\u002Fcode>, \u003Ccode>metapost\u003C\u002Fcode> and \u003Ccode>gnuplot\u003C\u002Fcode>. TeX-family figures come\nback with their text as outlines, so the picture needs no fonts. Anything else\nis a \u003Ccode>501\u003C\u002Fcode> naming the target.\u003C\u002Fp>\n\u003Ch2 id=\"what-a-figure-may-contain\">What a figure may contain\u003C\u002Fh2>\n\u003Cp>A figure is not a document you author — it is output Forma returned, handed\nback to us. So the renderer checks that it \u003Cem>is\u003C\u002Fem> that: every command in it has to\nbe one Forma's own output can contain. Anything else is refused by name rather\nthan run.\u003C\u002Fp>\n\u003Cp>That is stricter than it may sound, and deliberately so. TeX is a programming\nlanguage, MetaPost can read files, and gnuplot will run a shell command given a\nbacktick in a chart title. Rather than scan for dangerous constructs — which\nfails, because TeX can build any command out of characters — the renderer starts\nfrom the short list of things Forma's output contains and refuses the rest.\u003C\u002Fp>\n\u003Cp>The practical consequence: figures Forma returned draw, and hand-written TeX\ndoes not. If you want to typeset your own document, take the source from the\nanswer and run it yourself — the \u003Ccode>tikz\u003C\u002Fcode> output is a fragment that drops straight\ninto a \u003Ccode>tikzpicture\u003C\u002Fcode> environment.\u003C\u002Fp>\n\u003Ch2 id=\"three-states-not-two\">Three states, not two\u003C\u002Fh2>\n\u003Cp>\u003Ccode>drawable\u003C\u002Fcode> answers a question with three honest outcomes, and the \u003Ccode>reason\u003C\u002Fcode>\nsays which:\u003C\u002Fp>\n\u003Cdiv class=\"doc-table\">\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>\u003C\u002Fth>\n\u003Cth>\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>drawable: true\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>there is a picture, and the token draws it\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>no renderer\u003C\u002Ftd>\n\u003Ctd>nothing can draw this target — some targets produce data, not pictures\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>not drawn, with a reason\u003C\u002Ftd>\n\u003Ctd>the answer names data it does not carry\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003C\u002Fdiv>\n\u003Cp>That last one is deliberate. A chart whose data is\n\u003Ccode>{&quot;url&quot;: &quot;sales.csv&quot;}\u003C\u002Fcode> is pointing at a file we have never seen, so there is\nnothing truthful to draw — and we do not go and fetch it. The same applies to a\nchart that generates its own rows rather than carrying them. Put the numbers in\nyour intent and the chart carries them, and draws.\u003C\u002Fp>\n\u003Ch2 id=\"free\">Free\u003C\u002Fh2>\n\u003Cp>Drawing costs no credits. You already paid for the answer; what you display it\nwith should not change the price.\u003C\u002Fp>\n","# Draw a figure\n\n> Turn an answer into a picture. Free, and only for answers we vouched for.\n\n`POST https:\u002F\u002Fapi.formalogic.io\u002Fv1\u002Ffigures\u002Frender`\n\nRequest:\n\n| Field | Type | Where | Meaning |\n|---|---|---|---|\n| `token` | string | body, required | The `figure.token` from an answer. |\n| `format` | string | body | `svg` or `png`. |\n\nResponse 200: The drawn figure: `image\u002Fsvg+xml`, or `image\u002Fpng` when you ask for `png`.\n\nErrors (plus 401 `KEY_MISSING`, `KEY_UNKNOWN`, `KEY_REVOKED`, `KEY_EXPIRED` and 403 `ORG_DISABLED` on every endpoint):\n\n| Status | Code | When |\n|---|---|---|\n| 400 | `SIGNATURE_INVALID` | The token is malformed, altered or expired |\n| 422 | `VALIDATION_FAILED` | The body is missing `token`, the `format` is unknown, the answer names data it does not carry, or the figure contains something Forma does not produce |\n| 501 | `UNSUPPORTED` | Nothing draws this target |\n| 503 | `UPSTREAM_UNAVAILABLE` | A figure could not be drawn because of a problem on our side, or drawing is briefly unavailable. The answer is unaffected; retry after a short wait |\n\nSome answers can be drawn. When one can, its response carries a `figure` block:\n\n```json\n{\n  \"status\": \"valid\",\n  \"result\": { \"mark\": \"bar\", \"data\": { \"values\": [] } },\n  \"figure\": {\n    \"drawable\": true,\n    \"target\": \"vega-lite\",\n    \"token\": \"v2.dmVnYS1saXRlADE3OTAx…\"\n  }\n}\n```\n\nSend that `token` here and you get the picture back.\n\n## Why a token and not an id\n\nNothing is stored. The token **carries** the artifact — it is the answer plus a\nsignature proving we produced it — so there is no record to look up and no copy\nof your output kept on our side. It expires an hour after the answer.\n\nIt also means you never have to rebuild anything. Pass the token through\nunchanged; reconstructing the source yourself would have to match the signed\nbytes exactly, and a single space in the wrong place is indistinguishable from a\nforgery.\n\n## Formats\n\n| `format` | | |\n|---|---|---|\n| `svg` | the default | vector — what a browser or a document wants |\n| `png` | raster | what a model can look at; SVG is not something an agent can read |\n\nThe MCP `show_figure` tool defaults to `png` for that reason: its reader is a\nmodel.\n\n## What draws\n\n`vega-lite`, `tikz`, `pictex`, `metapost` and `gnuplot`. TeX-family figures come\nback with their text as outlines, so the picture needs no fonts. Anything else\nis a `501` naming the target.\n\n## What a figure may contain\n\nA figure is not a document you author — it is output Forma returned, handed\nback to us. So the renderer checks that it *is* that: every command in it has to\nbe one Forma's own output can contain. Anything else is refused by name rather\nthan run.\n\nThat is stricter than it may sound, and deliberately so. TeX is a programming\nlanguage, MetaPost can read files, and gnuplot will run a shell command given a\nbacktick in a chart title. Rather than scan for dangerous constructs — which\nfails, because TeX can build any command out of characters — the renderer starts\nfrom the short list of things Forma's output contains and refuses the rest.\n\nThe practical consequence: figures Forma returned draw, and hand-written TeX\ndoes not. If you want to typeset your own document, take the source from the\nanswer and run it yourself — the `tikz` output is a fragment that drops straight\ninto a `tikzpicture` environment.\n\n## Three states, not two\n\n`drawable` answers a question with three honest outcomes, and the `reason`\nsays which:\n\n| | |\n|---|---|\n| `drawable: true` | there is a picture, and the token draws it |\n| no renderer | nothing can draw this target — some targets produce data, not pictures |\n| not drawn, with a reason | the answer names data it does not carry |\n\nThat last one is deliberate. A chart whose data is\n`{\"url\": \"sales.csv\"}` is pointing at a file we have never seen, so there is\nnothing truthful to draw — and we do not go and fetch it. The same applies to a\nchart that generates its own rows rather than carrying them. Put the numbers in\nyour intent and the chart carries them, and draws.\n\n## Free\n\nDrawing costs no credits. You already paid for the answer; what you display it\nwith should not change the price.\n",1793819974007]