Skip to content

Authentication

Every request sends one credential as a bearer token:

Authorization: Bearer <credential>

Grouperly decides what each caller may see from the group’s own permissions. The API never shows more than the person or key behind it could see in Grouperly itself.

A group key (gk_…) belongs to one group. A group owner makes it in Settings → Developers, and it acts as that leader. If they stop being a leader, it stops working (key_owner_not_leader).

Each key has the scopes chosen when it was made:

Scope Allows
read The group, its events, members, positions, photos, and the adults on the roster. Youth appear with names, roles and tags only
contacts:write Adding and changing roster entries, and circle members
events:write Creating and changing events
rsvps:write Answering RSVPs on someone’s behalf
messages:announce Sending announcements to the group
documents:read The group’s documents
payments:read Payments for the group’s events
webhooks:manage Registering webhooks
youth:read Youth members’ birthdates and contact details

Each endpoint’s key scope is its x-scope in the OpenAPI document, and the API reference shows it. A key without it gets 403 insufficient_scope.

An app that people sign in to with Sign in with Grouperly calls the API with the signed-in person’s access token. It gets the token from auth.grouperly.com with resource=https://api.grouperly.com, asking for the API scopes it needs: https://api.grouperly.com/events.read and so on. Each endpoint lists its scope as x-app-scope. @grouperly/next does all of this for a Next.js app.

What the app may do in a group is what all three of these allow:

  1. The token’s scopes. If one is missing, the API answers insufficient_scope.
  2. The group’s install of the app. A leader allows the app in the group and chooses its scopes. Without that, the answer is app_not_installed or scope_not_allowed, with a link to send a leader to.
  3. The person’s own permission in the group. If they don’t have it, the answer is forbidden.

The token acts as the person, so the app sees what they’d see. A parent’s app gets the roster as a parent sees it.

  • Endpoints about the person (/me…) take only an app’s token, with the me.read scope. The person grants it on a consent page the first time.
  • Writes, such as changing a group’s profile or positions, are for apps’ tokens only, for now.

Apps that other groups install are open to invited partners for now. Email support@grouperly.com to build one.

An app calling as itself, never for a group’s data, uses its app secret (gapp_…), issued by Grouperly. Only the endpoints that say so take one. Today that’s publishing a vertical’s descriptor.

Grouperly is careful with children’s information:

  • An app sees youth members only with roster.youth.read. Without it, lists leave youth out, and counts still include them (youthCount, memberCount). Photos come without captions or tags, because those name the people in them.
  • A group key sees youth names, roles and tags. Their birthdates and contact details need youth:read. Without it, those fields are null.
  • Fields about youth are marked x-sensitive: youth in the OpenAPI document.
  • Responses that name youth are logged.
Caller Limit
A group key 120 requests a minute, per key
A partner app 120 requests a minute, per person
An app secret 120 requests a minute, per app

Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset. Over the limit, the answer is 429 rate_limited with Retry-After.