Inbound Webhooks Guide
Overview
Section titled “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
📢 Tag & Parameter Normalization — Updated March 2026
Inbound webhook tags and request parameters are normalized and populated before routing-plan resolution and call-flow execution. This means variable and tag nodes in your call flow can reliably read inbound RTB query parameters, body fields, and header values as tags — including data sent via the call_data webhook.
Header tag extraction expanded: Tag extraction from request headers now processes all request headers — not just X--prefixed ones. If you previously relied on non-X--prefixed headers being excluded from tag extraction, review your tag configuration. No action is required for most integrations — this fix is automatic.
Setting Up Inbound Webhooks
Section titled “Setting Up Inbound Webhooks”-
Navigate to Webhooks > Incoming in your MojaAI dashboard
-
Click Create Webhook
-
Choose the webhook type (
call_data,update_revenue,update_tags, orupdate_fields) -
Save the webhook — you’ll receive an authentication key and webhook URL
Authentication
Section titled “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
Section titled “Webhook Types”MojaAI supports four types of inbound webhooks, each with its own endpoint and request structure:
| Type | Endpoint | Purpose |
call_data |
/call-data |
Pass caller metadata before or during call routing |
update_revenue |
/update-revenue |
Update revenue and conversion data on calls |
update_tags |
/update-tags |
Add or remove custom tags on calls |
update_fields |
/update-fields |
Update multiple call record fields in a single request |
Call Data Webhook
Section titled “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.
POST https://webhooks.moja.cloud/call-data?moja_auth_key=\{auth_key\}
Request Headers
Section titled “Request Headers”Content-Type: application/json
Request Body
Section titled “Request Body”{ “caller_id”: “+13105559876”, “lead_source”: “google_ads”, “ad_campaign”: “medicare_q1”, “landing_page”: “medicare-info”}
Fields
Section titled “Fields”| Field | Type | Required | Description |
caller_id |
string | Yes | The caller’s phone number (used to match to incoming calls) |
transaction_id |
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
Section titled “Response”Success (200 OK)
{ “success”: true, “request_id”: “a1b2c3d4-e5f6-7890-abcd-ef1234567890”}
How Call Matching Works
Section titled “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_datawebhook -
A 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
Section titled “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).
POST https://webhooks.moja.cloud/update-revenue?moja_auth_key=\{auth_key\}
Request Headers
Section titled “Request Headers”Content-Type: application/json
Request Body
Section titled “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
Section titled “Fields”| Field | Type | Required | Description |
call_log_id |
string | Yes | The MojaAI call log ID. Accepts call_log_id, callLogId, call_sid, or callSid |
phone_number |
string | Yes | The caller’s phone number. Accepts phone_number or phoneNumber |
revenue_paid_out |
number | Yes | Revenue amount (USD). Accepts revenue_paid_out or revenuePaidOut |
transaction_id |
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
Section titled “Behavior”-
If the call’s
converted_attimestamp is not set, it is automatically set to the current time when revenue is updated -
When matching by
phone_number, the system looks back a configurable number of days (1–7, default: 7) and may match multiple calls -
Revenue 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
Section titled “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 |
call_log_ids |
All call log IDs that were updated |
revenue_paid_out |
The revenue amount that was applied |
active_call_log_ids |
Call log IDs for calls that were still active when updated (only included if there are active calls) |
Update Tags Webhook
Section titled “Update Tags Webhook”Use the update_tags webhook to add or remove custom tags on calls.
POST https://webhooks.moja.cloud/update-tags?moja_auth_key=\{auth_key\}
Request Headers
Section titled “Request Headers”Content-Type: application/json
Request Body
Section titled “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
Section titled “Fields”| Field | Type | Required | Description |
call_log_id |
string | Yes | The MojaAI call log ID. Accepts call_log_id, callLogId, call_sid, or callSid |
phone_number |
string | Yes | The caller’s phone number. Accepts phone_number or phoneNumber |
add |
object | Yes | Tags to add as key-value pairs: { "tag_key": "tag_value" \} |
remove |
array | Yes | Tag keys to remove: ["tag_key1", "tag_key2"] |
transaction_id |
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
Section titled “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
Section titled “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 |
call_log_ids |
All call log IDs that were updated |
added |
Tags that were added (as key-value objects) |
removed |
Tag keys that were removed |
active_call_log_ids |
Call log IDs for calls that were still active when updated (only included if there are active calls) |
Update Fields Webhook
Section titled “Update Fields Webhook”Use the update_fields webhook to update multiple call record fields in a single postback request. This is a unified webhook type that accepts any combination of supported field updates — revenue, conversion status, tags, publisher payouts, and more.
POST https://webhooks.moja.cloud/update-fields?moja_auth_key=\{auth_key\}
GET https://webhooks.moja.cloud/update-fields?moja_auth_key=\{auth_key\}&call_log_id=\{id\}&\{fields\}
Supported Fields
Section titled “Supported Fields”All fields are optional — include only the ones you want to update:
| Field | Type | Notes |
converted |
boolean | Mark a call as converted or remove conversion status |
call_converted_at |
datetime or null | Set an explicit conversion timestamp |
revenue_paid_out |
number | Override the revenue payout amount (USD) |
publisher_paid_out |
number | Override the publisher payout amount. Completed calls only. |
reason |
string or null | Set or clear the call reason/disposition |
no_payout_reason |
string or null | Set or clear a payout hold reason. Values: Campaign preconversion, Condition not met, Caps exceeded, or null. Completed calls only. |
add |
object or array | Tags to add or update. See tag format note below. |
remove |
string or string[] | Tag keys to remove. See tag format note below. |
Note on tag operations [VERIFY]: Based on the latest code review, tag operations (add and remove) may need to be wrapped under a tags key (e.g., tags.add / tags.remove). Verify the payload format against your integration before relying on a specific structure.
Payload Structure
Section titled “Payload Structure”Fields can be sent at the top level or nested inside a fields object. Calls are identified by call_log_id or phone_number.
Example — Top-level fields (POST):
{ “call_log_id”: “abc123-def456-ghi789”, “converted”: true, “revenue_paid_out”: 25.50, “reason”: “Qualified lead”}
Example — Tag operations using tags wrapper [VERIFY format]:
{ “call_log_id”: “abc123-def456-ghi789”, “converted”: true, “tags”: { “add”: { “lead_quality”: “high”, “disposition”: “sale_completed” }, “remove”: [“pending_review”] }}
Example — GET request:
Behavior
Section titled “Behavior”-
Completed calls are updated directly in the database
-
For live/active calls, updates are applied to the current call session
-
publisher_paid_outandno_payout_reasonare only applied to calls with statuscompleted -
Either
call_log_idorphone_numbermust be provided
Getting Started
Section titled “Getting Started”-
Navigate to Webhooks > Incoming > Create
-
Select type
update_fields -
Copy the generated auth key and endpoint URL
-
Configure your system to POST or GET with the call identifier and fields you want to update
-
Test with a completed call to verify fields are updated correctly
Note: The existing update_revenue and update_tags webhook types continue to work exactly as before. The update_fields type is an additional option — no changes needed to existing integrations.
Batch Updates
Section titled “Batch Updates”As of April 3, 2026, the update_revenue, update_tags, and update_fields webhook types support batch updates — you can now update up to 50 calls in a single request by passing call_log_id as an array instead of a single string.
All existing single-ID requests continue to work exactly as before. Batch support is a backward-compatible addition.
How it works
Section titled “How it works”Pass call_log_id as a JSON array. Everything else in the request stays the same — the same field values are applied to every call in the array.
Single call (existing — unchanged):
{ “call_log_id”: “abc-123”, “converted”: true, “revenue_paid_out”: 25.50}
Batch (new):
{ “call_log_id”: [“abc-123”, “def-456”, “ghi-789”], “converted”: true, “revenue_paid_out”: 25.50}
Requirements
Section titled “Requirements”| Supported types | update_revenue, update_tags, and update_fields. Not supported for call_data. |
| HTTP method | Batch requests must use POST with a JSON body. GET requests continue to work for single-ID updates only. |
| Maximum IDs per request | 50 call log IDs. |
| call_log_id vs. phone_number | You cannot combine an array call_log_id with phone_number in the same request. Use one or the other. |
| Same values for all calls | All calls in the batch receive the same field values. For different values per call, send separate requests. |
Response format
Section titled “Response format”A batch request response includes two fields:
-
call_log_ids— The IDs that were successfully updated. -
failed_call_log_ids— Any IDs that failed to update. This will be an empty array if all updates succeeded.
{ “call_log_ids”: [“abc-123”, “def-456”], “failed_call_log_ids”: [“ghi-789”]}
Always check failed_call_log_ids in the response. A single invalid or unrecognized ID will not block the rest of the batch — failed IDs are reported separately so you can retry them individually.
Batch examples by type
Section titled “Batch examples by type”Batch update_revenue:
POST {base_url}/update-revenue?moja_auth_key={auth_key}{ “call_log_id”: [“abc-123”, “def-456”, “ghi-789”], “revenue_paid_out”: 25.50}
Batch update_tags:
POST {base_url}/update-tags?moja_auth_key={auth_key}{ “call_log_id”: [“abc-123”, “def-456”, “ghi-789”], “add”: [ {“customer_type”: “premium”}, {“source”: “website”} ], “remove”: [“old_tag”]}
Batch update_fields:
POST {base_url}/update-fields?moja_auth_key={auth_key}{ “call_log_id”: [“abc-123”, “def-456”, “ghi-789”], “converted”: true, “revenue_paid_out”: 25.50, “disposition”: “sale”}
When to use batch updates
Section titled “When to use batch updates”Batch updates are well-suited for:
-
End-of-day reconciliation — Post conversion outcomes for all calls processed in your system at once.
-
Bulk correction — Fix misclassified conversions or incorrect revenue values across multiple calls.
-
High-volume integrations — Reduce the number of HTTP requests your system needs to make.
Note: Incoming webhooks have a rate limit of 100 requests per minute per webhook configuration. With batch support, a single request can update up to 50 calls — keep this in mind when designing high-volume integrations.
Identifying Calls
Section titled “Identifying Calls”To update revenue or tags, you need either the call_log_id or the caller’s phone_number.
Using call_log_id
Section titled “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
Section titled “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
Section titled “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 returned -
If a request with the same
transaction_idis currently being processed, a409 Conflictis returned -
The
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
Section titled “Error Codes”| Code | Error | Description |
| 400 | Missing required parameter | A required field is missing (e.g., caller_id for call data, revenue_paid_out for update revenue) |
| 401 | Unauthorized | Invalid or missing moja_auth_key |
| 403 | Forbidden | Call log does not belong to your organization |
| 404 | Not found | Call log not found (verify call_log_id or phone_number and check the lookback window) |
| 409 | Conflict | Duplicate transaction_id — request is already being processed |
| 429 | Rate limited | Too many requests (see Rate Limits below) |
| 500 | Server error | Internal server error |
Rate Limits
Section titled “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
Section titled “Best Practices”-
Use
call_log_idwhen possible — It’s more precise thanphone_numbermatching, which can affect multiple calls -
Include
transaction_id— Prevents duplicate processing when retrying requests -
Handle errors — Implement retry logic with exponential backoff for
429and500errors -
Send data promptly — For
call_datawebhooks, send caller metadata before the call arrives for best results -
Define 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
Section titled “Integration Examples”cURL — Update Revenue
Section titled “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
Section titled “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
Section titled “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
Section titled “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
Section titled “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
Section titled “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?
Section titled “Need Help?”-
Email: support@mojaai.com
-
Help Center: Available in your dashboard

