Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions api/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { AuthGuard } from './auth/auth.guard';
import { UnkeyModule } from './unkey/unkey.module';
import { SocialPostPreviewsModule } from './social-posts-previews/social-posts-previews.module';
import { WebhooksModule } from './webhooks/webhooks.module';
import { SocialAccountFeedsModule } from './social-account-feeds/social-account-feeds.module';

@Module({
imports: [
Expand All @@ -26,6 +27,7 @@ import { WebhooksModule } from './webhooks/webhooks.module';
SocialAccountsModule,
SocialPostPreviewsModule,
WebhooksModule,
SocialAccountFeedsModule,
],
controllers: [],
providers: [AuthGuard],
Expand Down
2 changes: 2 additions & 0 deletions api/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type { NestExpressApplication } from '@nestjs/platform-express';
import type { NextFunction, Request, Response } from 'express';
import { webhookControllerDescription } from './webhooks/docs/webhooks-controller.md';
import { socialPostPreviewControllerDescription } from './social-posts-previews/docs/social-posts-preview-controller.md';
import { socialAccountFeedsControllerDescription } from './social-account-feeds/docs/social-account-feeds-controller.md';

async function bootstrap() {
const app: NestExpressApplication = await NestFactory.create(AppModule);
Expand All @@ -32,6 +33,7 @@ async function bootstrap() {
.addTag('Social Posts', postsControllerDescription)
.addTag('Social Accounts', socialAccountsControllerDescription)
.addTag('Social Post Results', postResultsControllerDescription)
.addTag('Social Account Feeds', socialAccountFeedsControllerDescription)
.addTag('Webhooks', webhookControllerDescription)
.addTag('Social Post Previews', socialPostPreviewControllerDescription)
.setVersion('1.0')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const socialAccountFeedsControllerDescription = `
The social account feed is every post made for the social account, including posts not made through our API.
Use this endpoint to get the platform details for any post made under the connected account.
Details will include:
- Metrics information including views, likes, follows, etc..
- Post information including caption, url, media, etc..
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { PlatformPostDto } from './platform-post.dto';

export interface PaginationPlatformPostMeta {
cursor: string;
limit: number;
next: string | null;
}

export interface PaginatedPlatformPostResponse {
data: PlatformPostDto[];
meta: PaginationPlatformPostMeta;
}
151 changes: 151 additions & 0 deletions api/src/social-account-feeds/dto/platform-post-metrics.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import { ApiProperty } from '@nestjs/swagger';

export class TikTokBusinessVideoMetricPercentageDto {
@ApiProperty({ description: 'Percentage value for the metric' })
percentage: number;

@ApiProperty({ description: 'Time in seconds for the metric' })
second: string;
}

export class TikTokBusinessPostImpressionSourceDto {
@ApiProperty({ description: 'Percentage of impressions from this source' })
percentage: number;

@ApiProperty({ description: 'Name of the impression source' })
impression_source: string;
}

export class TikTokBusinessPostAudienceTypeDto {
@ApiProperty({ description: 'Percentage of audience of this type' })
percentage: number;

@ApiProperty({ description: 'Type of audience' })
type: string;
}

export class TikTokBusinessPostAudienceCountryDto {
@ApiProperty({ description: 'Percentage of audience from this country' })
percentage: number;

@ApiProperty({ description: 'Country name' })
country: string;
}

export class TikTokBusinessPostAudienceCityDto {
@ApiProperty({ description: 'Percentage of audience from this city' })
percentage: number;

@ApiProperty({ description: 'City name' })
city_name: string;
}

export class TikTokBusinessPostAudienceGenderDto {
@ApiProperty({ description: 'Percentage of audience of this gender' })
percentage: number;

@ApiProperty({ description: 'Gender category' })
gender: string;
}

export class TikTokBusinessMetricsDto {
@ApiProperty({ description: 'Number of likes on the post' })
likes: number;

@ApiProperty({ description: 'Number of comments on the post' })
comments: number;

@ApiProperty({ description: 'Number of shares on the post' })
shares: number;

@ApiProperty({ description: 'Number of favorites on the post' })
favorites: number;

@ApiProperty({ description: 'Total reach of the post' })
reach: number;

@ApiProperty({ description: 'Total number of video views' })
video_views: number;

@ApiProperty({ description: 'Total time watched in seconds' })
total_time_watched: number;

@ApiProperty({ description: 'Average time watched in seconds' })
average_time_watched: number;

@ApiProperty({ description: 'Rate of full video watches as a percentage' })
full_video_watched_rate: number;

@ApiProperty({ description: 'Number of new followers gained from the post' })
new_followers: number;

@ApiProperty({ description: 'Number of profile views generated' })
profile_views: number;

@ApiProperty({ description: 'Number of website clicks' })
website_clicks: number;

@ApiProperty({ description: 'Number of phone number clicks' })
phone_number_clicks: number;

@ApiProperty({ description: 'Number of lead submissions' })
lead_submissions: number;

@ApiProperty({ description: 'Number of app download clicks' })
app_download_clicks: number;

@ApiProperty({ description: 'Number of email clicks' })
email_clicks: number;

@ApiProperty({ description: 'Number of address clicks' })
address_clicks: number;

@ApiProperty({
description: 'Video view retention data by percentage and time',
type: TikTokBusinessVideoMetricPercentageDto,
isArray: true,
})
video_view_retention: TikTokBusinessVideoMetricPercentageDto[];

@ApiProperty({
description: 'Impression sources breakdown',
type: TikTokBusinessPostImpressionSourceDto,
isArray: true,
})
impression_sources: TikTokBusinessPostImpressionSourceDto[];

@ApiProperty({
description: 'Audience types breakdown',
type: TikTokBusinessPostAudienceTypeDto,
isArray: true,
})
audience_types: TikTokBusinessPostAudienceTypeDto[];

@ApiProperty({
description: 'Audience genders breakdown',
type: TikTokBusinessPostAudienceGenderDto,
isArray: true,
})
audience_genders: TikTokBusinessPostAudienceGenderDto[];

@ApiProperty({
description: 'Audience countries breakdown',
type: TikTokBusinessPostAudienceCountryDto,
isArray: true,
})
audience_countries: TikTokBusinessPostAudienceCountryDto[];

@ApiProperty({
description: 'Audience cities breakdown',
type: TikTokBusinessPostAudienceCityDto,
isArray: true,
})
audience_cities: TikTokBusinessPostAudienceCityDto[];

@ApiProperty({
description: 'Engagement likes data by percentage and time',
type: TikTokBusinessVideoMetricPercentageDto,
isArray: true,
})
engagement_likes: TikTokBusinessVideoMetricPercentageDto[];
}
60 changes: 60 additions & 0 deletions api/src/social-account-feeds/dto/platform-post-query.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { ApiProperty } from '@nestjs/swagger';
import { Type } from 'class-transformer';
import { IsInt, IsOptional, IsString, Max, Min } from 'class-validator';

const DEFAULT_LIMIT = 50;
const MAX_LIMIT = 100;

export class PlatformPostQueryDto {
@ApiProperty({
description: 'Number of items to return',
default: DEFAULT_LIMIT,
required: false,
})
@IsInt()
@Min(1)
@Max(MAX_LIMIT)
@IsOptional()
@Type(() => Number)
limit: number = DEFAULT_LIMIT;

@ApiProperty({
description: 'Cursor identifying next page of results',
required: false,
})
@IsOptional()
@Type(() => String)
cursor?: string | null;

@ApiProperty({
description:
'Filter by Post for Me Social Postexternal ID. Multiple values imply OR logic (e.g., ?external_post_id=xxxxxx&external_post_id=yyyyyy).',
required: false,
type: 'array',
items: { type: 'string' },
})
@IsOptional()
external_post_id?: string[];

@ApiProperty({
description:
'Filter by Post for Me Social Post id(s). Multiple values imply OR logic (e.g., ?social_post_id=sp_xxxxxx&social_post_id=sp_yyyyyy).',
required: false,
type: 'array',
items: { type: 'string' },
})
@IsString({ each: true })
@IsOptional()
social_post_id?: string[];

@ApiProperty({
description:
"Filter by the platform's id(s). Multiple values imply OR logic (e.g., ?social_post_id=spr_xxxxxx&social_post_id=spr_yyyyyy).",
required: false,
type: 'array',
items: { type: 'string' },
})
@IsString({ each: true })
@IsOptional()
platform_post_id?: string[];
}
65 changes: 65 additions & 0 deletions api/src/social-account-feeds/dto/platform-post.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { ApiProperty } from '@nestjs/swagger';
import { TikTokBusinessMetricsDto } from './platform-post-metrics.dto';

export class PlatformPostDto {
@ApiProperty({ description: 'Social media platform name' })
platform: string;

@ApiProperty({
description: 'ID of the social post result',
required: false,
nullable: true,
})
social_post_result_id?: string;

@ApiProperty({
description: 'ID of the social post',
required: false,
nullable: true,
})
social_post_id?: string;

@ApiProperty({
description: 'External post ID from the platform',
required: false,
nullable: true,
})
external_post_id?: string;

@ApiProperty({ description: 'Platform-specific post ID' })
platform_post_id: string;

@ApiProperty({
description: 'ID of the social account',
required: false,
nullable: true,
})
social_account_id?: string;

@ApiProperty({
description: 'External account ID from the platform',
required: false,
nullable: true,
})
external_account_id?: string;

@ApiProperty({ description: 'Platform-specific account ID' })
platform_account_id: string;

@ApiProperty({ description: 'URL to the post on the platform' })
platform_url: string;

@ApiProperty({ description: 'Caption or text content of the post' })
caption: string;

@ApiProperty({
description: 'Array of media items attached to the post',
isArray: true,
})
media: any[];

@ApiProperty({
description: 'Post metrics and analytics data',
})
metrics: TikTokBusinessMetricsDto;
}
Loading