Inbound Webhooks Guide
Overview
Inbound webhooks allow you to send data to MojaAI from your systems. Use these webhooks to pass caller metadata before a call is routed, update revenue on completed calls, or manage custom tags for reporting and attribution.
What you can do with inbound webhooks:
Pass caller metadata during call routing (e.g., lead source, campaign data)
Update revenue and conversion data on calls from your CRM
Add or remove custom tags on calls for categorization and reporting
Setting Up Inbound Webhooks
Navigate to Webhooks > Incoming in your MojaAI dashboard
Click Create Webhook
Choose the webhook type (
call_data,update_revenue, orupdate_tags)Save the webhook — you'll receive an authentication key and webhook URL
Authentication
Each inbound webhook has a unique authentication key. Include the key as a query parameter in your requests:
POST https://webhooks.moja.cloud/{webhook_type}?moja_auth_key={your_auth_key}
The moja_auth_key parameter is required on every request. Requests without a valid key will return a 401 Unauthorized error.
Webhook Types
MojaAI supports three types of inbound webhooks, each with its own endpoint and request structure:
Type | Endpoint | Purpose |
|
| Pass caller metadata before or during call routing |
|
| Update revenue and conversion data on calls |
|
| Add or remove custom tags on calls |
Call Data Webhook
Use the call_data webhook to pass caller metadata into MojaAI. This data is matched to incoming calls by caller ID and can be used for routing decisions, custom tags, and reporting.
Request Headers
Content-Type: application/json
Request Body
{
"caller_id": "+13105559876",
"lead_source": "google_ads",
"ad_campaign": "medicare_q1",
"landing_page": "medicare-info"
}
Fields
Field | Type | Required | Description |
| string | Yes | The caller's phone number (used to match to incoming calls) |
| string | No | Unique ID for idempotency (prevents duplicate processing) |
Any other fields | string | No | Stored as custom data and applied as tags if they match defined custom tags |
Any additional fields you send (beyond caller_id and transaction_id) are stored with the request. When a call comes in from the matching caller ID, fields that correspond to custom tags you've defined in MojaAI are automatically applied to the call.
Response
Success (200 OK)
{
"success": true,
"request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
How Call Matching Works
When a call arrives, MojaAI checks for call_data webhook requests that match the caller's phone number. If a match is found, the data from the webhook is applied to the call. The lookback window is configurable per webhook (default: 15 days).
Typical flow:
Your system sends caller data to the
call_datawebhookA call comes in from that phone number
MojaAI matches the call to the webhook data
Custom tag values from the webhook data are applied to the call
State and ZIP code are updated if included in the data
Update Revenue Webhook
Use the update_revenue webhook to update revenue amounts on completed calls. This is useful when conversions happen after the call ends (e.g., a sale closes days later).
Request Headers
Content-Type: application/json
Request Body
Identify the call by call_log_id:
{
"call_log_id": "abc123-def456-ghi789",
"revenue_paid_out": 150.00
}
Or identify the call by phone_number:
{
"phone_number": "+13105559876",
"revenue_paid_out": 150.00
}
Fields
Field | Type | Required | Description |
| string | Yes | The MojaAI call log ID. Accepts |
| string | Yes | The caller's phone number. Accepts |
| number | Yes | Revenue amount (USD). Accepts |
| string | No | Unique ID for idempotency (prevents duplicate processing) |
*Either call_log_id or phone_number must be provided. If both are provided, call_log_id takes priority.
Behavior
If the call's
converted_attimestamp is not set, it is automatically set to the current time when revenue is updatedWhen matching by
phone_number, the system looks back a configurable number of days (1–7, default: 7) and may match multiple callsRevenue can be updated on both active (live) and completed calls
For active calls, the revenue update is applied in real-time via the call session
Response
Success (200 OK)
{
"success": true,
"call_log_ids": ["abc123-def456-ghi789"],
"revenue_paid_out": 150.00,
"active_call_log_ids": ["abc123-def456-ghi789"]
}
Field | Description |
| All call log IDs that were updated |
| The revenue amount that was applied |
| Call log IDs for calls that were still active when updated (only included if there are active calls) |
Update Tags Webhook
Use the update_tags webhook to add or remove custom tags on calls.
Request Headers
Content-Type: application/json
Request Body
Adding tags:
{
"call_log_id": "abc123-def456-ghi789",
"add": {
"lead_quality": "high",
"disposition": "sale_completed"
}
}Removing tags:
{
"call_log_id": "abc123-def456-ghi789",
"remove": ["pending_review", "needs_callback"]
}Adding and removing in the same request:
{
"phone_number": "+13105559876",
"add": {
"disposition": "sale_completed"
},
"remove": ["pending_review"]
}
Fields
Field | Type | Required | Description |
| string | Yes | The MojaAI call log ID. Accepts |
| string | Yes | The caller's phone number. Accepts |
| object | Yes | Tags to add as key-value pairs: |
| array | Yes | Tag keys to remove: |
| string | No | Unique ID for idempotency (prevents duplicate processing) |
*Either call_log_id or phone_number must be provided.
**At least one of add or remove must be provided.
Behavior
Tags can be updated on both active (live) and completed calls
For active calls, tag updates are applied in real-time via the call session
Adding a tag that already exists updates its value
Removing a tag that doesn't exist is a no-op (no error)
When matching by
phone_number, the system looks back a configurable number of days (1–7, default: 7)
Response
Success (200 OK)
{
"success": true,
"call_log_ids": ["abc123-def456-ghi789"],
"added": [{"lead_quality": "high"}, {"disposition": "sale_completed"}],
"removed": ["pending_review"],
"active_call_log_ids": ["abc123-def456-ghi789"]
}
Field | Description |
| All call log IDs that were updated |
| Tags that were added (as key-value objects) |
| Tag keys that were removed |
| Call log IDs for calls that were still active when updated (only included if there are active calls) |
Identifying Calls
To update revenue or tags, you need either the call_log_id or the caller's phone_number.
Using call_log_id
The call_log_id uniquely identifies a specific call. You can obtain it from:
1. Outbound webhook payloads — Include the [CALL_ID] tag in your outbound webhook template:
{
"call_id": "[CALL_ID]",
"caller": "[CALLER_ID]",
"campaign": "[CAMPAIGN_NAME]"
}2. URL parameters — Configure your target to append the call ID to a redirect URL or form submission.3. Dashboard — Find the call log ID in your call logs in the MojaAI dashboard.
Using phone_number
When you provide phone_number instead of call_log_id, MojaAI looks up recent calls from that phone number within the configured lookback window. This can match multiple calls if the same caller has made more than one call within the window.
Lookback window: Configurable per webhook (1–7 days, default: 7 days).
Idempotency
All three webhook types support idempotent requests using the transaction_id field. When you include a transaction_id:
If a request with the same
transaction_idhas already been processed, the original response is returnedIf a request with the same
transaction_idis currently being processed, a409 Conflictis returnedThe
transaction_idis scoped to your organization
This prevents duplicate processing when retrying failed requests.
{
"call_log_id": "abc123-def456-ghi789",
"revenue_paid_out": 150.00,
"transaction_id": "txn_20260206_001"
}
Error Codes
Code | Error | Description |
400 | Missing required parameter | A required field is missing (e.g., |
401 | Unauthorized | Invalid or missing |
403 | Forbidden | Call log does not belong to your organization |
404 | Not found | Call log not found (verify |
409 | Conflict | Duplicate |
429 | Rate limited | Too many requests (see Rate Limits below) |
500 | Server error | Internal server error |
Rate Limits
Limit | Value |
Default | 100 requests per minute |
Rate limits are configurable per webhook and can be set to per-minute, per-hour, or per-day periods. Contact your account manager if you need a higher limit.
Best Practices
Use
call_log_idwhen possible — It's more precise thanphone_numbermatching, which can affect multiple callsInclude
transaction_id— Prevents duplicate processing when retrying requestsHandle errors — Implement retry logic with exponential backoff for
429and500errorsSend data promptly — For
call_datawebhooks, send caller metadata before the call arrives for best resultsDefine custom tags first — Create your custom tags in the MojaAI dashboard before sending
call_datawebhooks so the values are automatically applied to calls
Integration Examples
cURL — Update Revenue
curl -X POST "https://webhooks.moja.cloud/update-revenue?moja_auth_key=your_auth_key" \
-H "Content-Type: application/json" \
-d '{
"call_log_id": "abc123-def456-ghi789",
"revenue_paid_out": 150.00,
"transaction_id": "txn_20260206_001"
}'
cURL — Send Call Data
curl -X POST "https://webhooks.moja.cloud/call-data?moja_auth_key=your_auth_key" \
-H "Content-Type: application/json" \
-d '{
"caller_id": "+13105559876",
"lead_source": "google_ads",
"campaign_name": "medicare_q1"
}'
cURL — Update Tags
curl -X POST "https://webhooks.moja.cloud/update-tags?moja_auth_key=your_auth_key" \
-H "Content-Type: application/json" \
-d '{
"call_log_id": "abc123-def456-ghi789",
"add": {"disposition": "sale_completed"},
"remove": ["pending_review"]
}'
Python — Update Revenue
import requestsresponse = requests.post(
"https://webhooks.moja.cloud/update-revenue",
params={"moja_auth_key": "your_auth_key"},
json={
"call_log_id": "abc123-def456-ghi789",
"revenue_paid_out": 150.00,
"transaction_id": "txn_20260206_001"
}
)print(response.json())
JavaScript — Update Tags
const response = await fetch(
'https://webhooks.moja.cloud/update-tags?moja_auth_key=your_auth_key',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
call_log_id: 'abc123-def456-ghi789',
add: { disposition: 'sale_completed', lead_quality: 'high' },
remove: ['pending_review']
})
}
);const result = await response.json();
console.log(result);
Troubleshooting
Problem: Getting "Missing caller_id parameter" on call data webhook
Solution: Ensure you include a
caller_idfield in your request body or query parameters. The field name must becaller_idorfrom.
Problem: Getting "Call log not found" on update revenue or tags
Solution: Verify the
call_log_idis correct, or if usingphone_number, check that the call falls within the lookback window (default: 7 days). Call log IDs are case-sensitive.
Problem: Getting "Unauthorized" error
Solution: Check that your
moja_auth_keyis included as a query parameter (not in the URL path or headers). Verify the key is correct and the webhook has not been deleted.
Problem: Revenue update not reflected in reports
Solution: Updates may take a moment to process. If using
phone_numbermatching, verify the phone number format matches what's in MojaAI. Check the response forcall_log_idsto confirm which calls were updated.
Problem: Tags not appearing on calls
Solution: For
call_datawebhooks, ensure the tag keys you're sending match custom tags defined in your MojaAI dashboard. Forupdate_tags, tags are applied directly — check the responseaddedarray to confirm.
Need Help?
Email: [email protected]
Help Center: Available in your dashboard