Complete reference for openapi.yaml — the single source of truth for Redocly-rendered API documentation. The backend team uses a Python codegen script to auto-generate their schema; this guide defines every convention so the generated output matches the file exactly.
The backend stage branch serializers are the source of truth for schemas and field names.
openapi: 3.0.3
info:
title: Core API Concepts
version: 1.0.0
description: '...' ← multi-line markdown, single-quoted YAML
paths: ← all endpoint definitions, ordered by sidebar position
/public/v1/.../
post: / get:
components:
schemas: ← all request/response models (alphabetical)
securitySchemes:
Bearer:
type: http
scheme: bearer
bearerFormat: JWT
servers:
- url: https://api-dashboard.influencers.club
description: Production
tags: ← tag definitions (name + optional description)
x-tagGroups: ← sidebar navigation groups (CRITICAL for visibility)- OpenAPI version: always
3.0.3. Not 3.1.0, not 3.0.0. - info.description: single-quoted YAML string with markdown. Bold headers (
**Discovery**), paragraphs separated by blank lines. Escape literal single quotes by doubling:can''t. - servers: one entry only — production URL. No staging/dev servers.
- securitySchemes: exactly
Bearer: { type: http, scheme: bearer, bearerFormat: JWT }. No other schemes. - Paths ordering: Creator Content → Enrichment → Discovery → Batch → Account (matches sidebar order).
- Schemas ordering: alphabetical by schema name.
/public/v1/creators/your/route/:
post:
operationId: public_v1_creators_your_route_create
description: 'Single-line summary of what the endpoint does.
**What you get**
- First bullet describing the primary return value.
- Second bullet with additional detail.
**Credits**
- X credits per successful request. If no data is returned, no credits
are deducted.
<div class="ic-ai-prompt-root" data-endpoint="your-endpoint-key"></div>'
summary: Your Endpoint Name
tags:
- Your Endpoint Name
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/YourInputSchema'
application/x-www-form-urlencoded:
schema:
$ref: '#/components/schemas/YourInputSchema'
multipart/form-data:
schema:
$ref: '#/components/schemas/YourInputSchema'
required: true
security:
- Bearer: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/YourResponseSchema'
description: ''
x-credits: X credits per successful request. /public/v1/discovery/classifier/languages/:
get:
operationId: public_v1_discovery_classifier_languages_list
description: 'Retrieve a list of supported languages...
**Credits**
- 0 credits. This endpoint does not deduct credits.'
summary: Languages
tags:
- Dictionary
security:
- Bearer: []
responses:
'200':
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Language'
description: ''
x-credits: 0 credits. This endpoint does not deduct credits.GET endpoints use parameters: instead of requestBody::
parameters:
- in: path
name: batch_id
schema:
type: string
description: Unique batch identifier
required: true
- in: query
name: format
schema:
type: string
enum:
- csv
- json
default: csv
required: false
- in: query
name: search
schema:
type: string
description: Search string to filter results
required: false
- in: query
name: offset
schema:
type: integer
description: Cursor offset for pagination
required: falseThe search + offset pagination pattern applies to classifier endpoints: audience-brand-categories, audience-brand-names, audience-interests, audience-locations.
All paths end with /: /public/v1/creators/socials/ not /public/v1/creators/socials.
- POST:
public_v1_{path_segments_with_underscores}_create - GET list:
public_v1_{path_segments_with_underscores}_list - GET single resource:
public_v1_{path_segments_with_underscores}_retrieve - Exception:
account_credits_usage_retrieve(does not follow thepublic_v1_prefix)
summary must match the tag name exactly — it becomes the sidebar label. Multiple endpoints can share one tag (e.g. all batch endpoints use Batch enrichment).
- Always a single-quoted YAML string.
- Content is indented 8 spaces (relative to the
description:key). - Escape single quotes by doubling:
can''trenders ascan't. - Opens with a summary sentence, then bold section headers.
Every endpoint must have What you get and Credits. Exception: simple classifier endpoints where Credits alone suffices if the summary is self-explanatory.
Add only when needed: When to use, How it works, Limits, Requirements, Output formats, Error Responses, Result format, Response fields, Supported content types per platform, Checking completion, Request.
for indentation in sub-bullets: **Instagram** — fixed at 12 posts per page- AI prompt div must be the last thing before the closing
':The<div class="ic-ai-prompt-root" data-endpoint="your-key"></div>'data-endpointvalue is kebab-case and matches theENDPOINTSarray incopy-for-ai.js.
Standard POST endpoints: all three content types pointing to the same $ref:
application/jsonapplication/x-www-form-urlencodedmultipart/form-data
Batch file upload exception: only multipart/form-data.
Always - Bearer: [].
Some endpoints include an explicit in: header Authorization parameter alongside security: - Bearer: []:
parameters:
- in: header
name: Authorization
schema:
type: string
description: Bearer << Client JWT Token >>
required: trueThis applies to: Similar Creators POST, and all batch GET/POST endpoints (download, status, resume).
Plain-text string after responses. Describes credit cost. Examples:
0.03 credits per successful request. If no data is returned, no credits are deducted.0.01 credits per creator returned. If no creators are returned, no credits are deducted.0 credits. This endpoint does not deduct credits.- Multi-line for batch:
'Credits are deducted when batch records are processed successfully. Pricing follows the same credit model as the corresponding enrichment type: Handle enrichment (raw): 0.03 credits per successful record...'
Most 200 responses have description: '' (empty string):
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/YourResponseSchema'
description: ''Two exceptions:
- Batch download:
description: CSV or JSON file with enriched results depending on the \format` query parameter.` - Account credits:
description: OK
Use type: object with additionalProperties: {}:
'400':
content:
application/json:
schema:
type: object
additionalProperties: {}
description: Bad Request - Invalid input
'403':
content:
application/json:
schema:
type: object
additionalProperties: {}
description: Forbidden - Insufficient permissions
'404':
content:
application/json:
schema:
type: object
additionalProperties: {}
description: Not Found - Invalid batch ID
'429':
content:
application/json:
schema:
type: object
additionalProperties: {}
description: Too Many Requests - Rate limit exceededCurrently used on: batch create (400/403/429), batch download (400/404), batch resume (400/403/404), batch status (404).
Batch download returns two content types:
'200':
description: CSV or JSON file with enriched results...
content:
text/csv:
schema:
type: string
format: binary
description: Default CSV file with enriched results
application/json:
schema:
type: array
items:
type: object
properties:
input_value:
type: string
status:
type: string
enrichment_data:
type: object
additionalProperties: trueMost endpoints wrap their result in a standard envelope:
SomeResponse:
type: object
properties:
credits_cost:
type: number
nullable: true
result:
$ref: '#/components/schemas/SomeResult'
required:
- resultVariations:
AudienceOverlapResponseaddscredits_left,status,success, and usesbasics/detailsinstead ofresult.DiscoveryAPIResponseusescredits_left(format: decimal),total,limit,accounts(array).response_metais internal and not documented.
The account credits endpoint defines its response schema inline in the path, not via $ref:
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
properties:
credits_available:
type: number
credits_used:
type: number
required:
- credits_available
- credits_used
example:
credits_available: 0
credits_used: 0A named schema AccountCreditsUsageResponse also exists in components but is not referenced by the path.
| Backend (Django REST Framework) | OpenAPI 3.0.3 |
|---|---|
serializers.CharField() | type: string |
serializers.CharField(required=True) | type: string, minLength: 1 + in required array |
serializers.CharField(allow_blank=True) | type: string (no minLength) |
serializers.IntegerField() | type: integer |
serializers.FloatField() | type: number, format: double |
serializers.DecimalField(max_digits=N, decimal_places=M) | type: string, format: decimal, pattern: ^-?\d{0,N}(?:\.\d{0,M})?$ |
serializers.BooleanField() | type: boolean |
serializers.DateTimeField() | type: string, format: date-time |
serializers.URLField() | type: string, format: uri |
serializers.EmailField() | type: string, format: email |
serializers.FileField() | type: string, format: binary |
serializers.DictField() | type: object, additionalProperties: {} |
serializers.ListField(child=CharField()) | type: array, items: { type: string } |
serializers.ListField() (no child) | type: array, items: {} |
serializers.ChoiceField(choices=[...]) | type: string, enum: [...] |
allow_null=True | Add nullable: true |
required=False | Do NOT include in required array |
required=True (or default) | Include in required array |
default=value | Add default: value |
min_length=N on ListField | minItems: N |
max_length=N on ListField | maxItems: N |
min_length=1 on CharField | minLength: 1 |
help_text="..." | description: '...' |
Nested SomeSerializer() | $ref: '#/components/schemas/Some' |
Nested SomeSerializer(many=True) | type: array, items: { $ref: '#/components/schemas/Some' } |
Nested with allow_null=True | allOf: [{ $ref }] + nullable: true (see composition patterns) |
| Pydantic | OpenAPI |
|---|---|
Field(default=None) | nullable: true, not in required |
Optional[str] | type: string, nullable: true |
Optional[int] | type: integer, nullable: true |
Optional[bool] | type: boolean, nullable: true |
Optional[list[str]] | type: array, items: { type: string }, nullable: true |
validation_alias=AliasChoices(...) | Use the first alias as the field name |
Use the exact field names from the backend serializer. If the serializer uses snake_case, the schema uses snake_case. If it uses camelCase, the schema uses camelCase. Do not rename fields.
Platform-native field names are kept as-is:
- Twitch:
profileImageURL,displayName,isPartner,panelsUrls - Twitter:
userid(no underscore) - ConnectedSocial:
userId,fullname
Any field that acts as an identifier (handle, creators, email, post_id, etc.) must have a description explaining exactly what values are accepted. Check the backend view to see how the field is processed.
handle:
type: string
description: 'Creator identifier — username, profile URL, or YouTube channel ID (UC...).'Never leave identifier fields with just type: string and no description.
| Suffix | When to use | Example |
|---|---|---|
Request | Input schemas for request bodies | AudienceFilterRequest, SortRequest |
RequestRequest | DRF auto-gen when serializer name already ends in Request | EnrichFullHandleRequestRequest |
Response | Top-level response wrappers | HandleFullPlatformResponse |
Result | Inner result data object | CreatorPostsResult, HandleFullResultResponse |
Query | Input for query-style POST endpoints | CreatorPostsQuery, ConnectedSocialsQuery |
Input | Input for specific action endpoints | AudienceOverlapInput |
Model | Sub-schema representing a data entity | PostItemModel, EngagementModel |
DocsRequest | Platform-specific variant for documentation display | DiscoveryAPISearchInputInstagramDocsRequest |
| (none) | Utility/reference schemas | Brand, Language, YouTubeTopic |
When a backend serializer is named SomeRequestSerializer, DRF auto-generation appends Request, producing SomeRequestRequest. This is expected behavior. Keep these names as-is to match backend codegen output. Current examples: EnrichFullHandleRequestRequest, EnrichRawHandleRequestRequest, EnrichBasicEmailRequestRequest, EnrichSimilarCreatorsRequestRequest, DiscoveryAPISearchInputRequestRequest.
For non-nullable required nested objects:
user:
$ref: '#/components/schemas/OverlapUser'OAS 3.0.3 cannot put nullable: true on a $ref directly. Use allOf:
gender:
allOf:
- $ref: '#/components/schemas/AudienceGenderFilterRequest'
nullable: trueAdding a description alongside a $ref:
creator_has:
allOf:
- $ref: '#/components/schemas/CreatorHasRequest'
description: 'Supported platforms: Instagram, YouTube, TikTok, Twitch, Twitter, OnlyFans'The most complex form, combining all modifiers:
subscriber_growth:
allOf:
- $ref: '#/components/schemas/GrowthRequest'
nullable: true
default:
growth_percentage: null
time_range_months: 3
description: 'Supported platforms: YouTube'Used for the Discovery API to show platform-specific request bodies:
DiscoveryAPISearchInputRequestRequest:
oneOf:
- $ref: '#/components/schemas/DiscoveryAPISearchInputInstagramDocsRequest'
- $ref: '#/components/schemas/DiscoveryAPISearchInputYouTubeDocsRequest'
- $ref: '#/components/schemas/DiscoveryAPISearchInputTikTokDocsRequest'
- $ref: '#/components/schemas/DiscoveryAPISearchInputTwitchDocsRequest'
- $ref: '#/components/schemas/DiscoveryAPISearchInputTwitterDocsRequest'
- $ref: '#/components/schemas/DiscoveryAPISearchInputOnlyFansDocsRequest'
discriminator:
propertyName: platform
mapping:
instagram: '#/components/schemas/DiscoveryAPISearchInputInstagramDocsRequest'
youtube: '#/components/schemas/DiscoveryAPISearchInputYouTubeDocsRequest'
tiktok: '#/components/schemas/DiscoveryAPISearchInputTikTokDocsRequest'
twitch: '#/components/schemas/DiscoveryAPISearchInputTwitchDocsRequest'
twitter: '#/components/schemas/DiscoveryAPISearchInputTwitterDocsRequest'
onlyfans: '#/components/schemas/DiscoveryAPISearchInputOnlyFansDocsRequest'Each platform DocsRequest constrains platform to a single-value enum and references platform-specific filters. The description on each explains the pattern:
Redocly can''t dynamically show/hide fields based on `platform`, so we expose
a `oneOf` discriminator in the view schema that points to per-platform request variants.Fields accepting either string or integer:
last_post:
oneOf:
- type: string
- type: integer
nullable: true
description: 'Supported platforms: Instagram, TikTok, Twitter'| Pattern | When to use | Example |
|---|---|---|
additionalProperties: {} | Flexible object, any key-value (DictField, error responses) | Error schemas, metadata, income_data |
additionalProperties: true | Explicit open-ended object | AudienceDataResponse, batch enrichment_data |
additionalProperties: { type: string } | Object with string values only | CreatorContentDetailsResponse.result |
| Format | Type | When to use | Example fields |
|---|---|---|---|
format: double | type: number | Float/engagement percentages, rates, min/max ranges | engagement_percent, credits_cost, min, max |
format: decimal | type: string | Python Decimal fields (serializes to string) | credits_left, credits_used |
format: date-time | type: string | Timestamp fields | created_at, started_at, estimated_completion |
format: uri | type: string | URL fields | picture, profile_pic_url, links_in_bio items |
format: email | type: string | Email fields | email in enrichment responses |
format: binary | type: string | File upload/download | file in batch input, CSV download response |
Important: format: decimal always pairs with a pattern regex and type: string (not type: number):
credits_left:
type: string
format: decimal
pattern: ^-?\d{0,8}(?:\.\d{0,2})?$Applied to required CharField fields that cannot be empty:
handle:
type: string
minLength: 1Applied to list fields:
creators:
type: array
items:
type: string
minItems: 2
maxItems: 10Only add if the backend serializer explicitly has allow_null=True or Pydantic uses Optional[...]. Do not add by default.
Must match the backend exactly:
- Boolean:
default: false(e.g.has_videos,exclude_role_based_emails,include_lookalikes) - Numeric:
default: 1(e.g.min_pcton audience filters),default: 3(time_range_months) - String:
default: csv,default: relevancy,default: desc,default: ok,default: preferred - Object:
default: { growth_percentage: null, time_range_months: 3 }
For decimal-formatted string fields:
credits_used:
type: string
format: decimal
pattern: ^-?\d{0,8}(?:\.\d{0,2})?$Lowercase values. Can be on the property directly or on array items:
platform:
enum:
- instagram
- youtube
- tiktok
type: string exclude_platforms:
type: array
items:
enum:
- instagram
- youtube
- tiktok
type: stringApplied to response schemas with deeply nested $ref structures. Tells Redocly to auto-expand 2 levels deep in the response panel. Place directly under the schema name:
BatchEnrichmentResponse:
type: object
x-expandLevel: 2
properties:
...Schemas that have x-expandLevel: 2:
BatchEnrichmentResponseBatchEnrichmentStatusResponseCreatorContentDetailsResponseHandleEmailPlatformResponseHandleEmailResponseHandleFullPlatformResponseHandleFullResultResponseHandleRawPlatformResponseHandleRawResultResponseAccountCreditsUsageResponse
See section 4 (path entry rules).
See section 13 (x-tagGroups rules).
Three tiers of per-platform schemas:
HandleRaw[Platform]Response— 12 platforms: Instagram, YouTube, TikTok, OnlyFans, Twitter, Twitch, Facebook, Pinterest, Reddit, Snapchat, Discord, LinkedIn. Collected viaHandleRawResultResponse.HandleFull[Platform]Response— 7 platforms: Instagram, YouTube, TikTok, OnlyFans, Twitter, Twitch, LinkedIn. Collected viaHandleFullResultResponse.HandleEmail[Platform]Response— 6 platforms: Instagram, YouTube, TikTok, OnlyFans, Twitter, Twitch. Collected viaHandleEmailPlatformResponse.
Each platform response has platform-native field names. Twitch uses camelCase (profileImageURL, displayName). Do not rename.
Large schema with 50+ boolean fields for platform/service presence filtering:
has_amazonaffiliates:
type: boolean
nullable: true
default: falseAll fields follow has_[platform_or_service] naming. Schema ends with example: {}.
AudienceFilterRequest is nullable: true and contains sub-schemas:
location— array ofAudienceLocationFilterRequestgender—allOf: [AudienceGenderFilterRequest], nullablelanguage— array ofAudienceLanguageFilterRequestage— array ofAudienceAgeFilterRequestinterests— array ofAudienceInterestFilterRequest- Plus simple fields:
brands,brand_categories,credibility(enum)
Each sub-filter has min_pct with default: 1.
Four related endpoints under the Batch enrichment tag:
POST /public/v1/enrichment/batch/— create (multipart only, error responses 400/403/429)GET /public/v1/enrichment/batch/{batch_id}/status/— check statusPOST /public/v1/enrichment/batch/{batch_id}/resume/— resume paused jobGET /public/v1/enrichment/batch/{batch_id}/— download results (CSV/JSON)
Raw platform data arrays where item type is unconstrained:
post_data:
type: array
items: {}Used sparingly on request and response schemas:
EnrichFullHandleRequestRequest:
type: object
...
example:
handle: cristiano
platform: instagram
email_required: preferred
include_lookalikes: false
include_audience_data: falseAlso used on CreatorHasRequest (example: {}) and inline response schemas (account credits).
Every endpoint should have a dedicated named Result schema (e.g. CreatorPostsResult, AudienceOverlapResponse) rather than inlining the response structure. Break nested objects into their own schemas so Redocly renders them as expandable sections.
Good — each nested object is its own schema:
CreatorPostsResult:
type: object
properties:
items:
type: array
items:
$ref: '#/components/schemas/PostItemModel'
num_results:
type: integer
PostItemModel:
type: object
properties:
pk:
type: string
engagement:
$ref: '#/components/schemas/EngagementModel'
user:
$ref: '#/components/schemas/UserInfoModel'Bad — everything inlined in one flat schema:
CreatorPostsResult:
type: object
properties:
items:
type: array
items:
type: object
properties:
pk:
type: string
likes:
type: integerFollow the backend serializer structure — if the backend has a nested serializer, create a corresponding named schema.
Note: This is planned for a future iteration. When updating or adding endpoints, start applying this pattern where practical.
Every request parameter should include:
- A
descriptionexplaining what the field does and what values are accepted. - An
examplevalue showing a realistic input.
handle:
type: string
description: 'Creator identifier — username, profile URL, or YouTube channel ID (UC...).'
example: 'cristiano'
platform:
type: string
enum:
- instagram
- tiktok
- youtube
description: 'Social platform to query.'
example: 'instagram'Located after servers:, before x-tagGroups. Each endpoint's tag must be listed here.
tags:
- name: Discovery API
- name: Similar Creators
- name: Audience Overlap
- name: Dictionary
description: |
Provides the complete set of supported filter values used by the Discovery
and Similar Creators endpoints...
- name: Connected Socials
- name: Enrich by handle full
- name: Enrich by handle raw
- name: Enrich by email
- name: Batch enrichment
description: 'Bulk enrichment jobs: create, check status, resume, and download results.'
- name: Creator Posts
- name: Post Details
- name: Account credits & usage
description: Account-level endpoints (credits, usage).Rules:
- Tags without descriptions:
- name: TagName - Multi-line descriptions: pipe literal
|block scalar - Single-line descriptions: single-quoted string
- Add
description:only when the tag name alone isn't self-explanatory
Located at the very bottom of the file. Every tag must be listed here or it will not appear in the sidebar.
x-tagGroups:
- name: Creator Discovery
tags:
- Discovery API
- Similar Creators
- Audience Overlap
- Dictionary
- name: Creator Enrichment
tags:
- Connected Socials
- Enrich by handle full
- Enrich by handle raw
- Enrich by email
- Batch enrichment
- name: Creator Content
tags:
- Creator Posts
- Post Details
- name: User Info
tags:
- Account credits & usageTo add a new endpoint: add its tag under the correct existing group. To create a new group: check with the team first — do not invent groups.
- Endpoint not in sidebar — tag missing from
x-tagGroups. - Tag undeclared — tag in
x-tagGroupsbut missing fromtags:section. - Schema field mismatch — field name doesn't match backend serializer (e.g.
camelCasevssnake_case). - Invented constraints — do not add
enum,minItems,maxItems,description, or any constraint not in the backend serializer. - Missing content types — POST
requestBodymust have all 3 (except batch: multipart only). - Broken YAML string — unescaped single quote in single-quoted description. Use
''. - Missing trailing slash — paths must end with
/. - Wrong operationId — must follow
public_v1_{path}_{method}convention. - Forgetting AI prompt div —
<div class="ic-ai-prompt-root" data-endpoint="..."></div>at end of every description. - Nullable without allow_null — only add
nullable: trueif backend hasallow_null=True. - $ref with nullable directly — OAS 3.0.3 cannot put
nullableon a$ref. Must useallOf: [{ $ref }]withnullable: true. - Wrong format for DecimalField — must be
type: string, format: decimal, NOTtype: number. - Missing minLength: 1 — required CharField fields should have
minLength: 1. - Missing x-expandLevel: 2 — response schemas with nested
$refshould have this for proper Redocly rendering. - Renaming platform-native fields — camelCase fields like
profileImageURL,displayName,isPartner,userIdmust be kept as-is.