# Salesforce-to-Portal Order Communication Guide Note: 2025 update — Async-first via Salesforce Platform Events is now the recommended pattern. The legacy webhook path remains referenced only historically and should be phased out. ## Overview This guide focuses specifically on **secure communication between Salesforce and your Portal for order provisioning**. This is NOT about invoices or billing - it's about the order approval and provisioning workflow. ## The Order Flow ``` 1. Customer places order → Portal creates Salesforce Order (Status: "Pending Review") 2. Salesforce operator approves Order 3. Salesforce Flow publishes OrderProvisionRequested__e 4. Portal subscriber enqueues a job → provisions in WHMCS → updates Salesforce Order status 5. Customer sees updated status in Portal ``` ## 1. Salesforce → Portal (Order Provisioning) ### Recommended (2025): Async via Platform Events ✅ High-level flow ``` 1. Operator marks Order Approved in Salesforce 2. Record-Triggered Flow publishes Order_Fulfilment_Requested__e 3. Portal subscribes via Pub/Sub API (gRPC) and enqueues a provisioning job 4. Portal provisions in WHMCS and updates Salesforce Order status 5. Portal UI polls BFF for status (unchanged) ``` Salesforce Setup - Create High-Volume Platform Event: `Order_Fulfilment_Requested__e` - Fields (example API names): - `OrderId__c` (Text 18) — required - `IdemKey__c` (Text 80) — optional (Idempotency key) - `CorrelationId__c` (Text 80) — optional - `RequestedBy__c` (Text 80) — optional - `Version__c` (Number) — optional - Flow: Record-Triggered on Order when Status changes to Approved - Actions: - Update `Activation_Status__c = Activating` - Create `OrderProvisionRequested__e` and set `OrderId__c = $Record.Id` - Optionally clear activation error fields Portal Setup - Env - `SF_EVENTS_ENABLED=true` - `SF_PROVISION_EVENT_CHANNEL=/event/OrderProvisionRequested__e` - `SF_EVENTS_REPLAY=LATEST` (or `ALL` to start from earliest retained) - Subscriber (auto-start, durable replay): `apps/bff/src/vendors/salesforce/events/pubsub.subscriber.ts` - Subscribes to the channel and enqueues a job to the `provisioning` queue - Worker: `apps/bff/src/orders/queue/provisioning.processor.ts` - Guards on `Activation_Status__c = Activating`; provisions in WHMCS and then updates Salesforce Why async: resilient (replay within retention), decoupled, no inbound allowlisting. No auto-retries from the portal; operators retry from Salesforce by flipping status to Activating. ### Legacy Implementation (Webhook) — Removed The old endpoint `POST /orders/{sfOrderId}/fulfill` has been removed. Provisioning is now triggered solely via Platform Events published from Salesforce. ### Enhanced Security Implementation (Legacy Webhook) All Quick Actions and Named Credentials previously used to call the portal should be retired. ### Salesforce Apex Implementation (not needed) No Apex callout to the portal is required. Use a Record-Triggered Flow to publish the Platform Event. ## 2. Security Configuration ### Environment Variables ```bash # Platform Events (BFF) SF_EVENTS_ENABLED=true SF_PROVISION_EVENT_CHANNEL=/event/OrderProvisionRequested__e SF_EVENTS_REPLAY=LATEST # or ALL ``` ### Salesforce Named Credential Not required for the async path; the portal pulls events from Salesforce. ## 4. Customer Experience ### Portal UI Polling The portal should poll for order status updates: ```typescript // In your Portal UI export function useOrderStatus(sfOrderId: string) { const [status, setStatus] = useState("Pending Review"); useEffect(() => { const pollStatus = async () => { try { const response = await fetch(`/api/orders/${sfOrderId}`); const data = await response.json(); setStatus(data.status); // Stop polling when order is complete if (["Provisioned", "Failed"].includes(data.status)) { clearInterval(interval); } } catch (error) { console.error("Failed to fetch order status:", error); } }; const interval = setInterval(pollStatus, 5000); // Poll every 5 seconds pollStatus(); // Initial fetch return () => clearInterval(interval); }, [sfOrderId]); return status; } ``` ## 5. Monitoring and Alerting ### Key Metrics to Monitor - **Provisioning Success Rate**: Track successful vs failed provisioning attempts - **Provisioning Latency**: Time from SF approval to completion - **WHMCS API Errors**: Monitor WHMCS integration health - **Event Lag**: Time between event publish and job enqueue/complete ### Alert Conditions ```typescript // Example monitoring service @Injectable() export class OrderProvisioningMonitoringService { async recordProvisioningAttempt(sfOrderId: string, success: boolean, duration: number) { // Record metrics this.metricsService.increment("order.provisioning.attempts", { success: success.toString(), }); this.metricsService.histogram("order.provisioning.duration", duration); // Alert on high failure rate const recentFailureRate = await this.getRecentFailureRate(); if (recentFailureRate > 0.1) { // 10% failure rate await this.alertingService.sendAlert("High order provisioning failure rate"); } } } ``` ## 6. Testing ### Event Flow Testing Validate that an `OrderProvisionRequested__e` event enqueues a job and runs the orchestrator. Check logs and `/health/sf-events` for status and cursor. ## Summary This focused approach ensures secure communication specifically for your **order provisioning workflow**: 1. **Salesforce Flow** → Publishes Platform Event `OrderProvisionRequested__e` 2. **Portal BFF** → Subscribes, queues job, provisions in WHMCS, updates Salesforce 3. **Customer** → Sees real-time order status in Portal UI The security relies on your existing JWT-based Salesforce API integration and ; no inbound webhooks are required.