Errors
Every refusal is a JSON body with one key:
{ "error": "Could not find that document." }
The words are meant to be read. The status is what to branch on.
| Status | Meaning |
|---|---|
202 |
Asked for, and not finished — a solve that is still running |
400 |
A parameter this endpoint does not accept, or one sent where it does not apply |
401 |
No token, or one that has been revoked |
403 |
The token is for a different team, or is missing the scope this needs |
404 |
No such thing, or nothing you can see — the two are deliberately the same answer |
409 |
The thing exists but is not in a state that can answer yet — or, for a plug-in upload, collides with something the team already has |
413 |
A plug-in upload over 64 MB |
422 |
A plug-in upload that is not a Grasshopper plug-in NodePen can load |
500 |
Something is wrong on our side, not with the request |
502 |
A solve failed. The document is fine; the script did not run |
404 says less than it looks like
A document that is not there and a document that is not yours are the same answer, in the same words. That is deliberate: telling them apart would let anyone holding a token enumerate what other teams own by watching which ids answer differently. Folders and plug-ins behave the same way.
Changing a plug-in goes one step further: it is a team admin's, so a token belonging to anyone else
is answered Could not find that team., as though the team were not there.
So a 404 means "this id is not something you can read", and no more than that.
Almost nothing here is gated by plan
No endpoint that reads refuses for billing reasons. Versions, solutions and exports are the product rather than a tier of it, so a token that can reach a document can reach everything this API says about it. A refusal is always about the token, the id, or the state of the thing — never about what the team pays.
The exception is changing plug-ins. Uploading, enabling, disabling and removing one needs a team
on the Team or Custom plan, or one NodePen has enabled custom plug-ins for, and is refused 403
with Custom plug-ins are part of the Team plan. anywhere else. Listing them is not: a team that no
longer has custom plug-ins still solves with the ones it has.
What a call can still cost is credits: solving is what spends them, which is why no GET here
starts a solve. See 409 below.
409 is usually about solving
POST /api/v1/plugins/uploads/{uploadId} answers 409 for a plug-in that collides with
something, or one whose file has not all arrived — see its reference. Otherwise two endpoints
answer 409, and both mean the same thing: the document exists and you can read it, but there is
no solution behind it yet.
GET /api/v1/documents/{documentId}/solution— nothing has ever been solved.GET /api/v1/documents/{documentId}/export— an export is of a solution, so a document nobody has run has nothing to write out.
That is a very ordinary state for a document just created or just imported. Opening it in NodePen
solves it. The API deliberately will not, here or anywhere: solving costs your team credits, and a
GET that quietly spent them would be a surprising way to find that out.
The three ways a solution can decline
/solution distinguishes them so you do not have to inspect the body to know what to do:
| Status | Meaning | What to do |
|---|---|---|
409 |
This document has never been solved | Open it in the editor |
202 |
A solve is running | Try the same request shortly |
502 |
The most recent solve failed | Nothing, until the script is fixed |
400 is only ever a parameter
Five cases, all on the two endpoints that take one:
- A
formatthis endpoint does not answer in./solutiontakesjsonorbimz, with no leading dot./exporttakes.ghor.3dm, with one. They are different because one names representations of a solve and the other names file extensions. - A
rhinoVersionthat is not7,8or9. - A
rhinoVersionsent alongsideformat=.gh. It only applies to a.3dmexport, and is refused rather than ignored — a parameter that silently does nothing is discovered much later, in Rhino. - A
geometryTypethat is notsolutionordisplay. - A
geometryTypesent alongsideformat=.gh, refused for the same reason.
500 means a broken row, not a broken request
This team is not set up correctly. means a team is missing the root folder that is written in the
same transaction as the team itself. There is nothing a caller can do about it; tell us.