# GetBillingClientToken - Advanced Documentation ## Overview Generates a Braintree client token for secure payment processing, automatically creating the customer record in Braintree if it doesn't exist. Enforces ManageFirm permission and retries on transient failures. ## Business Rules - The Braintree customer ID is the company's ID (as a string) - If the Braintree customer does not exist, one is created automatically using the current person's name/email and the company name - The client token is generated with card verification enabled (`VerifyCard = true`) - The newest payment method is always set as default (`MakeDefault = true`) - The operation is wrapped in `Retry.ExecuteAsync`, which retries on transient failures (the catch block re-throws to trigger retry) - On the first call for a new company, the flow is: attempt token generation, fail with "customer not found", create customer, retry token generation ## Permissions & Security - Caller must be logged in (`curPerson.ID >= 1`) - Caller must have a company selected (`curCompany.ID >= 1`) - Caller must be a member of the current company (`IsPartOfCompany` check) - Caller must have the **ManageFirm** permission ## Data Flow 1. Validate authentication: person logged in, company selected, company membership 2. Validate ManageFirm permission 3. Initialize Braintree gateway using app settings (environment, merchant, public key, private key) 4. Enter retry loop via `Retry.ExecuteAsync` 5. Attempt to generate a client token for the company's customer ID 6. If successful, return the token string 7. If the error is "Customer specified by customer_id does not exist": a. Create a new Braintree customer with ID=CompanyID, the current person's name/email, and the company name b. If customer creation fails, throw a RadoloException with the Braintree error message and parameters c. Re-throw the original exception to trigger a retry (which will now succeed since the customer exists) 8. For any other exception, re-throw to trigger retry or propagate ## Side Effects - **External API call**: Braintree `ClientToken.GenerateAsync` called to generate a payment token - **External API call**: Braintree `Customer.CreateAsync` called if the customer does not exist (creates a customer record in Braintree's system) - No database writes occur in this endpoint ## Error Conditions - `RadoloException("You must be logged in to perform this action.")` - not authenticated - `RadoloException("You must have a company selected to perform this action.")` - no company - `RadoloException("You can only manage a subscripton for a company that you are part of[{personID},{companyID}].")` - not in company (note: typo "subscripton" is in the source) - `RadoloException("You do not have the Manage Firm permission.")` - missing ManageFirm - `RadoloException(braintreeMessage)` with Braintree parameters in exception Data - customer creation failed in Braintree - Transient Braintree API failures may propagate after retries are exhausted ## Usage Notes - This endpoint returns a raw string token, not a JSON object. The client should use this token to initialize the Braintree Drop-in UI or hosted fields. - The Braintree gateway configuration comes from four required AppSettings: `BraintreeEnvironment`, `BraintreeMerchant`, `BraintreePublic`, `BraintreePrivate`. Missing any of these will throw a RadoloException at class initialization time. - The `BraintreeEnvironment` setting controls whether the gateway connects to Braintree Sandbox or Production. The value "Production" (case-insensitive) routes to production; anything else routes to sandbox. - The customer creation uses the current user's identity (name/email), so the first admin to set up billing becomes the Braintree contact. This does not change on subsequent calls. - The retry mechanism means transient network issues with Braintree are handled transparently. However, if Braintree is fully down, the retries will eventually exhaust and the error will propagate. - The client token is short-lived (Braintree default is typically 24 hours). Generate a fresh token for each payment session.