Save a draft document the app's assistant wrote
const url = 'https://app.grouperly.com/api/v2/groups/example/documents/drafts';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"name":"example","body":"example","sourceDocumentIds":["example"],"sourceSharedCopyIds":["example"],"note":"example","restoreNames":true,"category":"GENERAL","visibility":"PRIVATE","folderId":"example","eventId":"example"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://app.grouperly.com/api/v2/groups/example/documents/drafts \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "name": "example", "body": "example", "sourceDocumentIds": [ "example" ], "sourceSharedCopyIds": [ "example" ], "note": "example", "restoreNames": true, "category": "GENERAL", "visibility": "PRIVATE", "folderId": "example", "eventId": "example" }'For the person to check in Grouperly (#253, DECISIONS #108): a DRAFT document whose first revision is DRAFTED, and whose history in Grouperly says which app’s assistant wrote it, for whom, and what it was drafted from. It’s Restricted (only the person and the group’s leaders) unless visibility says GROUP, and it keeps that visibility in a folder.
A draft is never the assistant’s to read or share until someone makes it final. Every source must be one the person may open and the assistant may read; another unit’s shared copy, only from the vertical’s own Grouperly app. restoreNames needs roster.youth.read.
60 drafts an hour per person and group. 503 unavailable while Grouperly’s AI is switched off here. Added in 2.24.0.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”The credential’s group
Request Bodyrequired
Section titled “Request Bodyrequired”At most 3 MB
object
Its name in the library, e.g. “Klondike 2027 packing list”
The draft’s text, in Markdown, at most 2 MB. Placeholders such as [Scout A] may stay as they are, or be named again with restoreNames
The group’s documents the assistant read for it: each one the person may open and the assistant may read (GET …/documents/{id}/pseudonymized). They’re listed in its history in Grouperly
Other units’ shared copies it read (SharedDocumentHit.copyId), still shared in the group’s vertical. Only the vertical’s own Grouperly app may name them
For its history, e.g. “From last year’s packing list and the council’s guide”. Grouperly already says which app’s assistant drafted it
Put the group’s children’s names back in place of their placeholders ([Scout A]): names only, never contact details. Needs roster.youth.read
Defaults to GENERAL
PRIVATE (the default): only the person and the group’s leaders see it until someone shares it. GROUP: every member
A library folder the person can see; the draft keeps its own visibility there
An event of the group to link it to
Responses
Section titled “Responses”Created
object
object
Bytes
PRIVATE documents reach only leaders, the uploader and those it was shared with
object
Null for a youth’s upload to an app without roster.youth.read
What it is attached to: an event, a series, a member, a position, a circle…
object
What it’s linked to. More types may be added: ignore a link whose type you don’t know (SERIES and CIRCLE were added in 2.16.0, #245).
Its lifecycle (DECISIONS #75): DRAFT, FINAL, SUPERSEDED or HISTORICAL
The number of its current text (GET …/markdown), or null when it has none yet
Where it is in the group’s library (#245), or null when it’s in no folder
object
The folder and those above it, e.g. “Committee/2026”
Its first revision, 1: send it as baseRevision for the next draft
Example
{ "document": { "category": "GENERAL", "visibility": "PUBLIC", "status": "DRAFT" }}Headers
Section titled “Headers”Requests allowed per minute for this credential
Requests left in this window
When the window ends (Unix seconds)
The body isn’t a JSON object of at most 16 KB, or a field is unknown, missing or malformed (invalid_body, with parameter)
object
object
Stable and machine-readable: unauthorized, forbidden, insufficient_scope, key_owner_not_leader, app_not_installed, scope_not_allowed, app_suspended, rate_limited, not_found, invalid_parameter, invalid_body, invalid_profile, invalid_descriptor, no_profile, already_exists, not_a_member, position_inactive, position_full, already_assigned, assignment_ended, version_not_current, nothing_to_pay, payments_not_ready, payload_too_large, first_party_only, terms_required, child_account, assistant_off, not_for_assistant, assistant_failed, not_a_draft, storage_full, unavailable, internal_error. New codes may be added.
For people; wording may change.
The query parameter (invalid_parameter) or body field (invalid_body, not_a_member) at fault.
Examplegenerated
{ "error": { "code": "example", "message": "example", "parameter": "example" }}Headers
Section titled “Headers”Requests allowed per minute for this credential
Requests left in this window
When the window ends (Unix seconds)
Missing, unknown, revoked or expired credential (unauthorized)
object
object
Stable and machine-readable: unauthorized, forbidden, insufficient_scope, key_owner_not_leader, app_not_installed, scope_not_allowed, app_suspended, rate_limited, not_found, invalid_parameter, invalid_body, invalid_profile, invalid_descriptor, no_profile, already_exists, not_a_member, position_inactive, position_full, already_assigned, assignment_ended, version_not_current, nothing_to_pay, payments_not_ready, payload_too_large, first_party_only, terms_required, child_account, assistant_off, not_for_assistant, assistant_failed, not_a_draft, storage_full, unavailable, internal_error. New codes may be added.
For people; wording may change.
The query parameter (invalid_parameter) or body field (invalid_body, not_a_member) at fault.
Examplegenerated
{ "error": { "code": "example", "message": "example", "parameter": "example" }}A key: wrong group (forbidden), missing scope (insufficient_scope), or its creator no longer leads the group (key_owner_not_leader). An app’s token: missing scope (insufficient_scope), the group hasn’t installed the app (app_not_installed) or allowed the scope (scope_not_allowed, the message has the consent link), the person may not do this in the group (forbidden), Grouperly paused the app (app_suspended), the person hasn’t accepted Grouperly’s current Terms (terms_required: refresh their token, then send them to the hub’s /account/welcome), or it’s a child’s account (child_account). Also: the group turned its assistant off (assistant_off), or the person may not add documents or isn’t an adult (forbidden)
object
object
Stable and machine-readable: unauthorized, forbidden, insufficient_scope, key_owner_not_leader, app_not_installed, scope_not_allowed, app_suspended, rate_limited, not_found, invalid_parameter, invalid_body, invalid_profile, invalid_descriptor, no_profile, already_exists, not_a_member, position_inactive, position_full, already_assigned, assignment_ended, version_not_current, nothing_to_pay, payments_not_ready, payload_too_large, first_party_only, terms_required, child_account, assistant_off, not_for_assistant, assistant_failed, not_a_draft, storage_full, unavailable, internal_error. New codes may be added.
For people; wording may change.
The query parameter (invalid_parameter) or body field (invalid_body, not_a_member) at fault.
Examplegenerated
{ "error": { "code": "example", "message": "example", "parameter": "example" }}Headers
Section titled “Headers”Requests allowed per minute for this credential
Requests left in this window
When the window ends (Unix seconds)
The group’s storage is full (storage_full)
object
object
Stable and machine-readable: unauthorized, forbidden, insufficient_scope, key_owner_not_leader, app_not_installed, scope_not_allowed, app_suspended, rate_limited, not_found, invalid_parameter, invalid_body, invalid_profile, invalid_descriptor, no_profile, already_exists, not_a_member, position_inactive, position_full, already_assigned, assignment_ended, version_not_current, nothing_to_pay, payments_not_ready, payload_too_large, first_party_only, terms_required, child_account, assistant_off, not_for_assistant, assistant_failed, not_a_draft, storage_full, unavailable, internal_error. New codes may be added.
For people; wording may change.
The query parameter (invalid_parameter) or body field (invalid_body, not_a_member) at fault.
Examplegenerated
{ "error": { "code": "example", "message": "example", "parameter": "example" }}Headers
Section titled “Headers”Requests allowed per minute for this credential
Requests left in this window
When the window ends (Unix seconds)
Rate limited (rate_limited)
object
object
Stable and machine-readable: unauthorized, forbidden, insufficient_scope, key_owner_not_leader, app_not_installed, scope_not_allowed, app_suspended, rate_limited, not_found, invalid_parameter, invalid_body, invalid_profile, invalid_descriptor, no_profile, already_exists, not_a_member, position_inactive, position_full, already_assigned, assignment_ended, version_not_current, nothing_to_pay, payments_not_ready, payload_too_large, first_party_only, terms_required, child_account, assistant_off, not_for_assistant, assistant_failed, not_a_draft, storage_full, unavailable, internal_error. New codes may be added.
For people; wording may change.
The query parameter (invalid_parameter) or body field (invalid_body, not_a_member) at fault.
Examplegenerated
{ "error": { "code": "example", "message": "example", "parameter": "example" }}Headers
Section titled “Headers”Requests allowed per minute for this credential
Requests left in this window
When the window ends (Unix seconds)
Seconds to wait
An app’s token for someone new, while Grouperly’s sign-in can’t be reached (unavailable); try again
object
object
Stable and machine-readable: unauthorized, forbidden, insufficient_scope, key_owner_not_leader, app_not_installed, scope_not_allowed, app_suspended, rate_limited, not_found, invalid_parameter, invalid_body, invalid_profile, invalid_descriptor, no_profile, already_exists, not_a_member, position_inactive, position_full, already_assigned, assignment_ended, version_not_current, nothing_to_pay, payments_not_ready, payload_too_large, first_party_only, terms_required, child_account, assistant_off, not_for_assistant, assistant_failed, not_a_draft, storage_full, unavailable, internal_error. New codes may be added.
For people; wording may change.
The query parameter (invalid_parameter) or body field (invalid_body, not_a_member) at fault.
Examplegenerated
{ "error": { "code": "example", "message": "example", "parameter": "example" }}