Overview
The FaxIntegrationService is a dedicated microservice that consolidates all fax operations into a single service. It handles both inbound faxes (receiving from RingCentral, storing in Azure Blob, publishing events) and outbound faxes (sending to pharmacies via RingCentral).Release: v2.11.0 (December 17, 2025)This service was extracted from
CurentaOrderTriagingCoreApi to improve separation of concerns and system reliability.Key Responsibilities
Inbound Fax Processing:| Responsibility | Description |
|---|---|
| Webhook Handling | Receives and validates RingCentral fax webhook notifications |
| PDF Download | Downloads fax PDF attachments from RingCentral API |
| Blob Upload | Uploads fax documents to Azure Blob Storage |
| Event Publishing | Publishes FaxNotificationReceived event to Service Bus |
| Responsibility | Description |
|---|---|
| Pharmacy Fax Sending | Sends order documents to pharmacies via RingCentral |
| Delivery Tracking | Tracks fax delivery status with improved logging |
| Status Reporting | Reports delivery success/failure back to calling service |
Service Metadata
| Property | Value |
|---|---|
| Repository | https://github.com/AllCare-ai/FaxIntegrationService |
| Technology | .NET 8 |
| Database | None (stateless) |
| Message Broker | Azure Service Bus |
| External APIs | RingCentral, Azure Blob Storage |
Architecture
High-Level Design
Inbound Data Flow
1
Webhook Received
RingCentral sends a webhook notification to FaxIntegrationService when a new fax arrives
2
Validation
Service validates the webhook payload and extracts fax metadata (message ID, sender, etc.)
3
PDF Download
Service authenticates with RingCentral API and downloads the fax PDF attachment
4
Blob Upload
PDF is uploaded to Azure Blob Storage with appropriate metadata
5
Event Published
FaxNotificationReceived event is published to Service Bus with blob URL and metadata6
Downstream Processing
CurentaOrderTriagingCoreApi subscribes to the event and processes the fax for order triaging
Outbound Data Flow
1
Send Request
CurentaOrderTriagingCoreApi calls FaxIntegrationService with document and recipient details
2
Fax Transmission
FaxIntegrationService sends the fax to the pharmacy via RingCentral API
3
Delivery Tracking
Service monitors RingCentral for delivery status updates
4
Status Response
Delivery status (success/failure) is returned to the calling service
API Reference
Webhook Endpoint
POST /api/fax/webhook
Receives incoming fax notifications from RingCentral. Headers:| Header | Description |
|---|---|
Validation-Token | RingCentral webhook validation token (returned in response for subscription verification) |
| Status | Description |
|---|---|
200 OK | Webhook processed successfully |
200 OK with Validation-Token header | Subscription verification response |
400 Bad Request | Invalid payload or processing failed |
Outbound Fax Endpoint
POST /api/fax/send
Sends a fax to a pharmacy or other recipient.Authentication Required — This endpoint requires JWT Bearer token authentication.
| Header | Description |
|---|---|
Authorization | Bearer token for authentication |
Content-Type | application/json |
| Field | Type | Required | Description |
|---|---|---|---|
recipientFaxNumber | string | Yes | Destination fax number (E.164 format) |
recipientName | string | No | Name of recipient for cover page |
documentUrl | string | Yes | URL to the PDF document to fax |
orderId | guid | No | Associated order ID for tracking |
coverPageText | string | No | Text to include on fax cover page |
priority | string | No | normal or high (default: normal) |
| Status | Description |
|---|---|
200 OK | Fax queued successfully |
400 Bad Request | Invalid request (missing fields, invalid fax number) |
401 Unauthorized | Missing or invalid authentication |
500 Internal Server Error | RingCentral API error |
GET /api/fax/status/
Gets the delivery status of a sent fax. Parameters:| Name | Type | Description |
|---|---|---|
faxId | string | The fax ID returned from the send endpoint |
| Status | Description |
|---|---|
Queued | Fax is queued for sending |
Sending | Fax is currently being transmitted |
Delivered | Fax was successfully delivered |
Failed | Fax delivery failed |
Busy | Recipient line was busy |
NoAnswer | Recipient did not answer |
Event Schema
FaxNotificationReceived
Published to Service Bus after successful fax ingestion.Configuration
Application Settings
Environment Variables
| Variable | Description | Required |
|---|---|---|
RingCentral__ClientId | RingCentral OAuth client ID | Yes |
RingCentral__ClientSecret | RingCentral OAuth client secret | Yes |
RingCentral__JwtToken | RingCentral JWT for authentication | Yes |
RingCentral__ReceiveExtensionId | Extension ID for receiving faxes | Yes |
AzureStorage__ConnectionString | Azure Blob Storage connection string | Yes |
AzureStorage__ContainerName | Blob container name | Yes |
ServiceBus__ConnectionString | Azure Service Bus connection string | Yes |
ServiceBus__TopicName | Topic for publishing events | Yes |
Migration from CurentaOrderTriagingCoreApi
What Was Removed
The following components were removed fromCurentaOrderTriagingCoreApi:
Inbound Fax Processing:
| Component | Previous Location | New Location |
|---|---|---|
| RingCentral Webhook Handler | FaxController.ValidateWebhook() | FaxIntegrationService |
| RingCentral Subscription Setup | RinCentralSubscription.cs | FaxIntegrationService |
| PDF Download Logic | RinCentralSubscription.GetAttachmentContent() | FaxIntegrationService |
| Blob Storage Upload | FaxService (inline) | FaxIntegrationService |
| Component | Previous Location | New Location |
|---|---|---|
| Pharmacy Fax Sending | FaxSenderService | FaxIntegrationService |
| RingCentral Send API | Orders service (inline) | FaxIntegrationService |
What Remains in CurentaOrderTriagingCoreApi
| Component | Description |
|---|---|
FaxController | Still handles fax history, listing, and processing actions |
FaxService | Still processes faxes for order triaging after receiving events |
FaxNotificationHub | SignalR hub for real-time notifications (unchanged) |
| Service Bus Consumer | Subscribes to FaxNotificationReceived events |
| Fax Send Client | Calls FaxIntegrationService to send outbound faxes |
Breaking Changes
For developers:| Change | Impact |
|---|---|
| Webhook URL change | RingCentral subscription must point to FaxIntegrationService URL |
| Service Bus dependency | CurentaOrderTriagingCoreApi must subscribe to fax-notifications topic |
| Outbound fax API | Orders service must call FaxIntegrationService API instead of sending directly |
Monitoring & Observability
Health Checks
| Endpoint | Description |
|---|---|
GET /health/live | Liveness probe |
GET /health/ready | Readiness probe (checks RingCentral, Blob, Service Bus connectivity) |
Key Metrics
Inbound Fax Metrics:| Metric | Description |
|---|---|
fax.inbound.received | Count of webhook notifications received |
fax.inbound.downloaded | Count of PDFs successfully downloaded |
fax.inbound.uploaded | Count of files uploaded to Blob Storage |
fax.inbound.published | Count of events published to Service Bus |
fax.inbound.duration | Time from webhook to event publish |
| Metric | Description |
|---|---|
fax.outbound.queued | Count of faxes queued for sending |
fax.outbound.sent | Count of faxes successfully sent |
fax.outbound.delivered | Count of faxes confirmed delivered |
fax.outbound.failed | Count of fax delivery failures |
fax.outbound.duration | Time from queue to delivery |
Logging
Key log events: Inbound:Troubleshooting
Common Issues
Webhook not receiving notifications
Webhook not receiving notifications
Symptoms:
- No fax events appearing in Service Bus
- No webhook logs in FaxIntegrationService
- RingCentral subscription expired or pointing to wrong URL
- Firewall blocking inbound requests
- Verify RingCentral subscription is active and pointing to correct URL
- Check network/firewall rules allow inbound traffic
- Manually trigger subscription renewal
PDF download failures
PDF download failures
Symptoms:
- Webhook received but no blob uploaded
- Error logs: “Failed to download PDF”
- RingCentral token expired
- Network timeout
- Invalid message/attachment ID
- Check RingCentral JWT token is valid
- Verify network connectivity to RingCentral API
- Check message ID exists in RingCentral
Blob upload failures
Blob upload failures
Symptoms:
- PDF downloaded but event not published
- Error logs: “Failed to upload to blob”
- Invalid storage connection string
- Container doesn’t exist
- Insufficient permissions
- Verify Azure Storage connection string
- Ensure container exists and is accessible
- Check managed identity or SAS token permissions
Events not reaching CurentaOrderTriagingCoreApi
Events not reaching CurentaOrderTriagingCoreApi
Symptoms:
- Events published but not processed
- Faxes not appearing in triaging queue
- Subscription not created
- Dead-letter queue full
- Deserialization errors
- Verify Service Bus subscription exists
- Check dead-letter queue for failed messages
- Validate event schema matches consumer expectation
Outbound fax not sending
Outbound fax not sending
Symptoms:
- Fax queued but never sent
- Status remains “Queued” indefinitely
- RingCentral API rate limiting
- Invalid recipient fax number
- Document URL inaccessible
- Check RingCentral rate limits and quotas
- Validate fax number format (E.164)
- Verify document URL is accessible from FaxIntegrationService
- Check RingCentral account has fax sending permissions
Outbound fax delivery failures
Outbound fax delivery failures
Symptoms:
- Fax status shows “Failed”, “Busy”, or “NoAnswer”
- Pharmacy not receiving faxes
- Recipient fax machine issues
- Invalid or disconnected fax number
- Network/line quality issues
- Verify recipient fax number is correct and active
- Contact recipient to confirm fax machine is operational
- Retry sending during off-peak hours
- Check RingCentral delivery reports for detailed error codes
Related Documentation
Changelog
| Version | Date | Changes |
|---|---|---|
| 1.1.0 | December 17, 2025 | Added outbound fax sending — pharmacy faxes now sent through this service |
| 1.0.0 | December 17, 2025 | Initial release — inbound fax processing extracted from CurentaOrderTriagingCoreApi |
Owners
| Role | Contact |
|---|---|
| Team | Platform Engineering |
| Support | Slack: #platform-engineering |