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.
| Method | Request → Response | Notes |
|---|---|---|
CreateDiagnostic | CreateDiagnosticRequest → Diagnostic | Creates the record from your business details. No generation yet. |
GetDiagnostic | GetDiagnosticRequest → Diagnostic | |
ListDiagnostics | ListDiagnosticsRequest → ListDiagnosticsResponse | Paginated |
GenerateDiagnostic | GenerateDiagnosticRequest → stream StreamChunk | Scrapes the site, streams the analysis, then fills the rest of the app. Fails with FailedPrecondition if the site cannot be read. |
UpdateDiagnostic | UpdateDiagnosticRequest → Diagnostic | Business details and metadata |
ExportDiagnosticPDF | ExportDiagnosticPDFRequest → ExportDiagnosticPDFResponse | PDF bytes and a file name |
AuditURL | AuditURLRequest → AuditReport | Relevance audit. 2–3 competitor_urls switch to relative benchmarking. profile picks a weighting, for example ai-focused. |
ApplyAuditActions | ApplyAuditActionsRequest → ApplyAuditActionsResponse | mode 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.
| Method | Request → Response | Notes |
|---|---|---|
StartResearch | StartResearchRequest → stream StreamChunk | Live research for a topic, with optional extra sources |
GetRadarResults | GetRadarResultsRequest → RadarResults | One stored result |
ListRadarResults | ListRadarResultsRequest → ListRadarResultsResponse | Most recent first |
SuggestProfiles | SuggestProfilesRequest → SuggestProfilesResponse | Influencer, competitor, and partner profiles |
UseRadarFeedback | UseRadarFeedbackRequest → Empty | Profile-level feedback |
GetTrendingPosts | GetTrendingPostsRequest → GetTrendingPostsResponse | Real scraped posts with a 0–100 hot score |
SubmitPostFeedback | SubmitPostFeedbackRequest → Empty | like or dislike on one post |
DiscoverCompetitorChannels | DiscoverCompetitorChannelsRequest → DiscoverCompetitorChannelsResponse | Competitors’ YouTube and Instagram channels |
DiscoverGuestOpportunities | DiscoverGuestOpportunitiesRequest → DiscoverGuestOpportunitiesResponse | Shows you could guest on |
DraftPartnershipOutreach | DraftPartnershipOutreachRequest → stream StreamChunk | Draft only. Nothing is sent. |
ListPartnershipOutreach | ListPartnershipOutreachRequest → 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.
| Method | Request → Response | Notes |
|---|---|---|
AnalyzeContentGaps | AnalyzeContentGapsRequest → ContentGapsResponse | Topics and formats you under-serve |
GenerateContentStrategy | GenerateContentStrategyRequest → ContentStrategyResponse | Pillars, cadence, alignment score |
GenerateStrategyRoadmap | GenerateStrategyRoadmapRequest → StrategyRoadmapResponse | Phased 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
| Method | Request → Response | Notes |
|---|---|---|
GenerateProfile | GenerateProfileRequest → stream StreamChunk | A 360° profile for an audience |
GenerateJourneyMap | GenerateJourneyMapRequest → stream StreamChunk | A multi-stage funnel map for a profile |
ListCustomerProfiles | ListCustomerProfilesRequest → ListCustomerProfilesResponse | Stored 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;
}