# Document Synchronization

Learn how to integrate your practice management system with Askara to receive and synchronize validated medical documents automatically.

## Overview

When a healthcare professional validates a document in Askara, your system can receive the document and import it into your database. This guide explains the integration flow and available synchronization methods.

## Integration Flow

1. **Receive notification** - Via webhook (push) or polling (pull)
2. **Download document** - Get PDF and metadata via API
3. **Import to your system** - Save document and update your database
4. **Confirm status** - Report success or failure back to Askara


## Synchronization Methods

### Option 1: Webhooks (Recommended)

Webhooks provide real-time notifications when documents are ready. Askara sends an HTTP POST request to your endpoint.

**Advantages:**

- Real-time synchronization
- No polling overhead
- Efficient resource usage


#### Webhook Events

Choose the event that best fits your workflow:

| Event | When Triggered | Use Case |
|  --- | --- | --- |
| `new_document` | Document is validated and ready | **Automatic sync** - Import documents immediately when ready |
| `document_synchronize` | User manually initiates sync | **On-demand sync** - Wait for explicit user action before importing |


**Choosing an Event:**

- **Use `new_document`** if you want to automatically import all validated documents into your system as soon as they're ready. This provides the fastest synchronization with no user intervention required.
- **Use `document_synchronize`** if you want users to explicitly trigger synchronization from Askara's interface. This gives healthcare professionals control over when documents are sent to your system.


**Note:** You can register for both events if you want to support both automatic and manual synchronization modes.

#### 1. Register Your Webhook

**Endpoint:** `POST /webhooks`

[→ API Reference: Create Webhook](/apis/askara-symfony/askara-api/webhook#create-webhook)

**Example - Automatic sync:**

```json
{
  "url": "https://your-system.com/api/askara/webhook",
  "events": ["new_document"],
  "active": true
}
```

**Example - Manual sync:**

```json
{
  "url": "https://your-system.com/api/askara/webhook",
  "events": ["document_synchronize"],
  "active": true
}
```

**Example - Both modes:**

```json
{
  "url": "https://your-system.com/api/askara/webhook",
  "events": ["new_document", "document_synchronize"],
  "active": true
}
```

#### 2. Receive Webhook Events

When an event occurs, Askara sends a POST request to your webhook URL.

**Webhook Payload Structure:**

```json
{
  "events": [{
    "id": "document-uuid",
    "resource_type": "document",
    "action": "new_document",
    "metadata": {
      "document": {
        "uuid": "...",
        "type": "referral_letter",
        "state": "verified",
        "patient": { "uuid": "...", "externalId": "...", ... },
        "pdf": { "url": "...", "fileName": "..." }
      }
    },
    "resource_metadata": {
      "user_id": "...",
      "organization_id": "..."
    }
  }],
  "meta": {
    "webhook_id": "your-webhook-uuid"
  }
}
```

**Important:**

- Respond with `200 OK` within 5 seconds
- Process the document asynchronously (download, import, confirm)
- The payload structure is identical for both `new_document` and `document_synchronize` events
- Check the `action` field to distinguish between events if you're subscribed to both


#### 3. Download Document Data

Use the document UUID to fetch full details if needed.

**Endpoint:** `GET /documents/{uuid}`

[→ API Reference: Get Document](/apis/askara-symfony/askara-api/document#get-document)

The PDF URL in the webhook payload is pre-signed and valid for 1 hour.

### Option 2: Polling

If webhooks aren't feasible, poll periodically for unsynchronized documents.

**Endpoint:** `GET /documents?synchronized=false`

[→ API Reference: List Documents](/apis/askara-symfony/askara-api/document#list-documents)

**Query Parameters:**

- `synchronized=false` - Returns only documents not yet synchronized with your client
- `synchronized=true` - Returns only synchronized documents


**Recommended polling interval:** 30-60 seconds

**Response:** List of documents with embedded `pdf` and `patient` data.

## Confirming Synchronization Status

**CRITICAL:** Always confirm the synchronization status after processing a document, whether it succeeded or failed.

### Report Success

**Endpoint:** `POST /documents/{uuid}/status`

[→ API Reference: Set Document Status](/apis/askara-symfony/askara-api/document#set-document-status)

**Simple confirmation (recommended for most integrations):**

```json
{
  "success": true
}
```

**With optional tracking information:**

```json
{
  "success": true,
  "directory": "your_software_id",
  "path": "C:\\YourSoftware\\Documents\\Patients\\DOE_JOHN\\document.pdf"
}
```

**Fields:**

- `success` *(required)* - `true` to mark synchronization as successful
- `directory` *(optional)* - Your software identifier for internal tracking
- `path` *(optional)* - Full file path where you saved the document for internal tracking


This marks the document as synchronized and stops automatic retries.

### Report Failure

Send the same request with `success: false` and provide an error message:

```json
{
  "success": false,
  "error": "Failed to save document: Database connection timeout"
}
```

**Fields:**

- `success` *(required)* - `false` to indicate synchronization failed
- `error` *(optional but recommended)* - Error message describing why synchronization failed
- `directory` *(optional)* - Your software identifier
- `path` *(optional)* - File path (usually empty on failure)


**Important:** Always provide an `error` message when `success` is `false` to help troubleshoot synchronization issues.

This records the failure with the error message. Healthcare professionals can then retry synchronization manually from Askara's interface.

## Retry Behavior

### Webhook Delivery Retries

If your webhook endpoint fails to respond (network error, timeout, non-2xx status code), Askara automatically retries webhook delivery:

- **Retry 1:** After 5 seconds
- **Retry 2:** After 10 seconds
- **Retry 3:** After 20 seconds
- **Max retries:** 3 attempts


After 3 failed attempts, the webhook delivery is marked as failed and stored in the failure queue.

### Document Synchronization Retries

Document synchronization itself is **not retried automatically**. Retries are triggered:

- **Manual retry:** Healthcare professionals can click "Synchronize" in Askara UI
- **Rate limiting:** Manual retries are limited to once every 30 seconds to prevent abuse
- **After success confirmation (`success: true`):** Document is marked as synchronized, no further retries needed
- **After failure confirmation (`success: false`):** Document remains unsynchronized and can be retried manually


## Required OAuth2 Scopes

To synchronize documents, your OAuth2 client must request these scopes:

- `read:documents` - Retrieve document information
- `write:document_integrations` - Confirm synchronization status


[→ OAuth2 Guide](/guides/oauth2)

## Example Implementation

### Node.js Webhook Handler

```javascript
app.post('/api/askara/webhook', async (req, res) => {
  // Respond quickly to avoid timeout
  res.status(200).send('OK');

  const events = req.body.events;

  // Process asynchronously
  for (const event of events) {
    if (event.action === 'new_document' || event.action === 'document_synchronize') {
      const document = event.metadata.document;

      try {
        // Download PDF
        const pdfResponse = await fetch(document.pdf.url);
        const pdfBuffer = await pdfResponse.buffer();

        // Save to your system
        const filePath = await saveToSystem(pdfBuffer, document);

        // Confirm success
        await fetch(`https://api.askara.ai/documents/${document.uuid}/status`, {
          method: 'POST',
          headers: {
            'Authorization': `Bearer ${accessToken}`,
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({
            success: true,
            directory: 'your_software_id',
            path: filePath
          })
        });
      } catch (error) {
        // Report failure
        await fetch(`https://api.askara.ai/documents/${document.uuid}/status`, {
          method: 'POST',
          headers: {
            'Authorization': `Bearer ${accessToken}`,
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({
            success: false,
            error: error.message
          })
        });
      }
    }
  }
});
```

## Best Practices

1. **Always confirm status** - Report both successes and failures
2. **Provide error messages** - Include detailed error information when synchronization fails
3. **Process asynchronously** - Don't block webhook responses while processing
4. **Validate webhook signatures** - Verify requests come from Askara (if implemented)
5. **Handle duplicates** - Use document UUID to prevent duplicate imports
6. **Implement idempotency** - Same document UUID should produce the same result


## Troubleshooting

### Webhook Not Receiving Events

- Verify your webhook URL is publicly accessible
- Check that your endpoint responds with `200 OK` within 5 seconds
- Review webhook logs in Askara dashboard
- Ensure your firewall allows Askara's IP addresses


### Synchronization Failures

- Check OAuth2 token hasn't expired
- Verify you have the required scopes
- Review error messages in document integration status
- Test with polling method to isolate webhook issues


## Next Steps

- **[API Reference](/apis/askara-symfony/askara-api)** - Explore all endpoints
- **[OAuth2 Authentication](/guides/oauth2)** - Secure your integration
- **[Rate Limiting](/guides/rate_limiting)** - Understand API limits
- **[Support](https://www.askara.ai/en/contact)** - Get help with your integration