Champagne

Onboarding operations

Club-scoped onboarding query, special blocks, attachments, and validation.

onboardings(clubId: ID!) returns every onboarding owned by a club. Use onboarding(clubId: ID!, id: ID!) for one record. Each returns id, clubId, name, description, revision, and ordered questions plus afterApproval and hosted configurations. Hosted settings include enabled, slug, font, and primaryColor. Each block includes id, title, type, required, options, nullable documentName, nullable documentData, nullable personField and attributeKey targets, the answer format, and, for identity verification and booking blocks, identityVerification and reservationCategoryId. Questions and after-approval steps share this shape.

query ClubOnboardings($clubId: ID! = "51000000-0000-4000-8000-000000000051") {
  onboardings(clubId: $clubId) {
    id
    clubId
    name
    description
    revision
    questions {
      id
      title
      type
      required
      options
      documentName
      documentData
    }
    afterApproval {
      redirectUrl
      steps {
        id
        type
        documentName
      }
    }
  }
}

The example defaults to the seeded Ukab Clubs club and runs with empty variables ({}). Override clubId with an ID from clubDirectory to inspect another club. An unavailable club returns an empty list.

hostedOnboarding(slug: String!, id: ID!) is the public lookup used by https://<club-slug>.champagne.dev-ukab.fr/onboarding/<onboarding-id>. The slug belongs to the club and is configured once in club settings; id selects one of that club's published onboardings. Disabled, unknown, or mismatched combinations return null.

updateClubHostedSlug(clubId: ID!, slug: String) sets that club-wide slug and returns the updated Club (id, name, hostedSlug, ...). It requires settings_manage in the club. The slug is trimmed and lowercased before validation and must be 3–63 lowercase letters, numbers, or inner hyphens. The platform's own subdomains (app, api, consumer, docs, mail, news, staging, www) are refused with BAD_USER_INPUT. null or a blank string removes it, which takes every hosted onboarding of the club offline. Slugs are unique across clubs: a slug already used by another club returns BAD_USER_INPUT ("This address is already used by another club.") and leaves both clubs unchanged. An unknown club returns BAD_USER_INPUT ("This club is unavailable."). The change is recorded in the club's activity history.

mutation SetHostedSlug($clubId: ID!, $slug: String) {
  updateClubHostedSlug(clubId: $clubId, slug: $slug) {
    id
    hostedSlug
  }
}

createOnboarding(input: CreateOnboardingInput!) accepts a clubId, name, and description. It creates a revision-one onboarding with required name and email-verification blocks and returns { onboarding, error }. The generated onboarding ID is a compact value such as onb_4f3a2b1c9d; seeded journeys use readable IDs such as common-members.

saveOnboarding(input: SaveOnboardingInput!) accepts id, clubId, name, description, the loaded revision, the complete ordered questions array, and afterApproval, and hosted. Hosted settings retain per-onboarding enablement, font, and primary color; the shared subdomain is not part of this input. It edits that onboarding atomically, increments its revision, and returns { onboarding, error }. A stale revision or unavailable club/onboarding returns a readable error. For a club with the billing module turned off, a PLAN_SELECTION or PLAN_PAYMENT step returns the error "Payments are turned off for this club.", and onboarding, onboardings and hostedOnboarding leave those steps out; see Clubs with billing turned off.

mutation SaveOnboarding($input: SaveOnboardingInput!) {
  saveOnboarding(input: $input) {
    onboarding {
      id
      revision
    }
    error
  }
}

An OnboardingQuestionInput supplies id, title, type, required, and options. For ordinary choice questions, options contains labels. For plan selection, it contains the plan IDs offered during onboarding; an empty list retains the legacy behavior of offering every currently available club plan. Other special blocks use required: true and options: [].

TypeRules
SHORT_ANSWEROnly in questions; empty options; optional personField or attributeKey target
LONG_ANSWEROnly in questions; empty options; optional text attributeKey target
OPTIONSOnly in questions; 2–20 distinct choices (case-insensitive after trimming), or choices taken from its personField or attributeKey target
PLAN_SELECTIONOnly in questions; at most one; up to 100 distinct plan IDs in options
PLAN_PAYMENTOnly in afterApproval.steps; at most one; requires plan selection
DOCUMENT_SIGNATUREOnly in afterApproval.steps; at most one; required PDF attachment
IDENTITY_VERIFICATIONEither side; at most one overall; always required; optional identityVerification checks; refused when Stripe Identity is not configured
EMAIL_OTPOnly in questions; exactly one, required; empty options
PHONE_OTPEither side; at most one overall; always required; empty options; verifies a mobile number by text message and saves it as the person phone number
PERSON_NAMEOnly in questions; exactly one, required; empty options
PERSON_ADDRESSEither side; at most one overall; empty options; collects a structured Address (line1, line2, city, postalCode, state, country) saved as the person address
RESERVATION_BOOKINGEither side; at most one overall; requires reservationCategoryId (see Booking step); required may be false

"Either side" blocks can be placed in questions (answered while the application is a draft) or in afterApproval.steps (answered once accepted), but only once across both lists. Before approval, IDENTITY_VERIFICATION and RESERVATION_BOOKING must come after the PERSON_NAME and EMAIL_OTP blocks. Address and phone answered before approval are forwarded to the person on acceptance; after approval they are saved on the person immediately. Breaking these rules returns BAD_USER_INPUT with one of:

  • "After approval can only contain plan payment, document signature, address, phone verification, identity verification and booking steps."
  • "Plan payment and document signature belong in After approval."
  • "Applicant address can appear only once."
  • "Phone verification can appear only once and is always required."
  • "Identity verification can appear only once."
  • "Booking can appear only once."
  • "Place identity verification and booking after the applicant name and email."

The afterApproval object contains an ordered steps array and an optional absolute HTTP(S) redirectUrl. A custom frontend receives the application ID in that URL's applicationId query parameter. When the URL is omitted, approval emails link to Champagne's consumer app.

Names allow 1–200 trimmed characters and descriptions 1–1000. Onboardings contain 1–50 application blocks with unique UUIDs. Onboarding IDs contain 3–32 lowercase letters, numbers, underscores, or hyphens and begin with a letter. Block titles allow 1–500 trimmed characters and option labels 1–200. Invalid inputs yield GraphQL BAD_USER_INPUT before any database write.

Hosted slugs use 3–63 lowercase letters, numbers, and hyphens, cannot begin or end with a hyphen, and cannot use reserved Champagne service labels. Enabled slugs are globally unique. The font is one of MODERN, CLASSIC, or EDITORIAL; the primary color is a six-digit hexadecimal color.

Supply both documentName and canonical base64 documentData for signature blocks. Names allow up to 200 characters and must end in .pdf. The API checks the PDF header and a 2 MiB decoded size per document; total document data is limited to 4 MiB. Other block types reject attachments.

Booking step

A RESERVATION_BOOKING block lets an applicant book a visit, for example a discovery tour, either while applying or once accepted, before becoming a member. reservationCategoryId names the reservation category it books; other block types reject the field with BAD_USER_INPUT, and a booking block without a valid UUID receives BAD_USER_INPUT: "Choose the reservation category of each booking step.". These rules apply on either side. When saving, the category must also be:

  • a category of the same club; a category of another club or one that no longer exists returns error: "Choose a reservation category of this club for each booking step.";
  • booked by time slot (slotBooking), otherwise error: "Choose a reservation category booked by time slot.";
  • free: no resource with an amount, a depositAmount or a plan price above 0, otherwise error: "Onboarding visits are free. Choose a category without prices.". Onboarding never takes payment for a booking; charge for later visits through billing.

Mark the category onboardingOnly to keep it out of member booking. A category used by a booking block on either side cannot be deleted while the block remains: deleteReservationCategory returns error: "An onboarding booking step uses this category. Remove the step first.". Applicants book through the application booking operations.

Question targets and answer formats are described in Member attributes.

Application execution is handled by application operations. Payment and document signatures are available only after acceptance. Payment uses hosted Stripe Checkout (see application operations); document signatures use Yousign's hosted flow and a server-verified completion operation. Email verification sends a real message through the configured mail provider.

IDENTITY_VERIFICATION asks applicants to verify an ID document with Stripe Identity. Its identityVerification: IdentityVerificationSettingsInput sets the checks; it is only accepted on this block type and defaults to:

FieldDefaultRule
minimumAge18Integer 0–99 compared with the document's date of birth; 0 disables the age check
requireSelfietrueStripe compares a selfie with the document photo (require_matching_selfie)
requireNameMatchtrueEvery word of the applicant's first and last name must appear in the document's name

identityVerificationAvailable(clubId: ID!): Boolean! tells staff editors whether this server can run Stripe Identity. When it is false, saveOnboarding refuses an onboarding that contains the step with BAD_USER_INPUT "Identity verification with Stripe Identity is not configured on this server." The query needs staff access to the club.

query IdentityVerificationAvailable($clubId: ID!) {
  identityVerificationAvailable(clubId: $clubId)
}

SPONSORS adds a required sponsorship question answered with one-time sponsor codes (see sponsorship). sponsorCount accepts 1–5 (default 2) and is returned on questions; it is null for other block types. One sponsorship block is allowed per onboarding. The configuration is copied into new applications.

Sur cette page