Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Pricing Recommendation API

Overview

The Pricing Recommendation API provides partner-portal endpoints for AI-driven pricing recommendations. It integrates with RapidCanvas to:

  1. Preview predicted revenue for a restaurant without exposing the upstream API key to the frontend.
  2. Generate initial or refreshed recommendations for active AI-driven pricing rules.
  3. Convert RapidCanvas recommendations into pending price modifiers that require partner approval before becoming active.
  4. Send approve/reject decisions back to RapidCanvas as feedback.

The flow is:

Partner Portal  →  GET /pricing/recommendations/predict
                       (preview predicted revenue)

Partner Portal  →  POST /pricing/recommendations/initial
                       (trigger initial recommendation for a rule)

Daily Job       →  RecommendationFetchJob
                       (fetches recommendations for all active ai_driven rules)

Backend         →  PriceModifier::CreateFromRecommendation
                       (creates pending price modifiers)

Partner Portal  →  POST /price_modifiers/:id/approve
Partner Portal  →  POST /price_modifiers/:id/reject
                       (approve or reject pending modifiers)

Backend         →  Recommendation::NotifyDecision
                       (sends decision feedback to RapidCanvas)

Authentication

  • Requires Partner API bearer token authentication.
  • Restaurant access is validated using the authenticated partner context.
  • restaurant_id is normalized from the authorized restaurant context.

Required Environment Variables

  • RAPIDCANVAS_API_KEY - RapidCanvas API key.

Optional Environment Variables

  • RAPIDCANVAS_BASE_URL - Defaults to https://app.rapidcanvas.ai.
  • RAPIDCANVAS_RECOMMENDATION_DECISION_PATH - Optional explicit feedback endpoint for approve/reject callbacks. If omitted, the backend builds a default decision path based on the recommendation ID.

Internal Defaults (Code Constants)

  • Initial recommendation path: RapidCanvas::Client::INITIAL_RECOMMENDATION_PATH
  • Refresh recommendation path: RapidCanvas::Client::REFRESH_RECOMMENDATION_PATH
  • Predicted revenue path: RapidCanvas::Client::PREDICTED_REVENUE_PATH
  • Request timeout: RapidCanvas::Client::DEFAULT_TIMEOUT_SECONDS (20)
  • Open timeout: RapidCanvas::Client::DEFAULT_OPEN_TIMEOUT_SECONDS (10)

Retry Policy

Handled by Http::RetryWithBackoff:

  • Maximum retries: 3
  • Exponential backoff: 500ms, 1000ms, 2000ms
  • Retried only for:
    • timeout
    • network errors
    • HTTP 429
    • HTTP 5xx
  • Not retried for other 4xx responses

Endpoints

1. Predicted Revenue Preview

GET /api/partner/v1/pricing/recommendations/predict

Loads predicted revenue data for the AI-driven rule form. This endpoint does not call RapidCanvas recommendation generation and does not send goal_revenue or global_cap.

Query Parameters

ParameterTypeRequiredDescription
restaurant_idintegeryesRestaurant context used by partner auth/access checks.
target_period_typestringnoTarget period selector: day_end, week_end, or month_end.
target_revenue / target_salefloatnoOptional revenue goal used to compute delta_to_goal.

Example Request

GET /api/partner/v1/pricing/recommendations/predict?restaurant_id=370&target_period_type=month_end&target_revenue=800000

Example Success Response

{
  "success": true,
  "message": "Predicted revenue loaded successfully",
  "data": {
    "restaurant_id": 370,
    "target_period_type": "month_end",
    "prediction": {
      "organic_projection_revenue_amount": 671773.0,
      "confidence": "high"
    },
    "history": {
      "last_month_revenue_amount": 650000.25,
      "last_year_same_month_revenue_amount": 710000.75
    },
    "constraints": {
      "demand_ceiling_revenue_amount": 950500.5
    },
    "predicted_revenue": {
      "revenue_amount": 671773.0,
      "observed_so_far_amount": 120000.0,
      "projected_remaining_amount": 551773.0
    },
    "window": {
      "days_in_window": 30,
      "days_observed": 5,
      "days_remaining": 25
    },
    "goal": {
      "target_revenue": 800000.0,
      "delta_to_goal": 128227.0
    }
  }
}

2. Initial Recommendation

POST /api/partner/v1/pricing/recommendations/initial

Triggers an initial RapidCanvas recommendation request for a single AI-driven pricing rule. Internally it uses the same Recommendation::GetPredictedRevenue flow as the predict preview (the endpoint is currently aliased to the same handler).

Request Body

ParameterTypeRequiredDescription
restaurant_idintegeryesRestaurant context.
target_period_typestringnoday_end, week_end, month_end, or custom.
target_revenue / target_salefloatnoRevenue goal.

Example Request

POST /api/partner/v1/pricing/recommendations/initial
Content-Type: application/json

{
  "restaurant_id": 370,
  "target_period_type": "month_end",
  "target_revenue": 800000
}

Response

Same response contract as GET /pricing/recommendations/predict.


3. Approve Pending Price Modifier

POST /api/partner/v1/price_modifiers/:id/approve

Approves a pending AI-generated price modifier, changing its status to active. The backend notifies RapidCanvas of the approval decision.

Path Parameters

ParameterTypeDescription
idintegerPrice modifier ID.

Response

Returns the approved price modifier and optional RapidCanvas feedback result.

{
  "success": true,
  "message": "Price modifier approved",
  "data": {
    "modifier": { /* price modifier details */ },
    "rapidcanvas": { /* upstream feedback response */ }
  }
}

4. Reject Pending Price Modifier

POST /api/partner/v1/price_modifiers/:id/reject

Rejects a pending AI-generated price modifier, changing its status to rejected. The backend notifies RapidCanvas of the rejection decision.

Path Parameters

ParameterTypeDescription
idintegerPrice modifier ID.

Response

{
  "success": true,
  "message": "Price modifier rejected",
  "data": {
    "modifier": { /* price modifier details */ },
    "rapidcanvas": { /* upstream feedback response */ }
  }
}

5. Pending Modifier Count

GET /api/partner/v1/price_modifiers/pending_count

Returns the number of pending AI-generated price modifiers for the authorized restaurant.


Background Jobs

RecommendationFetchJob

  • Schedule: Daily (configured in config/recurring.yml).
  • Queue: recommendations.
  • Optional parameter: date (ISO date string, defaults to today in ICT).

The job delegates to Recommendation::FetchActiveRules, which:

  1. Finds active ai_driven pricing rules valid on the target date.
  2. Builds RapidCanvas payloads from the saved AI setup context (AiRecommendation).
  3. Calls /initial for new rules or /refresh for rules with existing recommendations.
  4. Converts RapidCanvas responses into pending price modifiers via PriceModifier::CreateFromRecommendation.

Recommendation Lifecycle

  1. Setup - A pricing rule is created with rule_type: "ai_driven" and an associated AiRecommendation context (target_sale, target_sale_period, etc.).
  2. Fetch - RecommendationFetchJob or the initial endpoint requests a recommendation from RapidCanvas.
  3. Adapt - Recommendation::RapidCanvas::ResponseAdapter normalizes the upstream response into a price modifier shape.
  4. Create - PriceModifier::CreateFromRecommendation creates one or more pending PriceModifier records linked to the pricing rule.
  5. Decide - Partner approves or rejects the pending modifier.
  6. Feedback - Recommendation::NotifyDecision sends the decision to RapidCanvas for model feedback.

Global Cap Builder

Recommendation::RapidCanvas::GlobalCapBuilder reads the restaurant’s global pricing settings and builds the global_cap payload sent to RapidCanvas:

{
  "increase": { "type": "percent", "value": 20.0 },
  "decrease": { "type": "percent", "value": 15.0 }
}

Supported cap types: percent and amount. Amount caps require a currency.


Error Handling

All recommendation endpoints return standardized error responses.

Example Error Response

{
  "success": false,
  "message": "RapidCanvas upstream failure: Service temporarily unavailable",
  "data": null
}

Validation errors include an errors object:

{
  "success": false,
  "message": "Invalid predicted revenue request payload",
  "errors": {
    "restaurant_id": ["must be greater than 0"]
  }
}

Error Codes

ScenarioHTTP Status
Invalid request payload422 Unprocessable Content
RapidCanvas timeout504 Gateway Timeout
RapidCanvas network failure502 Bad Gateway
RapidCanvas upstream error502 Bad Gateway
Unexpected RapidCanvas response502 Bad Gateway
Missing RapidCanvas configuration503 Service Unavailable

Notes

  • The backend keeps the RapidCanvas API key server-side only.
  • Validation happens before any upstream call.
  • Unexpected upstream payloads are rejected with a standardized error response.
  • Retry logging includes retry attempt, reason, and status when available.
  • Approve/reject notifications to RapidCanvas are best-effort; modifier status is updated even if the upstream feedback call fails.