SmartERP Documentation An Ashewa Technology Solutions Platform

Webhook API

Every webhook route of both modules, with authentication, request and response shapes.

All routes below are called by an external system (usually n8n), not by a logged-in person. They use auth='none', so Odoo does not check a login. Each one authenticates on the shared API key instead.

Authentication#

Send the key in a header on every request:

X-Api-Key: <the shared API key>
SituationResponse
Key matchesThe request proceeds.
Key missing or wrong401 with {"error": "unauthorized"}.
No key configured in Odoo401. Every call is refused, and the AI Workforce logs a warning.

The comparison is constant-time, so response timing does not leak the key.

Generate a strong key with:

python3 -c "import secrets; print(secrets.token_urlsafe(32))"

Social Media Marketing Automation#

Configure the key under Social Marketing → Configuration → Automation Settings (Managers only).

MethodPathPurpose
GET/social_media/webhook/posts/dueList Scheduled posts whose date has passed.
POST/social_media/webhook/posts/<id>/resultReport a publish attempt.
POST/social_media/webhook/posts/<id>/ai-contentDeliver AI-generated content.

GET /social_media/webhook/posts/due#

Response 200:

{
  "posts": [
    {
      "id": 42,
      "message": "We are excited to announce…",
      "link_url": "https://example.com/launch",
      "hashtags": ["ProductLaunch", "AcmeInc"],
      "platform": "facebook",
      "account_id": 3,
      "account_handle": "@acme",
      "campaign_id": 1,
      "scheduled_date": "2026-05-01T09:00:00"
    }
  ]
}

POST /social_media/webhook/posts/<id>/result#

Body:

{ "success": true, "like_count": 0, "comment_count": 0, "share_count": 0, "click_count": 0 }

or, on failure:

{ "success": false, "error": "Facebook API returned 190" }
  • On success the post becomes Published, Published Date is set, the error is cleared, and any of the four counters you include are stored.
  • On failure the post becomes Failed with your error text, or "n8n reported a publish failure." if you send none.
  • Response 200 {"ok": true}; 404 {"error": "not_found"} for an unknown post.

POST /social_media/webhook/posts/<id>/ai-content#

Body:

{ "success": true, "message": "The drafted text", "hashtags": ["launch", "acme"] }
  • On success the post's AI Content Status becomes Received. The message replaces the post's text if you send one. Each hashtag is matched by name (a leading # is removed) and created if it does not exist; the post's hashtags are replaced with that set.
  • On failure ("success": false) the status becomes Failed and your error is stored in Error Message.
  • Response 200 {"ok": true}; 404 for an unknown post.

AI Growth Workforce#

Configure the key as the system parameter social_media_ai_workforce.api_key. See System parameters.

MethodPathPurpose
GET/social_ai/webhook/posts/dueScheduled posts ready to publish.
POST/social_ai/webhook/posts/<id>/contentDeliver AI-generated copy.
POST/social_ai/webhook/posts/<id>/resultReport a publish result.

GET /social_ai/webhook/posts/due#

Up to 50 Scheduled posts whose date has passed. Response 200:

{
  "count": 1,
  "posts": [
    {
      "id": 42,
      "name": "Launch teaser",
      "message": "…",
      "hashtags": "#SmartERP #Ethiopia",
      "scheduled_date": "2026-05-01 09:00:00",
      "agent": "AI Social Media Manager",
      "platforms": { "telegram": true, "facebook": false, "instagram": false, "twitter": true }
    }
  ]
}

Note the differences from the other module: hashtags is one string, and platforms is a map of flags rather than a single platform.

POST /social_ai/webhook/posts/<id>/content#

Body:

{ "success": true, "message": "The drafted text", "hashtags": ["launch", "acme"] }
  • hashtags may be a list (each item gets a # if it lacks one, joined by spaces) or a string.
  • A missing message gives 400 {"error": "missing 'message' in body"}. (success defaults to true if omitted.)
  • On success the post's message (and hashtags) are replaced, AI Generated is set, AI Content becomes Content Received, and a log entry records that a draft is ready for human review. Response {"status": "applied", "post_id": 42}.
  • With "success": false the status becomes Generation Failed and your error is stored. Response {"status": "recorded_failure"}.
  • 404 {"error": "post not found"} for an unknown post.

POST /social_ai/webhook/posts/<id>/result#

Body:

{ "success": true, "detail": "Facebook post 123" }

or:

{ "success": false, "error": "Token expired" }
  • Success sets the post to Posted and logs Published, with the detail as the result.
  • Failure sets it to Failed, stores Failure Reason, and logs Publish Failed.
  • Response {"status": "recorded", "post_id": 42}; 404 for an unknown post.

Warning

The result route sets the post's state to Posted or Failed whatever state it was in, and the publishing gate does not run for publishing that happens outside Odoo. Only let n8n publish posts returned by the due route, which are exactly those a human scheduled.

Calling it from the command line#

curl -s https://smarterp.example.com/social_ai/webhook/posts/due \
     -H "X-Api-Key: $KEY"

Requests SmartERP makes to n8n#

When someone presses Generate with AI, SmartERP POSTs JSON to the configured webhook URL and expects a success answer within 10 to 15 seconds. It does not wait for the draft: n8n answers immediately and delivers the result later on the callback URL. An error status, or no reply, is reported to the user. The AI Growth Workforce also records it as a failure on the post, and it accepts only 200, 201 or 202 as success.

ModuleTimeoutPayload fields
Social Media Marketing Automation10 spost_id, platform, account_handle, brief, callback_url, api_key
AI Growth Workforce15 spost_id, brief, hashtags, agent, platforms, callback_url, api_key

callback_url is built from Odoo's web.base.url system parameter. Set it to your public HTTPS address, or n8n will be handed a URL it cannot reach.

Last updated: 2026-10-16