2025-09-02 16:09:17 +09:00
# Salesforce-to-Portal Order Communication Guide
2025-09-06 10:01:44 +09:00
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.
2025-09-02 16:09:17 +09:00
## 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")
2025-09-06 10:01:44 +09:00
2. Salesforce operator approves Order
3. Salesforce Flow publishes OrderProvisionRequested__e
4. Portal subscriber enqueues a job → provisions in WHMCS → updates Salesforce Order status
2025-09-02 16:09:17 +09:00
5. Customer sees updated status in Portal
```
## 1. Salesforce → Portal (Order Provisioning)
2025-09-06 10:01:44 +09:00
### Recommended (2025): Async via Platform Events ✅
2025-09-02 16:09:17 +09:00
2025-09-06 10:01:44 +09:00
High-level flow
2025-09-02 16:09:17 +09:00
```
2025-09-06 10:01:44 +09:00
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)
2025-09-02 16:09:17 +09:00
```
2025-09-06 10:01:44 +09:00
Salesforce Setup
2025-09-02 16:09:17 +09:00
2025-09-06 10:01:44 +09:00
- 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
2025-09-02 16:09:17 +09:00
2025-09-06 10:01:44 +09:00
Portal Setup
2025-09-02 16:09:17 +09:00
2025-09-06 10:01:44 +09:00
- 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
2025-09-02 16:09:17 +09:00
2025-09-06 10:01:44 +09:00
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.
2025-09-02 16:09:17 +09:00
2025-09-06 10:01:44 +09:00
### Legacy Implementation (Webhook) — Removed
2025-09-02 16:09:17 +09:00
2025-09-06 10:01:44 +09:00
The old endpoint `POST /orders/{sfOrderId}/fulfill` has been removed. Provisioning is now triggered solely via Platform Events published from Salesforce.
2025-09-02 16:09:17 +09:00
2025-09-06 10:01:44 +09:00
### Enhanced Security Implementation (Legacy Webhook)
2025-09-02 16:09:17 +09:00
2025-09-06 10:01:44 +09:00
All Quick Actions and Named Credentials previously used to call the portal should be retired.
### Salesforce Apex Implementation (not needed)
2025-09-09 18:19:54 +09:00
2025-09-06 10:01:44 +09:00
No Apex callout to the portal is required. Use a Record-Triggered Flow to publish the Platform Event.
2025-09-02 16:09:17 +09:00
2025-09-06 10:01:44 +09:00
## 2. Security Configuration
2025-09-02 16:09:17 +09:00
### Environment Variables
```bash
2025-09-06 10:01:44 +09:00
# Platform Events (BFF)
SF_EVENTS_ENABLED=true
SF_PROVISION_EVENT_CHANNEL=/event/OrderProvisionRequested__e
SF_EVENTS_REPLAY=LATEST # or ALL
2025-09-02 16:09:17 +09:00
```
### Salesforce Named Credential
2025-09-09 18:19:54 +09:00
2025-09-06 10:01:44 +09:00
Not required for the async path; the portal pulls events from Salesforce.
2025-09-02 16:09:17 +09:00
## 4. Customer Experience
### Portal UI Polling
The portal should poll for order status updates:
```typescript
// In your Portal UI
export function useOrderStatus(sfOrderId: string) {
2025-09-09 18:19:54 +09:00
const [status, setStatus] = useState< OrderStatus > ("Pending Review");
2025-09-02 16:09:17 +09:00
useEffect(() => {
const pollStatus = async () => {
try {
const response = await fetch(`/api/orders/${sfOrderId}` );
const data = await response.json();
setStatus(data.status);
2025-09-09 18:19:54 +09:00
2025-09-02 16:09:17 +09:00
// Stop polling when order is complete
2025-09-09 18:19:54 +09:00
if (["Provisioned", "Failed"].includes(data.status)) {
2025-09-02 16:09:17 +09:00
clearInterval(interval);
}
} catch (error) {
2025-09-09 18:19:54 +09:00
console.error("Failed to fetch order status:", error);
2025-09-02 16:09:17 +09:00
}
};
2025-09-09 18:19:54 +09:00
2025-09-02 16:09:17 +09:00
const interval = setInterval(pollStatus, 5000); // Poll every 5 seconds
pollStatus(); // Initial fetch
2025-09-09 18:19:54 +09:00
2025-09-02 16:09:17 +09:00
return () => clearInterval(interval);
}, [sfOrderId]);
2025-09-09 18:19:54 +09:00
2025-09-02 16:09:17 +09:00
return status;
}
```
## 5. Monitoring and Alerting
### Key Metrics to Monitor
- **Provisioning Success Rate**: Track successful vs failed provisioning attempts
2025-09-06 10:01:44 +09:00
- **Provisioning Latency**: Time from SF approval to completion
2025-09-02 16:09:17 +09:00
- **WHMCS API Errors**: Monitor WHMCS integration health
2025-09-06 10:01:44 +09:00
- **Event Lag**: Time between event publish and job enqueue/complete
2025-09-02 16:09:17 +09:00
### Alert Conditions
```typescript
// Example monitoring service
@Injectable ()
export class OrderProvisioningMonitoringService {
async recordProvisioningAttempt(sfOrderId: string, success: boolean, duration: number) {
// Record metrics
2025-09-09 18:19:54 +09:00
this.metricsService.increment("order.provisioning.attempts", {
2025-09-02 16:09:17 +09:00
success: success.toString(),
});
2025-09-09 18:19:54 +09:00
this.metricsService.histogram("order.provisioning.duration", duration);
2025-09-02 16:09:17 +09:00
// Alert on high failure rate
const recentFailureRate = await this.getRecentFailureRate();
2025-09-09 18:19:54 +09:00
if (recentFailureRate > 0.1) {
// 10% failure rate
await this.alertingService.sendAlert("High order provisioning failure rate");
2025-09-02 16:09:17 +09:00
}
}
}
```
## 6. Testing
2025-09-06 10:01:44 +09:00
### Event Flow Testing
2025-09-02 16:09:17 +09:00
2025-09-06 10:01:44 +09:00
Validate that an `OrderProvisionRequested__e` event enqueues a job and runs the orchestrator. Check logs and `/health/sf-events` for status and cursor.
2025-09-02 16:09:17 +09:00
## Summary
This focused approach ensures secure communication specifically for your **order provisioning workflow** :
2025-09-06 10:01:44 +09:00
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
2025-09-02 16:09:17 +09:00
2025-09-06 10:01:44 +09:00
The security relies on your existing JWT-based Salesforce API integration and ; no inbound webhooks are required.