Skip to content

Analysis services

Package pulse.v1. Every method needs a bearer token.

DiagnosticService

The Site Audit: the model-written diagnosis and the rule-based relevance audit. See Site Audit.

MethodRequest → ResponseNotes
CreateDiagnosticCreateDiagnosticRequest → DiagnosticCreates the record from your business details. No generation yet.
GetDiagnosticGetDiagnosticRequest → Diagnostic
ListDiagnosticsListDiagnosticsRequest → ListDiagnosticsResponsePaginated
GenerateDiagnosticGenerateDiagnosticRequest → stream StreamChunkScrapes the site, streams the analysis, then fills the rest of the app. Fails with FailedPrecondition if the site cannot be read.
UpdateDiagnosticUpdateDiagnosticRequest → DiagnosticBusiness details and metadata
ExportDiagnosticPDFExportDiagnosticPDFRequest → ExportDiagnosticPDFResponsePDF bytes and a file name
AuditURLAuditURLRequest → AuditReportRelevance audit. 2–3 competitor_urls switch to relative benchmarking. profile picks a weighting, for example ai-focused.
ApplyAuditActionsApplyAuditActionsRequest → ApplyAuditActionsResponsemode is plan (default), apply, commit, or pr. All but plan need PULSE_APPLY_ENABLED=true.
message CreateDiagnosticRequest {
  string business_name = 1;
  string industry = 2;
  string niche = 3;
  string target_audience = 4;
  string current_channels = 5;
  string competitors = 6;
  string business_description = 7;
  string website_url = 8;
  repeated string goals = 9;
}

message GetDiagnosticRequest {
  string id = 1;
}

message ListDiagnosticsRequest {
  PaginationRequest pagination = 1;
}

message ListDiagnosticsResponse {
  repeated Diagnostic diagnostics = 1;
  PaginationResponse pagination = 2;
}

message GenerateDiagnosticRequest {
  string diagnostic_id = 1; // ID of the pre-created diagnostic to populate
}

message UpdateDiagnosticRequest {
  string id = 1;
  string business_name = 2;
  string industry = 3;
  string niche = 4;
  string target_audience = 5;
  string current_channels = 6;
  string competitors = 7;
  string business_description = 8;
  string website_url = 9;
  map<string, string> metadata = 10;
}

message ExportDiagnosticPDFRequest {
  string diagnostic_id = 1;
}

message ExportDiagnosticPDFResponse {
  bytes pdf_data = 1;
  string filename = 2;
}

The Diagnostic message

channel_prescriptions and brand_visibility hold only proposals the judging ladder kept. judgements lists every verdict.

message Diagnostic {
  string id = 1;
  string user_id = 2;
  string business_name = 3;
  string industry = 4;
  string niche = 5;
  string target_audience = 6;
  string current_channels = 7;      // comma-separated active channels
  string competitors = 8;           // comma-separated competitor names
  string business_description = 9;  // user's free-form business description
  string website_url = 10;
  string positioning_analysis = 11;
  string swot_analysis = 12;
  string channel_recommendations = 13;
  string content_strategy = 14;
  string competitive_landscape = 15;
  string ai_opinion = 16;           // strategic opinion from the AI market-analyst
  string status = 17;               // "pending", "generating", "completed", "error"
  map<string, string> metadata = 18;
  google.protobuf.Timestamp created_at = 19;
  google.protobuf.Timestamp updated_at = 20;
  repeated ChannelPrescription channel_prescriptions = 21;
  repeated AudienceSegment audience_segments = 22;
  repeated CronogramTask cronogram = 23;
  repeated string sources_used = 24;
  repeated string agent_tasks = 25;
  repeated string goals = 26;
  repeated DocumentPrescription document_prescriptions = 27;
  repeated BrandVisibilityInsight brand_visibility = 28;
  runink.ui.judgement.v1.JudgementSet judgements = 29;
}

message ChannelPrescription {
  Channel channel = 1;
  string role = 2;
  string priority = 3;
  repeated ContentSuggestion suggestions = 4;
  string cta_recommendation = 5;
  repeated string kpis = 6;
  runink.ui.judgement.v1.Judgement judgement = 7;
}

message ContentSuggestion {
  string title = 1;
  string description = 2;
  string cta = 3;
}

message DocumentPrescription {
  string format = 1;
  string role = 2;
  string priority = 3;
  repeated ContentSuggestion suggestions = 4;
}

message BrandVisibilityInsight {
  string dimension = 1;
  string insight = 2;               // what the diagnosis found about current AI-search visibility
  repeated string target_terms = 3; // entities/phrases/queries to own for AI-search lexical relevance
  repeated string actions = 4;      // concrete actions to raise generative-AI discoverability
  string rationale = 5;             // why this shapes brand awareness in AI/metasearch engines
  runink.ui.judgement.v1.Judgement judgement = 6;
}

message AudienceSegment {
  string level = 1;
  repeated string areas = 2;
  repeated string roles = 3;
  repeated string technologies = 4;
}

message CronogramTask {
  int32 week = 1;
  Channel channel = 2;
  string task = 3;
  bool completed = 4;
}

Audit messages

message AuditURLRequest {
  string url = 1;
  repeated string competitor_urls = 2;
  string profile = 3;
}

message AuditReport {
  string url = 1;
  google.protobuf.Timestamp audited_at = 2;
  double overall_score = 3;
  repeated AuditComposite composites = 4;
  repeated string skipped_data_sources = 5;
  string benchmark_mode = 6;
  repeated AuditRecommendation recommendations = 7;
  repeated AuditAction actions = 8;
}

message AuditComposite {
  string id = 1;
  string label = 2;
  double score = 3;
  double weight = 4;    // normalized 0-1
  double coverage = 5;  // 0-1
  repeated AuditSignal signals = 6;
}

message AuditSignal {
  string id = 1;
  double score = 2;
  double weight = 3;    // normalized 0-1 within its composite
  double coverage = 4;  // 0-1
  repeated AuditCheck checks = 5;
}

message AuditCheck {
  string id = 1;
  double score = 2;
  string status = 3;
  string raw_value = 4;
  string notes = 5;
  string mode = 6;
}

message AuditRecommendation {
  string check_id = 1;
  double score = 2;
  double impact = 3;
  string notes = 4;
}

message AuditAction {
  string check_id = 1;
  string title = 2;
  string rationale = 3;
  string severity = 4;     // critical|high|medium|low
  string type = 5;         // file_create|head_insert|content_edit|header_config|manual
  string target_hint = 6;
  string artifact = 7;     // the concrete content/snippet to apply
  string confidence = 8;   // high|medium|low
  bool auto_apply = 9;
  double impact = 10;
}

message ApplyAuditActionsRequest {
  string url = 1;
  string repo_path = 2;
  string profile = 3;
  string mode = 4;   // plan|apply|commit|pr
  string branch = 5; // default: seo/pulse-remediation
  string base = 6;   // default: main
}

message ApplyAuditActionsResponse {
  string stack = 1;
  double overall_score = 2;
  repeated PlannedChange changes = 3;
  repeated AuditAction manual = 4;
  ApplyGitResult git = 5;
  string pr_body = 6;
}

message PlannedChange {
  string path = 1;
  string op = 2; // create|modify|skip
  string check_id = 3;
  string reason = 4;
}

message ApplyGitResult {
  string branch = 1;
  bool committed = 2;
  bool pushed = 3;
  string pr_url = 4;
  string instructions = 5;
}

RadarService

Market research. See Audience and market.

MethodRequest → ResponseNotes
StartResearchStartResearchRequest → stream StreamChunkLive research for a topic, with optional extra sources
GetRadarResultsGetRadarResultsRequest → RadarResultsOne stored result
ListRadarResultsListRadarResultsRequest → ListRadarResultsResponseMost recent first
SuggestProfilesSuggestProfilesRequest → SuggestProfilesResponseInfluencer, competitor, and partner profiles
UseRadarFeedbackUseRadarFeedbackRequest → EmptyProfile-level feedback
GetTrendingPostsGetTrendingPostsRequest → GetTrendingPostsResponseReal scraped posts with a 0–100 hot score
SubmitPostFeedbackSubmitPostFeedbackRequest → Emptylike or dislike on one post
DiscoverCompetitorChannelsDiscoverCompetitorChannelsRequest → DiscoverCompetitorChannelsResponseCompetitors’ YouTube and Instagram channels
DiscoverGuestOpportunitiesDiscoverGuestOpportunitiesRequest → DiscoverGuestOpportunitiesResponseShows you could guest on
DraftPartnershipOutreachDraftPartnershipOutreachRequest → stream StreamChunkDraft only. Nothing is sent.
ListPartnershipOutreachListPartnershipOutreachRequest → ListPartnershipOutreachResponse
message StartResearchRequest {
  string topic = 1;
  string niche = 2;
  repeated Channel channels = 3;
  string target_audience = 4;
  string region = 5;            // e.g. "BR", "US", "LATAM"
  string language = 6;          // e.g. "pt-BR", "en-US"
  repeated ExtraSource extra_sources = 7;
}

enum ExtraSourceKind {
  EXTRA_SOURCE_KIND_UNSPECIFIED = 0;
  EXTRA_SOURCE_KIND_WEB = 1;         // a web-search seed (query grounded live)
  EXTRA_SOURCE_KIND_WEBSITE = 2;     // a website or YouTube URL to scrape
  EXTRA_SOURCE_KIND_PASTED_TEXT = 3; // free-form text pasted by the user
}

message ExtraSource {
  ExtraSourceKind kind = 1;
  string label = 2;     // display title (page title, "Pasted text", the query…)
  string url = 3;       // for website/YouTube sources
  string content = 4;   // inline text for pasted-text sources
}

message GetRadarResultsRequest {
  string research_id = 1;
}

message ListRadarResultsRequest {}

message ListRadarResultsResponse {
  repeated RadarResults results = 1;
}

message ListRadarResultsResponse {
  repeated RadarResults results = 1;
}

message RadarResults {
  string id = 1;
  string topic = 2;
  repeated TrendingTopic trends = 3;
  repeated HashtagCluster hashtag_clusters = 4;
  repeated ProfileSuggestion suggested_profiles = 5;
  string market_summary = 6;
  string competitive_intel = 7;
  google.protobuf.Timestamp generated_at = 8;
}

message TrendingTopic {
  string title = 1;
  string description = 2;
  double relevance_score = 3; // 0.0-1.0
  string source = 4;          // platform or data source
  repeated Channel channels = 5;
}

message HashtagCluster {
  string primary_hashtag = 1;
  repeated string related_hashtags = 2;
  int64 estimated_reach = 3;
  double engagement_rate = 4;
  Channel channel = 5;
}

message ProfileSuggestion {
  string username = 1;
  string display_name = 2;
  string bio = 3;
  string profile_url = 4;
  Channel channel = 5;
  int64 follower_count = 6;
  double relevance_score = 7;
  string category = 8; // "influencer", "competitor", "partner"
}

message SuggestProfilesRequest {
  string niche = 1;
  repeated Channel channels = 2;
  string region = 3;
  int32 max_results = 4;
}

message SuggestProfilesResponse {
  repeated ProfileSuggestion profiles = 1;
}

message UseRadarFeedbackRequest {
  string research_id = 1;
  string profile_username = 2;
  string feedback_type = 3; // "useful", "not_relevant", "save", "block"
  string notes = 4;
}

message RadarPost {
  string id = 1;
  string source_url = 2;
  string image_url = 3;
  string caption = 4;
  string author_handle = 5;
  Channel channel = 6;
  int32 hot_score = 7;    // 0-100
  string feedback = 8;    // "", "like", "dislike"
  google.protobuf.Timestamp created_at = 9;
}

message GetTrendingPostsRequest {
  string niche = 1;
  repeated Channel channels = 2;
  int32 max_results = 3;
}

message GetTrendingPostsResponse {
  repeated RadarPost posts = 1;
}

message SubmitPostFeedbackRequest {
  string post_id = 1;
  string feedback = 2; // "like" or "dislike"
}

message DiscoveredChannel {
  string id = 1;
  string name = 2;              // channel / show / person name
  string handle = 3;            // @handle or host name
  Channel channel = 4;          // YOUTUBE, INSTAGRAM, PODCAST, ...
  string url = 5;               // channel / show URL
  string description = 6;       // what the channel is about
  int64 audience_size = 7;      // subscribers/followers/listeners (best estimate)
  string category = 8;          // "competitor" or "guest_opportunity"
  double relevance_score = 9;   // 0.0-1.0 fit for the niche
  string contact_hint = 10;     // booking/contact link or email if found, else ""
  google.protobuf.Timestamp created_at = 11;
}

message DiscoverCompetitorChannelsRequest {
  string niche = 1;
  repeated string competitors = 2; // explicit names; if empty, derived from niche/diagnosis
  string region = 3;
  int32 max_results = 4;
}

message DiscoverCompetitorChannelsResponse {
  repeated DiscoveredChannel channels = 1;
}

message DiscoverGuestOpportunitiesRequest {
  string niche = 1;
  string topic = 2;                // what the user wants to be a guest about
  repeated Channel channels = 3;   // restrict to e.g. YOUTUBE, PODCAST; empty = both
  string region = 4;
  int32 max_results = 5;
}

message DiscoverGuestOpportunitiesResponse {
  repeated DiscoveredChannel channels = 1;
}

message PartnershipOutreach {
  string id = 1;
  string channel_id = 2;        // DiscoveredChannel.id it targets (may be "")
  string target_name = 3;
  string target_url = 4;
  Channel channel = 5;
  string subject = 6;
  string body = 7;
  string value_for_them = 8;    // why the host benefits
  string value_for_us = 9;      // why we benefit
  string status = 10;           // "draft"
  google.protobuf.Timestamp created_at = 11;
}

message DraftPartnershipOutreachRequest {
  string channel_id = 1;        // discovered channel to target (optional)
  string target_name = 2;       // required if channel_id empty
  string target_url = 3;
  Channel channel = 4;
  string category = 5;          // "competitor" | "guest_opportunity"
  string angle = 6;             // optional extra context / offer angle
}

message ListPartnershipOutreachRequest {
  int32 max_results = 1;
}

message ListPartnershipOutreachResponse {
  repeated PartnershipOutreach outreach = 1;
}

InsightsService

Content intelligence, synthesized by the platform’s own model from your diagnosis, published content, and live market signals. Every row passes through the judging ladder.

MethodRequest → ResponseNotes
AnalyzeContentGapsAnalyzeContentGapsRequest → ContentGapsResponseTopics and formats you under-serve
GenerateContentStrategyGenerateContentStrategyRequest → ContentStrategyResponsePillars, cadence, alignment score
GenerateStrategyRoadmapGenerateStrategyRoadmapRequest → StrategyRoadmapResponsePhased roadmap, readiness score
message AnalyzeContentGapsRequest {
  string focus_area = 1;    // optional theme to concentrate the analysis on
  DateRange date_range = 2; // window of published content to assess
}

message ContentGap {
  string topic = 1;
  string format = 2;         // e.g. "article", "video", "infographic"
  double demand_score = 3;   // 0-100 — how much the audience wants this
  double coverage_score = 4; // 0-100 — how well the user currently covers it
  double opportunity = 5;    // 0-100 — prescriptive priority (demand vs coverage)
  string rationale = 6;
  runink.ui.judgement.v1.Judgement judgement = 7;
}

message ContentGapsResponse {
  repeated ContentGap gaps = 1;
  double coverage_index = 2; // headline: overall content coverage 0-100
  string summary = 3;
  google.protobuf.Timestamp generated_at = 4;
  runink.ui.judgement.v1.JudgementSet judgements = 5;
}

message GenerateContentStrategyRequest {
  string objective = 1;         // e.g. "Thought Leadership", "Lead Gen"
  repeated Channel channels = 2;
  string audience = 3;
}

message ContentPillar {
  string name = 1;
  string description = 2;
  repeated string example_topics = 3;
  double weight = 4; // recommended share of the content mix 0-100
  runink.ui.judgement.v1.Judgement judgement = 5;
}

message ContentStrategyResponse {
  repeated ContentPillar pillars = 1;
  string cadence = 2;          // e.g. "3 posts/week, 1 long-form/month"
  double alignment_score = 3;  // headline: strategy-fit 0-100
  string summary = 4;
  google.protobuf.Timestamp generated_at = 5;
  runink.ui.judgement.v1.JudgementSet judgements = 6;
}

message GenerateStrategyRoadmapRequest {
  string objective = 1;
  int32 horizon_weeks = 2; // planning horizon (defaults sensibly when 0)
}

message RoadmapPhase {
  string name = 1;                // e.g. "Foundation", "Momentum", "Scale"
  string timeframe = 2;           // e.g. "Weeks 1-4"
  repeated string initiatives = 3;
  double momentum = 4;            // projected momentum 0-100
  string outcome = 5;
  runink.ui.judgement.v1.Judgement judgement = 6;
}

message StrategyRoadmapResponse {
  repeated RoadmapPhase phases = 1;
  double readiness_score = 2; // headline 0-100
  string summary = 3;
  google.protobuf.Timestamp generated_at = 4;
  runink.ui.judgement.v1.JudgementSet judgements = 5;
}

Customer360Service

MethodRequest → ResponseNotes
GenerateProfileGenerateProfileRequest → stream StreamChunkA 360° profile for an audience
GenerateJourneyMapGenerateJourneyMapRequest → stream StreamChunkA multi-stage funnel map for a profile
ListCustomerProfilesListCustomerProfilesRequest → ListCustomerProfilesResponseStored profiles, including those made from a diagnosis
message GenerateProfileRequest {
  string diagnostic_id = 1;
  string target_audience = 2;
  repeated Channel channels = 3;
}

message GenerateJourneyMapRequest {
  string profile_context = 1; // the generated profile text
  string campaign_objective = 2; // e.g. "brand_awareness", "lead_gen"
}

message ListCustomerProfilesRequest {}

message ListCustomerProfilesResponse {
  repeated CustomerProfile profiles = 1;
}

message ListCustomerProfilesResponse {
  repeated CustomerProfile profiles = 1;
}

message CustomerProfile {
  string id = 1;
  string target_audience = 2;
  string profile_json = 3; // the profile content (markdown/JSON as produced)
  string level = 4;        // e.g. decision_maker / influencer / end_user
  string diagnostic_id = 5;
  google.protobuf.Timestamp created_at = 6;
}