Signup & Invites

Using these APIs, you can manage invites to make a person signup for a club, optionally making the person a member for that club. An invite represents a multi-step process for onboarding new people for a club. The steps are:

  • invite created: The Club API client creates an invite, and an e-mail is sent to the user where they can signup. Additionally, the signup page URL is available at the openHref response property.

    A club_person_invite event is triggered on creation.

  • invite email sent: An email is sent to the user, and sentAt is set every time the email is (re)sent. Every time the email is sent, a club_person_invite event might be triggered. The email might have been sent at creation of the invite, skipping any additional events unless the email is resent.

    Club API clients can update or delete the invite, triggering events on every change.

  • invite opened: The user clicks the url in the email and starts signup process, updating openedAt at the first time the page is visited and triggering a club_person_invite.

    Club API clients can update or delete the invite, triggering events on every change. The user will never be notified about updates or deletions done via Club API. For every change, another club_person_invite is triggered, even if the change is via Club API.

  • invite deleted: Either the user or a Club API client deletes the invite. A final club_person_invite is triggered. Deletion can be done at any point until the invite is completed.

  • invite completed: The user completes the invite and the signup will be completed soon. A club_person_invite event is triggered, and userCompletedAt will be set.

  • invite processed: The final state of an invite, and there will be one final club_person_invite event. clubiProcessedAt is now set and the invite can no longer change. personId, referring to the person ID of your new club person or member, is guaranteed to be set and final.

    Between invite completed and processed, additional events might have been generated representing the club person changes. If the signup includes a name, birth date, or gender change, other clubs might have been notified about these changes.

Any Club API client and the person can modify their signup before completing it. An invite can be completed using an existing person or a new one. Use clubPersonInvite to check the latest changes on an invite, including any person ID set to that invite. Only when an invite is processed (clubiProcessedAt is set), the personId is final.

For every change on invites, including changes you make yourself, a club_person_invite event is generated.

Once the invite is completed, the person (referred by personId) will be added to clubPeople for that club until deleteClubPerson is called.

The role XR ("Club relatie") will be attached to the person at all times. Club API clients cannot modify this role except by using deleteClubPerson. The person will be made a club member if makeMember is true at time of completion.

For testing purposes, mock* API calls. These APIs are available in any environment (including production), but access is whitelisted per club and per person. If no personId is set on completion, one will be created.

Regardless whether completion was done by a user or done using mockCompleteClubPersonInvite, processing is done asynchronously. Once the processing is completed, a final club_person_invite event is triggered. Additionally, other events are likely generated as part of updating or creating resources related to the new club person or member.

The invite APIs are experimental and subject to change.

clubPersonInvite

Query

clubId: ID!, id: ID!ClubPersonInvite!

Find an invite

Input arguments
clubId: ID!
id: ID!
Output arguments

clubPersonInvites

Query

clubId: ID!, search: ClubPersonInviteSearch!ClubPersonInvitePaginated!

Find all invites for a club

Input arguments
clubId: ID!
Output arguments

createClubPersonInvite

Mutation

clubId: ID!, request: CreateClubPersonInviteRequest!ClubPersonInvite!

Create a new invite to signup a person for a club, optionally as a member.

Input arguments
Output arguments

updateClubPersonInvite

Mutation

changes: [ClubPersonInviteChangeRequest!]!, clubId: ID!, id: ID!ClubPersonInvite!

Update one or more properties of an invite. Only invites that have not been completed can be updated.

Input arguments
clubId: ID!
id: ID!
Output arguments

deleteClubPersonInvite

Mutation

clubId: ID!, id: ID!Boolean!

Delete an invite. Only invites that have not been completed can be deleted. Returns true if the club person invite existed at one point, and is now deleted.

Input arguments
clubId: ID!
id: ID!
Output arguments

mockCompleteClubPersonInvite

Mutation

clubId: ID!, id: ID!Boolean!

For automated testing purposes, simulate an invite to be completed.

If personId was not set (use mockUpdateClubPersonInvitePerson), a new person will be created. If makeMember is true, the person will be made a club member.

Note that the processing of invites is done asynchronously. This mock API marks an invite for completion, queueing it for processing. club_person_invite Events will be triggered while the invite is being processed. Only when clubiProcessedAt is set, the invite is final and no more club_person_invite events are triggered.

Input arguments
clubId: ID!
id: ID!
Output arguments

mockUpdateClubPersonInvitePerson

Mutation

clubId: ID!, id: ID!, ownerPersonId: ID, personId: IDBoolean!

For automated testing purposes, assign an owner and/or person to an invite.

Input arguments
clubId: ID!
id: ID!
ownerPersonId: ID
personId: ID
Output arguments

ClubPersonInvite

Object
id: ID!
clubId: ID!
email: String!
telephone: String
birthDate: LocalDate
gender: Gender
givenName: String
namePrefix: String
familyName: String
initials: String
personId: ID
ownerPersonId: ID
makeMember: Boolean
openHref: String!
sentAt: Instant
userCompletedAt: Instant
clubiProcessedAt: Instant
openedAt: Instant

ClubPersonInviteSearch

Input Object
offset: Int
limit: Int

ClubPersonInvitePaginated

Object
collection: [ClubPersonInvite]!
count: Int!
offset: Int!
limit: Int!

CreateClubPersonInviteRequest

Input Object
email: String!
telephone: String
birthDate: LocalDate
gender: Gender
givenName: String
namePrefix: String
familyName: String
initials: String
makeMember: Boolean

ClubPersonInviteChangeRequest

Input Object
key: String! — A property of CreateClubPersonInviteRequest
prev: ClubPersonInviteValue — The current value of the property referred to by key.
next: ClubPersonInviteValue — The desired value of the property referred to by key.

ClubPersonInviteRequestAddress

Input Object
houseNumber: String! — Full house number, must start with a digit
postalCode: String! — A 1000AA-formatted string
countryCode: String! — Required, but can be omitted if already present. Country code. EG 'NL'. Must be 2 characters.

ClubPersonInviteValue

Scalar

A value compatible with the ClubPersonInvite's property referred to by key. EG, if key is "givenName", value should be a String.

Club People

Using these APIs, you can manage people associated to a club, and their personal details. For managing contact details, see Club Person Contacts.

clubPerson

Query

clubId: ID!, personId: ID!ClubPerson!

Input arguments
clubId: ID! — Federation reference id of the club, EG XX11AA01.
personId: ID! — Person reference id of the club, EG J82SC4X.
Output arguments

clubPeople

Query

clubId: ID!, limit: Int, membership: Boolean, offset: IntClubPeopleResponse!

Input arguments
clubId: ID! — Federation reference id of the club, EG XX11AA01.
limit: Int
membership: Boolean — Filter club people by whether they have a membership or not
offset: Int
Output arguments

clubPersonChangeset

Query

clubId: ID!, id: ID!ClubPersonChangeset!

Input arguments
clubId: ID! — Federation reference id of the club, EG XX11AA01.
id: ID! — ID as returned by createClubPersonChangeset
Output arguments

createClubPersonChangeset

Mutation

changes: [ClubPeopleChangeRequestChange!]!, clubId: ID!, personId: ID!ClubPersonChangeset

Create a set of changes for a person in a club. Only when all changes are accepted, they'll be applied. Otherwise, the changeset will be rejected, even if some of the changes would be valid.

All updates on the person (name, birth date and gender) will be propagated to all other clubs where the person is a 'club person'.

For every property you want to change, you need to provide the key of the property (EG "familyName"), the current value (EG "Flodder") and the desired value (EG "Flodeur").

Every change is validated either automatically or manually (or both), and only when all changes are accepted, and the provided current values still match the actual current values (IE none of the properties were changed by some other process or changeset) the changeset's changes are actually applied.

In some cases, the accepted value is different from the requested value. This should only happen when the requested value and accepted value are functionally identical, but are formatted differently. However, this behaviour is not guaranteed: You should always check what the actual accepted value is by fetching the clubPersonChange again, looking at the changes[].value property, or by just using clubPerson to fetch the updated person.

You can create multiple changesets at once. Because the provided current value needs to match actual current value when the changeset is accepted, any conflicting changeset will fail.

The changeset will be updated upon validation and processing. Once they changeset is accepted or rejected, their state is final and they will no longer be updated.

For every create, update or delete on the changeset, a club_person_changeset event is triggered. In some cases, the changeset is accepted immediately.

When updating the person based on a changeset, additional events related to the person or club_person might be triggered. In some cases, other clubs will also receive events about the updated person. In some cases, other changesets in other clubs are invalidated because of the person updates.

Input arguments
changes: [ClubPeopleChangeRequestChange!]! — A list of changes. If one change is rejected, the whole changeset will be rejected. If all changeset are accepted, the changeset will be accepted and the person will be updated.
clubId: ID! — Federation reference id of the club, EG "XX11AA01".
personId: ID! — ID of the person, EG "J82SC4X".
Output arguments

deleteClubPersonChangeset

Mutation

clubId: ID!, id: ID!Boolean!

Delete a pending changeset, canceling all pending changes, both accepted and rejected. This is only possible if the changeset's state is pending. Idempotent: Invoking this function multiple times should have the same result.

Returns true on success, or some kind of error on failure.

Also see deleteClubMember to keep the relationship but make the person no longer a member of this club.

Input arguments
clubId: ID! — Federation reference id of the club, EG "XX11AA01".
id: ID! — ID as returned by createClubPersonChangeset
Output arguments

deleteClubPerson

Mutation

clubId: ID!, personId: ID!Boolean!

Immediately delete all relations of a person within a club, deleting memberships, roles, team roles and contact details. The club will have no more access to this person.

Specifically, the following resources attached to both the person and club get deleted or updated:

  • All future team players (startDate after today) will be deleted.
  • All active team players will have their endDate set to today.
  • All future memberships, club_assignable roles and club_assignable team roles (validFrom after now) will be deleted.
  • All active memberships, club_assignable roles and club_assignable team roles will have their validTo set to now.
  • All XR-roles ("Club Relatie") will be deleted.

Note that contacts are not deleted or updated. This will be implemented later. Additionally, the person itself will not be altered, nor will any resource for any other club be altered.

For every record that's being deleted or updated, some events might be triggered.

To reintroduce the person the club, you have to send a new invite using createClubPersonInvite.

Returns true on success, or some kind of error on failure.

Input arguments
clubId: ID! — ID of the club, EG "XX11AA01".
personId: ID! — ID of the person, EG "J82SC4X".
Output arguments

ClubPersonMembership

Object
active: Boolean!true when this membership is active, or false if it is not (yet?)
validFrom: Instant
validTo: Instant
clubId: ID!

ClubPersonRole

Object
active: Boolean!true when this role is active, or false if it is not (yet?)
validFrom: Instant
validTo: Instant
clubId: ID!
categoryId: ID!

ClubPersonTeamRole

Object
active: Boolean!true when this team role is active, or false if it is not (yet?)
validFrom: Instant
validTo: Instant
clubId: ID!
categoryId: ID!
teamId: ID!

ClubPersonTeamPlayer

Object
active: Boolean!true when this team_player is active, or false if it is not (yet?)
startDate: LocalDate
endDate: LocalDate
teamId: ID!

ClubPerson

Object
id: ID!
initials: String!
givenName: String
namePrefix: String
familyName: String!
fullName: String!
gender: Gender!
birthDate: LocalDate
membership: ClubPersonMembership — The currently active or future membership for this person within this club. Always check active to verify the person has an active membership.
roles: [ClubPersonRole!]! — Currently active and future roles for this person within this club. Always check active to verify the role is actually active.
teamRoles: [ClubPersonTeamRole!]! — Currently active and future team roles for this person within this club's teams. Always check active to verify the role is actually active.
teamPlayers: [ClubPersonTeamPlayer!]! — Currently active and future team players for this person within this club's teams. Always check active to verify the team_player is actually active.

ClubPeopleResponse

Object
clubId: ID!
count: Int
offset: Int
limit: Int
collection: [ClubPerson!]!

ClubPeopleChangeRequestChange

Input Object
key: ID! — A property of a clubPerson to change. Possible keys: [ 'givenName', 'namePrefix', 'familyName', 'gender', 'birthDate', 'initials' ]
prev: String — The current value, as a string, or NULL if the current value is NULL
next: String — The desired value as a string, or NULL if the desired value is NULL

ClubPersonChangeset

Object
id: ID!
personId: ID!
clubId: ID!
createdAt: Instant!
updatedAt: Instant
rejectedAt: Instant — If set, none of the changes were processed. Usually this happens when at least one change is rejected. rejectedAt and acceptedAt can never both be set.
acceptedAt: Instant — If set, all changes were accepted and processed. This state is final. rejectedAt and acceptedAt can never both be set.
state: ClubPersonChangesetState!pending if rejectedAt and acceptedAt are blank. rejected or accepted otherwise. If rejected, none of the changes were processed. If accepted, all changes were processed.
changes: [ClubPersonChangesetChange!]! — An array of changes based on the requested changes. Will have all the input properties as provided via createClubPersonChangeset, but with additional fields to inspect the state of each change in the changeset.

ClubPersonChangesetChange

Object
key: ID! — A property of a clubPerson to change. Permitted keys: [ 'givenName', 'namePrefix', 'familyName', 'gender', 'birthDate', 'initials' ]
prev: String — The current value, as a string, or NULL if the current value is NULL
next: String — The desired value as a string, or NULL if the desired value is NULL
value: String — The final, accepted value as a string, or NULL if the accepted value is NULL
rejectedAt: Instant — If this change is rejected, this timestamp will be set. Only rejectedAt or acceptedAt can be set, not both.
acceptedAt: Instant — If this change is accepted, this timestamp will be set. Only rejectedAt or acceptedAt can be set, not both. Note that a change is only processed when all changes are accepted. IE, if acceptedAt is set, it is only an indication that the change might be processed in the future, but only if none of the other changes are rejected. Accepted changes can still be canceled using deleteClubPersonChangeset.
rejectedCode: ID — Some error code that describes why the change was rejected. Should be set when rejectedAt is set.
rejectedMessage: String — Some human-readable message to describe why the change was rejected. Should be set when rejectedAt is set.

ClubPersonChangesetState

Enum
rejected
accepted
pending

Club Members

Using these APIs, you can manage people's membership for a club

clubMember

Query

clubId: ID!, personId: ID!ClubMember2

Get a membership of a person in a club. Returns a currently active or future membership.

Input arguments
clubId: ID! — Federation reference id of the club, EG XX11AA01.
personId: ID! — Person reference id of the club, EG J82SC4X.
Output arguments

clubMembers

Query

clubId: ID![ClubMember2!]!

Get all memberships of people with an active or future membership in a given club, similar to clubPeople(membership: true)

Input arguments
clubId: ID! — Federation reference id of the club, EG XX11AA01.
Output arguments

createClubMember

Mutation

clubId: ID!, personId: ID!ClubMember2!

Immediately make a person member of a club. Requires the person to be a "club person". If the person isn't already related to the club, use createClubPersonInvite instead. Idempotent: If invoked multiple times, the result should be the same.

Specifically, for all club member records for this person in this club, this function will:

  • Delete all future club member records, if any
  • Set the validTo on all active club_member records, except for one
  • Remove the validTo on one active club_member, if set
  • If there is no active club member record, one is created

If the person is not a clubPerson, a "ClubPersonNotFound" error is returned and nothing will change.

Input arguments
clubId: ID! — ID of the club, EG "XX11AA01".
personId: ID! — ID of the person, EG "J82SC4X".
Output arguments

deleteClubMember

Mutation

clubId: ID!, personId: ID!Boolean!

Immediately delete a player's membership and associated roles and team players. Returns true on success, or an error. Idempotent: If invoked multiple times, the result should be the same.

Specifically, this function will:

  • Check if the person and club exists, and the person is related to the club.
  • Set the validTo of all active memberships for the person and club
  • Delete all future memberships for the person and club
  • End or delete all club_assignable roles for the person and club
  • Ensure the person is still a "club person", optionally creating a hidden XR role
  • End or delete all team players attached to the active and future memberships.

You can make the person a member again using createClubMember. You can delete the person from the club using deleteClubPerson.

Input arguments
clubId: ID! — ID of the club, EG "XX11AA01".
personId: ID! — ID of the person, EG "J82SC4X".
Output arguments

ClubMember2

Object
active: Boolean!true when this membership is active, or false if it is not (yet?)
validFrom: Instant
validTo: Instant
personId: ID!
clubId: ID!

Club Roles

Using these APIs, you can manage people's roles in a club.

A club role is a role attached to a club member without being attached to a team. A club role's category is either assignable or readable. Readable roles are assigned externally and Club API users can only read them. Assignable roles can be assigned by Club API users.

A role can only be attached by a club member. By deleting a person's membership, all roles will also be deleted.

clubRole

Query

categoryId: ID!, clubId: ID!, personId: ID!ClubRole

Get a role of a person in a club. Returns a currently active or future role.

Input arguments
categoryId: ID! — EG "WA".
clubId: ID! — EG "XX11AA01".
personId: ID! — EG "J82SC4X".
Output arguments

clubRoles

Query

categoryId: ID, clubId: ID!, limit: Int, offset: Int, permission: ClubRolePermission, personId: IDClubRolesResponse!

Get all roles in a club, optionally filtered by category or person.

Input arguments
categoryId: ID — Optional. EG "WA".
clubId: ID! — EG "XX11AA01".
limit: Int — Limit the number of roles returned by this amount
offset: Int — Skip this amount of roles for the purpose of pagination.
permission: ClubRolePermission — Optional. Filter roles by their permission
personId: ID — Optional. EG "J82SC4X".
Output arguments

createClubRole

Mutation

categoryId: ID, clubId: ID!, personId: ID, siteVisibility: ClubRoleSiteVisibilityClubRole!

Input arguments
categoryId: ID — Optional. EG "WA".
clubId: ID! — EG "XX11AA01".
personId: ID — Optional. EG "J82SC4X".
siteVisibility: ClubRoleSiteVisibility — Whether this role should be published on KNHB.nl. See RoleSiteVisibility for behavior per value.
Output arguments

deleteClubRole

Mutation

categoryId: ID, clubId: ID!, personId: IDBoolean!

Input arguments
categoryId: ID — Optional. EG "WA".
clubId: ID! — EG "XX11AA01".
personId: ID — Optional. EG "J82SC4X".
Output arguments

ClubRole

Object
active: Boolean!true when this role is active, or false if it is not (yet?)
validFrom: Instant
validTo: Instant
personId: ID!
clubId: ID!
categoryId: ID!
siteVisibility: ClubRoleSiteVisibility — Whether this role should be published on KNHB.nl. See RoleSiteVisibility for behavior per value.

ClubRolesResponse

Object
clubId: ID!
personId: ID
categoryId: ID
permission: ClubRolePermission
count: Int
offset: Int
limit: Int
collection: [ClubRole!]!

ClubRolePermission

Enum
readable
assignable

ClubRoleSiteVisibility

Enum
NONE — This person role is never returned by ApiClubControl.clubs and therefore not shown on knhb.nl. This is the default behavior, and this is equal to public=false
ONLY_ROLE — This person role is returned but contact info is never shown, even if public contact info is present
ROLE_CLUB_EMAIL — This person role is returned with club email for the same club & role category if present. Otherwise, only the role is returned
ROLE_PERSON_CONTACT — This person role is returned with latest person contact if that person contact is public. Otherwise, only the role is returned.
ROLE_ANY_CONTACT — Combines ROLE_CLUB_EMAIL and ROLE_PERSON_CONTACT to fetch either a public club email or public person contact, whichever is available. This value is equal to public=true

Club Person Contacts

Using these APIS, you can manage people's contact details in a club.

You can only read or update a person's contact details if the person is associated to a club. You can associate a person to a club using an invite. See Signup & Invites.

These APIs replace the updatePersonContact API call. E-mail addresses and telephone numbers set by updatePersonContact are returned by this API as legacyEmail and legacyTelephone. When the person's contact details are updated, the legacy* fields are set to NULL, and emails and telephones are set instead.

emails and telephones are sorted lists and their order is stored. The first item in the list is considered the most significant value, or the primary method of contact.

The value must be a normalized, sanitized value. For emails, the value must be a well-formatted e-mail address that you have validated. This API will not validate the e-mail address. emails.value is validated naively using /^[^@\s]+@[^@\s]+$/.

For telephones.value, the value MUST be an international E.164 formatted number starting with a + and no leading zeroes, EG "+31612345678". The value is validated using /^\+[1-9]\d{1,14}$/.

The label is free-form text and should contain a short name of the phone number or e-mail address, EG "Moeder", "Vader", "Thuis" or "Mobiel". There is no defined length limit but any client using the label is free to truncate the value to a reasonable length.

When updating a club person contact, providing an address, emails and telephones is required. You need to provide the full contact details, including the full address, all telephones and all emails. Any value that is omitted is deleted.

For every update, a club_person_contact event is triggered, with the club_id and person_id of the club person.

clubPersonContact

Query

clubId: ID!, personId: ID!ClubPersonContact!

Input arguments
clubId: ID! — Federation reference id of the club, EG XX11AA01.
personId: ID! — ID of the person, EG "J82SC4X".
Output arguments

updateClubPersonContact

Mutation

clubId: ID!, params: ClubPersonContactInput!, personId: ID!ClubPersonContact!

Replace a person's contact details for a club all at once. Be sure to submit all values, any omitted value will be deleted.

Input arguments
clubId: ID! — Federation reference id of the club, EG "XX11AA01".
params: ClubPersonContactInput! — All changes at once.
personId: ID! — ID of the person, EG "J82SC4X".
Output arguments

ClubPersonContact

Object
clubId: ID! — Federation reference id of the club, EG "XX11AA01".
personId: ID! — ID of the person, EG "J82SC4X".
legacyEmail: String — Old e-mail address as provided by legacy APIs like updatePersonContact. Will be NULL if updateClubPersonContact is called once. Unlike emails.value, legacyEmail is just plain text and its value is not guaranteed to be an actual e-mail address.
legacyTelephone: String — Old telephone number as provided by legacy APIs like updatePersonContact. Will be NULL if updateClubPersonContact is called once. Unlike telephones.value, legacyTelephone is just plain text and its value is not guaranteed to be a telephone number.
emails: [ClubPersonContactValue!]! — An array of label/value pairs where the value must be a value that somewhat resembles an e-mail address. This list is sorted by order it was submitted using updateClubPersonContact where the most significant e-mail address is the first value. If updateClubPersonContact is never called, this list will be empty.
telephones: [ClubPersonContactValue!]! — An array of label/value pairs where the value must be a E.164 formatted telephone number. This list is sorted by order it was submitted using updateClubPersonContact where the most significant telephone number is the first value. If updateClubPersonContact is never called, this list will be empty.
address: ClubPersonContactAddress — This person's address. Note that even though submitting an address in updateClubPersonContact is required, technically it is possible for the address to be NULL.

ClubPersonContactAddress

Object
countryCode: String!
regionCode: String
locality: String!
postalCode: String!
streetAddress: String!
streetName: String!
houseNumber: String!
poBoxNumber: String — Usually NULL
lat: Float — Latitude. NULL if not known.
lon: Float — Longitude. NULL if not known.

ClubPersonContactInput

Input Object
emails: [ClubPersonContactValueInput!]! — An array of label/value pairs where the value must be a value that somewhat resembles an e-mail address. This list's order will be saved, where the first value is considered to be the most significant.
telephones: [ClubPersonContactValueInput!]! — An array of label/value pairs where the value must be a E.164 formatted telephone number. This list's order will be saved, where the first value is considered to be the most significant.
address: ClubPersonContactAddressInput! — This person's address.

ClubPersonContactAddressInput

Input Object
countryCode: String!
regionCode: String
locality: String!
postalCode: String!
streetAddress: String!
streetName: String!
houseNumber: String!
poBoxNumber: String — Usually NULL
lat: Float — Latitude. NULL if not known.
lon: Float — Longitude. NULL if not known.

ClubPersonContactValueInput

Input Object
label: String!
value: String!

Other

Uncategorized & undocumented calls

club

Query

id: ID!Club!

Get a single club. Attempting to fetch dissolved or deleted clubs rejects with ClubNotFound

Input arguments
id: ID! — Federation reference id of the club, EG XX11AA01
Output arguments

clubEmail

Query

category: ID!, clubId: ID!, now: InstantClubEmail

Input arguments
category: ID! — ID of the role category. Only role categories with club_staff_assignable permission can be used.
clubId: ID! — Federation reference id of the club, EG XX11AA01.
now: Instantdeprecated — Will use the current date and time at all times. This field is ignored.
Output arguments

clubEmails

Query

clubId: ID!, now: Instant[ClubEmail!]!

Input arguments
clubId: ID! — Federation reference id of the club, EG XX11AA01.
now: Instantdeprecated — Will use the current date and time at all times. This field is ignored.
Output arguments

clubMatch

Query

clubId: ID!, matchId: ID!, seasonId: ID!ClubMatch!

Input arguments
clubId: ID!
matchId: ID!
seasonId: ID!
Output arguments

clubMatches

Query

clubId: ID!, seasonId: ID!, status: [String][ClubMatch!]!

Input arguments
clubId: ID!
seasonId: ID!
status: [String]
Output arguments

clubs

Query

no args[Club!]!

Get all active (non-dissolved) clubs

Input arguments
no args
Output arguments
[Club!]!

districts

Query

no args[District!]!

Get all active districts

Input arguments
no args
Output arguments

facilities

Query

clubId: ID![Facility!]

Get all facilities by club id

Input arguments
clubId: ID! — Federation reference id of the club, EG XX11AA01. Club must be active.
Output arguments

facility

Query

clubId: ID!, id: ID!Facility!

Get a facility by club id & facility ID.

Input arguments
clubId: ID! — Federation reference id of the club, EG XX11AA01. Club must be active.
id: ID! — Rejects with FacilityNotFound if facility does not exist within this club
Output arguments

facilityFields

Query

club: String!, facility: ID![FacilityField!]!

Input arguments
club: String!
facility: ID!
Output arguments

match

Query

id: ID!Match!

Input arguments
id: ID!
Output arguments

matches

Query

no args[Match!]!

Input arguments
no args
Output arguments
[Match!]!

members

Query

clubId: ID!, validAt: DateTimeTz[ClubMember!]!

Get all members of a club at a given point in time

Input arguments
clubId: ID! — Club ID. See clubs
validAt: DateTimeTzdeprecated — Point in time to get members from. This field is ignored, will always use current datetime.
Output arguments

people

Query

birthDate: LocalDate!, familyName: String!, givenName: String, initials: Initials![Person!]!

Get a list of person IDs by givenName, initials, family name and birth date. Will not include deceased people. Note that creating a person might trigger a PersonAlreadyExists error when creating a person even though this call returns no people with the same givenName, initials, familyName or birthDate.

There is no call to reliably check whether createPerson will succeed or not.

If givenName is omitted, givenName is ignored and all matching people will be returned.

Input arguments
birthDate: LocalDate! — Person's date of birth
familyName: String! — Person's family- or surname
givenName: String — Person's first name, or given name. EG 'Paul'. This field is nullable for backwards compatibility reasons, but any blank value will be rejected.
initials: Initials! — Person's initials. Must contain only uppercase letters
Output arguments
[Person!]!

referees

Query

clubId: ID!, now: DateTimeTz[RefereePerson!]!

Get a list of person ids for roles having the RF category in a club

Input arguments
clubId: ID! — Fetch roles for this club
now: DateTimeTz — Ignored and deprecated
Output arguments

roleCategories

Query

no args[RoleCategory!]!

Get all role categories

Input arguments
no args
Output arguments

roles

Query

categoryId: ID, clubId: ID, personId: ID, validAt: DateTimeTz[Role!]!

Fetch all roles for a club or person. You must at least filter by clubId or personId.

Input arguments
categoryId: ID — Optionally filter roles by category id. Should be a role category with 'club_assignable' permission.
clubId: ID — Filter roles by club id
personId: ID — Filter roles by person id
validAt: DateTimeTzdeprecated — Optionally only return roles active at this point in time. If omitted, the current date/time is used.
Output arguments
[Role!]!

seasons

Query

no args[Season!]!

Get all seasons

Input arguments
no args
Output arguments
[Season!]!

sportTypes

Query

no args[SportType!]!

Get sport-types

Input arguments
no args
Output arguments

staffMemberPeople

Query

validAt: DateTimeTz[StaffMemberPerson!]!

Get all staff member people from all clubs, valid at a given point in time.

This call returns alive people with at least one active role with role category having the 'club_staff_assignable' permission. A person is only returned once for one club, even if the person is a staff member in multiple clubs.

staffMemberPeople attempts to fetch contact info for the person.

Input arguments
validAt: DateTimeTz — Ignored and deprecated
Output arguments

team

Query

id: ID!Team!

Input arguments
id: ID!
Output arguments

teamPlayers

Query

teamId: ID!, clubId: ID, date: LocalDate, seasonId: ID, sportTypeId: ID[TeamPlayer!]!

Get a list of team players in a team. Because a team can only be uniquely identified by teamId, clubId and sportTypeId, these 3 fields are all required.

Input arguments
teamId: ID! — Fetch players from this team's id. EG 'MD1' (if clubId & sportTypeId are included) or '1234' (without clubId or sportTypeId)
clubId: IDdeprecated — Fetch players from the team found in this club.
date: LocalDatedeprecated — Fetch team players active on this day
seasonId: IDdeprecated
sportTypeId: IDdeprecated — Fetch players from the team found with this sporttype
Output arguments

teamRoles

Query

teamId: ID!, clubId: ID, seasonId: ID, sportTypeId: ID, validAt: DateTimeTz[TeamRole!]!

Get all active team roles in a team by club, sportType and team id,for role categories with permission 'team_assignable'.

Input arguments
teamId: ID!
clubId: IDdeprecated
seasonId: IDdeprecated
sportTypeId: IDdeprecated
validAt: DateTimeTzdeprecated
Output arguments

teamSubmissionTeams

Query

clubId: ID!, seasonId: ID!, sportTypeId: ID![TeamSubmissionTeam!]!

Find a team submission by season, club and sporttype and return its submitted teams.

Input arguments
clubId: ID!
seasonId: ID!
sportTypeId: ID!
Output arguments

teams

Query

clubId: ID, seasonId: ID, sportTypeId: ID[Team!]!

Get a list of teams by club and sportType

Input arguments
clubId: ID — Fetch teams for this club. If NULL or omitted, all teams are returned.
seasonId: ID — Only fetch teams active in this season. If NULL or omitted, all teams are returned.
sportTypeId: ID — Fetch teams for this sport type. If NULL or omitted, all teams are returned.
Output arguments
[Team!]!

createPerson

Mutation

input: PersonInput!ID!

Create a person for the given params. Rejects with PersonAlreadyExists error if:

  • another person with matching initials, familyName and birthDate already exists.
  • birthDate is 1900-01-01 or NULL, and another person with matching initials, familyName, missing birthDate and givenName already exists. BirthDate '1900-01-01' is considered a magic constant that represents 'unknown birthdate', and equals to using NULL.

Returns the created person's ID.

Input arguments
input: PersonInput!
Output arguments

createRole

Mutation

categoryId: ID!, clubId: ID!, personId: ID!, reason: String, siteVisibility: RoleSiteVisibility, public: Boolean, validFrom: DateTimeTzRole!

Ensure a role is active for a person in a club with a certain role category. In addition to ensuring the role is active, siteVisibility is updated. The person must be an active member of that club in the given point in time. The person must be alive, and the club must not be dissolved. The updated or created role is returned, or the call is rejected with an error.

Input arguments
categoryId: ID! — A role category id with 'club_assignable' permission. See roleCategories
clubId: ID! — Club ID for the new role. See clubs
personId: ID! — Person ID for the new role. See people
reason: String — Optional reason why you're creating this role.
siteVisibility: RoleSiteVisibility — Whether this role should be published on KNHB.nl. See RoleSiteVisibility for behavior per value.
public: Booleandeprecated — Whether this role should be published on KNHB.nl. If false, this role will not be published. If true, this role will be published together with either an e-mail set using updateClubEmail of updatePersonContact. For forward compatibility (public is deprecated), replace public=false with siteVisibility=NONE and public=true with siteVisibility=ROLE_ANY_CONTACT.
validFrom: DateTimeTzdeprecated — No longer used
Output arguments

createTeamRole

Mutation

categoryId: ID!, personId: ID, teamId: ID!, clubId: ID, seasonId: ID, sportTypeId: ID, validFrom: DateTimeTzTeamRole!

Ensure a team role with this role category is active from validFrom for a person in a team. Returns one of the team roles affected.

Input arguments
categoryId: ID!
personId: ID
teamId: ID!
clubId: IDdeprecated
seasonId: IDdeprecated
sportTypeId: IDdeprecated
validFrom: DateTimeTzdeprecated
Output arguments

deleteClubEmail

Mutation

category: ID!, clubId: ID!, now: InstantClubEmail!

Remove an e-mail address by club id and category id from a point in time. Returns any deleted e-mail.

Input arguments
category: ID! — ID of the role category. Only role categories with club_staff_assignable permission can be used.
clubId: ID! — Federation reference id of the club, EG XX11AA01.
now: Instantdeprecated — Will use the current date and time at all times. This field is ignored.
Output arguments

deleteMember

Mutation

clubId: ID!, personId: ID!, validTo: DateTimeTzBoolean!

Ensure a member is no longer active from a point in time by removing active open memberships.

In addition to ending memberships, all active team players and roles are also ended at the same point in time. This is not reversible, but one could create the members, roles and team players.

This operation always returns true, or rejects with error.

Input arguments
clubId: ID! — Club ID. See clubs
personId: ID! — Person ID. See people
validTo: DateTimeTzdeprecated — The membership will be no longer valid at this point in time. This field is ignored, will always use current datetime.
Output arguments

deleteRole

Mutation

categoryId: ID!, clubId: ID!, personId: ID!, reason: String, public: Boolean, validTo: DateTimeTzRole!

Input arguments
categoryId: ID! — A role category id with 'club_assignable' permission. See roleCategories
clubId: ID! — Club ID for the new role. See clubs
personId: ID! — Person ID for the new role. See people
reason: String — Optional reason why you're deleting this role.
public: Booleandeprecated — This field makes absolutely no sense and is ignored.
validTo: DateTimeTzdeprecated — No longer used
Output arguments

deleteTeamRole

Mutation

categoryId: ID!, personId: ID, teamId: ID!, clubId: ID, seasonId: ID, sportTypeId: ID, validTo: DateTimeTzTeamRole!

Ensure a team role with this role category is no longer active from validTo for a person in a team. Returns one of the team roles deleted, or rejects with RoleNotFound if no role exists.

Input arguments
categoryId: ID!
personId: ID
teamId: ID!
clubId: IDdeprecated
seasonId: IDdeprecated
sportTypeId: IDdeprecated
validTo: DateTimeTzdeprecated
Output arguments

endTeamPlayer

Mutation

personId: ID!, teamId: ID!, clubId: ID, endDate: LocalDateOrDateTimeTz, seasonId: ID, sportTypeId: IDTeamPlayer!

Ensure there is no active team player for the given team (by sporttype, club and team) and member (by person id & club id) by updating all active team players with the given enddate.

Input arguments
personId: ID!
teamId: ID!
clubId: IDdeprecated
endDate: LocalDateOrDateTimeTzdeprecated
seasonId: IDdeprecated
sportTypeId: IDdeprecated
Output arguments

personDeceased

Mutation

date: LocalDateOrDateTimeTz!, id: ID!Boolean!

Notify a person is no longer alive. This operation is final and cannot be undone.

Upon this call, the person's decease-date is logged, and all relations are ended at the given date. Memberships (members), Roles (teamRoles, roles), Contacts (updatePersonContact) and team players (teamPlayers) are all ended, deleted or removed permanently.

After this call, referring the deceased person in any other API call will reject with PersonDeceased error, and all other API calls will never include any deceased person or relation of a deceased person.

Input arguments
Output arguments

registerMember

Mutation

clubId: ID!, personId: ID!, validFrom: DateTimeTzBoolean!

Ensure a member is active from a point in time Rejects with MemberIntersection or MemberAlreadyActive error if another membership is already active at that point in time.

This operation always returns true, or rejects with error.

Input arguments
clubId: ID! — Club ID. See clubs
personId: ID! — Person ID. See people
validFrom: DateTimeTzdeprecated — The membership will be valid from this point. This field is ignored, will always use current datetime.
Output arguments

startTeamPlayer

Mutation

jerseyNumber: Int, personId: ID!, position: Int, teamId: ID!, clubId: ID, seasonId: ID, sportTypeId: ID, startDate: LocalDateOrDateTimeTzTeamPlayer!

Ensure a person is member of a team in a club, and update it's jerseyNumber and position. Unless the target team is in a poule period category one of D7 DB DVW DW H7 HB HW XB XW, all existing team players for the same person (even in other clubs) are ended. Using startTeamPlayer to update the jerseyNumber of position will reset the startDate. Given person must be an active member of the club.

Input arguments
jerseyNumber: Int
personId: ID!
position: Int
teamId: ID!
clubId: IDdeprecated
seasonId: IDdeprecated
sportTypeId: IDdeprecated
startDate: LocalDateOrDateTimeTzdeprecated
Output arguments

updateClub

Mutation

id: ID!, input: UpdateClubInput!Club!

Update a non-dissolved club. Will fail with ClubNotFound when trying to update non-dissolved club. For other possible failures, see UpdateClubInput.

Input arguments
id: ID! — Federation reference id of the club, EG XX11AA01
input: UpdateClubInput! — Params to update
Output arguments

updateClubEmail

Mutation

category: ID!, clubId: ID!, email: String, public: Boolean, name: String, now: Instant, publicEmail: BooleanClubEmail!

Set or update an e-mail address for a given role category in a club. If an e-mail address is already active for the same club and role category, it will be deactivated from the given timestamp.

Input arguments
category: ID! — ID of the role category. Only role categories with club_staff_assignable permission can be used.
clubId: ID! — Federation reference id of the club, EG XX11AA01. Club must be active.
email: String — E-mail to set. Club API will not attempt validate or verify the e-mail address. The e-mail address might exposed in other API calls or other APIs. To set exposure on KNHB.nl, use public=true or false.
public: Boolean — When true, the e-mail might be shown on KNHB.nl. When false or omitted, the e-mail is guaranteed to be NOT shown on KNHB.nl. If a person role exists within the club with the same role category, that person's name might be used with this e-mail. See createRole.
name: Stringdeprecated — This field is ignored and will be removed in the future.
now: Instantdeprecated — Will use the current date and time at all times. This field is ignored.
publicEmail: Booleandeprecated — This field is ignored and will be removed in the future.
Output arguments

updateFacilityContact

Mutation

clubId: ID!, facilityId: ID!, input: UpdateContactInput!, now: DateTimeTzBoolean!

Update one or more properties of a facility's contact info. Only changed properties are updated. To explicitly unset a property, use NULL. Always returns TRUE, renders an error otherwise.

Input arguments
clubId: ID! — Federation reference id of the club, EG XX11AA01. Club must be active.
facilityId: ID! — Federation reference id of the person, EG 123.
input: UpdateContactInput! — The new contact info properties.
now: DateTimeTzdeprecated — The new contact info will be active from this point in time.
Output arguments

updateJuniorTeamSubmission

Mutation

clubId: String!, description: String!, seasonId: String!, sportTypeId: String!, teams: [JuniorTeamSubmissionTeamInput!]!JuniorTeamSubmission!

Create or update a junior team submission with a complete set of teams

Input arguments
clubId: String! — ID of club. See clubs
description: String! — Description of this team submission. Usually left blank
seasonId: String! — ID of season. See seasons
sportTypeId: String! — ID of sport type. See sportTypes
teams: [JuniorTeamSubmissionTeamInput!]! — List of teams in this submission
Output arguments

updateMatch

Mutation

club: String, facility: ID, field: ID, id: ID!, input: UpdateMatchInput!Match!

Input arguments
club: String
facility: ID
field: ID
id: ID!
Output arguments

updatePerson

Mutation

id: ID!, input: PersonInput!Boolean!

Update a person by a subset of params. Only provided params are updated. Person must be alive to be updated.

Input arguments
id: ID!
input: PersonInput!
Output arguments

updatePersonContact

Mutation

clubId: ID!, input: UpdateContactInput!, personId: ID!, now: DateTimeTzBoolean!

Update one or more properties of a person's contact info. Only changed properties are updated. To explicitly unset a property, use NULL. Always returns TRUE, renders an error otherwise.

Input arguments
clubId: ID! — Federation reference id of the club, EG XX11AA01. Club must be active.
input: UpdateContactInput! — The new contact info properties.
personId: ID! — Federation reference id of the person, EG X11X11. Person must be alive.
now: DateTimeTzdeprecated — The new contact info will be active from this point in time.
Output arguments

Boolean

The Boolean scalar type represents true or false.

undefined

Club

Object
id: ID!
name: String!
abbreviation: String
district: String
website: String
homekit: String
awaykit: String
email: String
paymentMethods: String
waterPitches: Int
semiWaterPitches: Int
sandPitches: Int
jerseyPictureUrl: String
logoPictureUrl: String
facebook: String
twitter: String
instagram: String
youtube: String
routeInformation: String
parkingInformation: String
telephone: String
description: String
foundingDate: LocalDate
dissolvingDate: LocalDate

ClubEmail

Object
clubId: String!
email: String
validFrom: Instant
validTo: Instant
category: ID
public: Boolean
name: String
publicEmail: Boolean

ClubMatch

Object
id: ID!
subfield: String
facilityId: ID
homeTeam: ClubMatchTeam!
awayTeam: ClubMatchTeam!
pouleId: ID
officialRemarks: String
status: String
homeScore: Int
awayScore: Int
facilityOfficialClubId: ID
facilityFieldId: ID
matchCode: String
homeShootoutScore: Int
awayShootoutScore: Int
isMutable: Boolean!

ClubMatchCategory

Object
id: ID!
name: String

ClubMatchPeriod

Object
id: ID!
name: String

ClubMatchTeam

Object
id: ID!
clubId: ID
name: String
shortName: String
sportType: String

ClubMember

Object
birthDate: LocalDate
familyName: String
personId: ID!

ClubPersonInviteAddress

Object
houseNumber: String! — Full house number, must start with a digit
postalCode: String! — A 1000AA-formatted string
countryCode: String! — Country code. EG 'NL', 2 characters.

DateTimeTz

Scalar

A deprecated, ISO datetime with timezone. Format must match exactly "2018-12-25 23:59:59+01:00".

District

Object
id: String
name: String
description: String

Facility

Object
id: String
name: String
type: String
regionOwner: String
sportlinkFacilityId: String
organizationId: String
clubId: String
isPrimary: Boolean

FacilityAddress

Object
streetName: String
houseNumber: String
postalCode: String
city: String
countryCode: String
lat: Float
lon: Float

FacilityField

Object
id: ID!
name: String
type: String
location: String
facilityName: String

Float

The Float scalar type represents signed double-precision fractional values as specified by IEEE 754.

undefined

Gender

Enum
MALE — This person identifies as male
FEMALE — This person identifies as female
UNKNOWN — This person's gender is unknown or kept private
OTHER — This person identifies as neither male or female

ID

The ID scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as "4") or integer (such as 4) input value will be accepted as an ID.

undefined

Initials

Scalar

Uppercased letters representing the person's initials

Instant

Scalar

A ISO UTC timestamp formatted "2022-12-25T16:00:00Z"

Int

The Int scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.

undefined

JuniorTeamSubmission

Object
sportTypeId: String!
clubId: String!
seasonId: String!
description: String!

JuniorTeamSubmissionTeamFrom

Object
name: String!
count: Int!
description: String!

JuniorTeamSubmissionTeamFromInput

Input Object
name: String!
count: Int!
description: String!

LocalDate

Scalar

A YYYY-MM-DD formatted date

LocalDateOrDateTimeTz

Scalar

A deprecated, lossy input date-timeformat, either a DateTimeTz or a LocalDate. Providing a LocalDate is not recommended, but supported due to backwards compatibility.

LocalDateTime

Scalar

A ISO local datetime. Format must match exactly "2018-12-25T23:59:59". Seconds can be omitted if they're ":00".

Note the absense of a timezone or offset. The local date & time represents the calendar date and wall time relevant to the associated location. IE if a match date is "2018-12-25T14:00" in the Netherlands (Europe/Amsterdam, GMT+01:00), the match is played at "2018-12-25T13:00:00Z".

The timezone or offset is usually implied from the location. Unless specified, it is usually Europe/Amsterdam.

Match

Object
id: ID!
subfield: String
fieldName: String
fieldType: String
facilityName: String
homeTeamName: String
awayTeamName: String
poule: String
officialRemarks: String
isMutable: Boolean!

Mutation

Object
createPerson: ID!
updatePerson: Boolean!
personDeceased: Boolean!

Person

Object
id: ID!

PersonInput

Input Object
birthDate: LocalDate
givenName: String
namePrefix: String
familyName: String
initials: Initials
gender: Gender

Query

Object
people: [Person!]!

RefereePerson

Object
id: ID!

Role

Object
categoryId: ID
personId: ID
clubId: ID!
validFrom: DateTimeTz
validTo: DateTimeTz
public: Boolean
siteVisibility: RoleSiteVisibility!

RoleCategory

Object
id: ID!
name: String!
limit: Int!
permissions: [String!]!

RoleSiteVisibility

Enum
NONE — This person role is never returned by ApiClubControl.clubs and therefore not shown on knhb.nl. This is the default behavior, and this is equal to public=false
ONLY_ROLE — This person role is returned but contact info is never shown, even if public contact info is present
ROLE_CLUB_EMAIL — This person role is returned with club email for the same club & role category if present. Otherwise, only the role is returned
ROLE_PERSON_CONTACT — This person role is returned with latest person contact if that person contact is public. Otherwise, only the role is returned.
ROLE_ANY_CONTACT — Combines ROLE_CLUB_EMAIL and ROLE_PERSON_CONTACT to fetch either a public club email or public person contact, whichever is available. This value is equal to public=true

Season

Object
id: ID!
description: String
startDate: LocalDate
endDate: LocalDate
shortName: String
active: Boolean

SportType

Object
id: ID!

StaffMemberPerson

Object
id: ID!
givenName: String
initials: String
familyName: String
namePrefix: String
clubId: ID
email: String
telephone: String

String

The String scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.

undefined

Team

Object
id: ID!
newId: ID!
name: String
sportTypeId: ID
clubId: ID
shortName: String
sportlinkId: ID

TeamPlayer

Object
personId: ID!
jerseyNumber: Int
position: Int
startDate: LocalDate!
endDate: LocalDate

TeamRole

Object
categoryId: ID
personId: ID
validFrom: DateTimeTz!
validTo: DateTimeTz

TeamSubmissionTeam

Object
shortName: ID!
description: String
level: String

UpdateClubInput

Input Object
name: String
abbreviation: String
district: String
website: String
homekit: String
awaykit: String
email: String
paymentMethods: String
waterPitches: Int
semiWaterPitches: Int
sandPitches: Int
jerseyPictureUrl: String
logoPictureUrl: String
facebook: String
twitter: String
instagram: String
youtube: String
routeInformation: String
parkingInformation: String
telephone: String
description: String
foundingDate: LocalDate
dissolvingDate: LocalDate

UpdateContactInput

Input Object
email: String
telephone: String
countryCode: String
regionCode: String
locality: String
postalCode: String
streetAddress: String
streetName: String
houseNumber: String
poBoxNumber: String
public: Boolean
lat: Float
lon: Float

UpdateMatchInput

Input Object
time: String
subfield: String
officialClub: String
officialRemarks: String
facilityId: ID
facilityFieldId: ID

__Directive

A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.

In some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.

undefined

__DirectiveLocation

A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.

undefined

__EnumValue

One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.

undefined

__Field

Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.

undefined

__InputValue

Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.

undefined

__Schema

A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.

undefined

__Type

The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the __TypeKind enum.

Depending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name and description, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.

undefined

__TypeKind

An enum describing what kind of type a given __Type is.

undefined