---
title: "Create business"
method: POST
path: "/api/businesses"
tags: ["businesses"]
---

# Create business

`POST /api/businesses`

## Request

- Base URL: `https://api.mymarky.ai`
- URL: `https://api.mymarky.ai/api/businesses`
- Auth: HTTP bearer

Create a new business in your organization.

Send an `Idempotency-Key` header to make a retry safe (a resend with the same
key returns the original business instead of creating a duplicate).

Errors:
    401 authentication_required: API key or token is missing, invalid, or revoked.
    403 permission_denied: Your plan does not include API access.
    403 WORKSPACE_LIMIT_EXCEEDED: You hit your plan's workspace limit. Carries an
        `upgrade_url` (one-click "add a workspace" screen) and `workspace_limit`.
    422 IDEMPOTENCY_KEY_CONFLICT: The Idempotency-Key was reused with a different body.
    429 rate_limit_exceeded: You sent too many requests this minute.

## Headers

- `Idempotency-Key` string, nullable: Optional. Send a unique value (e.g. a UUID) to make this create request safe to retry. A repeat with the same key returns the original response instead of creating a duplicate. Cached for 24h, scoped to your org. Reusing a key with a different body returns 422.
- `Marky-Version` '2026-04-08' | '2026-07-17' | '2026-08-02' | '2026-08-04' | '2026-08-06'

## Request body

- BusinessCreateRequest
  - `tone` string, nullable: Brand voice — the tone and personality Marky writes captions in (the 'Profile' field in the app).
  - `audience_combined` string, nullable: The target audience the brand writes for — who the posts are meant to reach (the 'Target Audience' field in the app).
  - `caption_writing_rules` string, nullable: Extra rules Marky follows when writing captions. Put each rule on its own line (newline-separated) — do NOT write one long paragraph. The app shows each line as a separate rule chip, so a run-on paragraph renders as one un-editable blob. E.g. 'Never use emojis\nAlways end with a question\nKeep captions under 80 words'.
  - `caption_suffix` string, nullable: Text appended to the end of every generated caption (e.g. a hashtag block or a link).
  - `custom_caption_prompt` string, nullable: A custom instruction injected into caption generation for this business.
  - `custom_meme_prompt` string, nullable: A custom instruction injected into meme generation for this business.
  - `custom_carousel_prompt` string, nullable: A custom instruction injected into carousel generation for this business.
  - `design_style` string, nullable: Free-text/markdown guidance on how this brand's graphics should be COMPOSED — which palette colour leads, how gradients are used, where the logo sits, whitespace, type treatment. Do NOT restate the raw brand tokens here (colours, fonts, logo file); those live in palettes / header_font / body_font / logo_url. This is the judgement the tokens can't express. SCOPE: it is added to the prompt for AI-GENERATED images and sets the look of theme covers. It does NOT reach a template design, so it will not change a batch generated from templates — for those, use palettes / header_font / body_font / logo_url, creative_types and include_stock. SIZE: 5000 characters, and writing this field REPLACES the whole value. Plan to the cap before composing; the response's `field_budgets` entry tells you how much room is left.
  - `brand_style_grid_url` string, nullable: URL of a rendered 2x2 grid of four sample posts, all in ONE of the treatments from the design_style table — the first look the user kept when they ran /brand-setup. Written by /brand-setup at the end of that run; the app shows it so someone can SEE their look instead of reading it.
  - `strategy` string, nullable: Social strategy doc as MARKDOWN — the goal we're working toward, what we're trying right now, what we won't do, cadence and mix, plus a running log of experiments and what we learned. This is the layer an agency revisits each quarter. Write plain markdown (## headings, - bullets, | tables |); the app renders it in a rich-text editor, so no HTML tags — they show up as literal text and spend the size budget without adding meaning. Keep the pillars themselves in topics, the brand voice in tone/audience_combined, and how graphics look in design_style; strategy holds what none of those can express — what we're trying to ACHIEVE and what we've learned. SIZE: 6000 characters, and writing this field REPLACES the whole doc. A longer value is still saved, but it comes back with a warning you have to act on in the same turn — so plan the doc to the cap BEFORE you compose it, rather than writing long and compacting after. The response's `field_budgets` entry for this field tells you exactly how much room is left.
  - `tagline` string, nullable: Brand tagline shown on designs.
  - `ctas` string[], nullable: Call-to-action phrases Marky can use on designs (e.g. 'Call today', 'Book now').
  - `palettes` Palette[], nullable: Brand color palettes used on generated designs.
    - `name` string: Label for this palette
    - `colors` string[]: Hex color codes in the palette, e.g. ['#0d0c0c', '#FFFFFF', '#121212'].
    - `text_color` string, nullable: Hex color used for body text on designs
    - `accent_color` string, nullable: Hex accent/brand color
    - `background_color` string, nullable: Hex background color for designs
  - `header_font` FontSetting
    - `name` string, required: Font family name, e.g. 'Montserrat'. Must be a font Marky can load (a Google Font, or one with a direct url below).
    - `url` string, nullable: Direct font file URL. Leave null for a Google Font (Marky resolves it by name).
  - `body_font` FontSetting
    - `name` string, required: Font family name, e.g. 'Montserrat'. Must be a font Marky can load (a Google Font, or one with a direct url below).
    - `url` string, nullable: Direct font file URL. Leave null for a Google Font (Marky resolves it by name).
  - `logo_url` string, nullable: URL of the brand logo.
  - `logo_background_color` string, nullable: Background color behind the logo on designs (hex, or '#00000000' for transparent).
  - `logo_width` integer, nullable: Logo width in pixels, used when laying the logo onto designs.
  - `name` string, required: Business name
  - `description` string, nullable: Business description
  - `industry` string, nullable: Industry (e.g. 'Real Estate', 'Marketing Agency')
  - `website` string, nullable: Business website URL
  - `language` string: Content language, as an ISO 639-1 code (e.g. 'en') or English name (e.g. 'English'). Both accepted.

## Response `201`

Successful Response

- BusinessResponse
  - `tone` string, nullable: Brand voice — the tone and personality Marky writes captions in (the 'Profile' field in the app).
  - `audience_combined` string, nullable: The target audience the brand writes for — who the posts are meant to reach (the 'Target Audience' field in the app).
  - `caption_writing_rules` string, nullable: Extra rules Marky follows when writing captions. Put each rule on its own line (newline-separated) — do NOT write one long paragraph. The app shows each line as a separate rule chip, so a run-on paragraph renders as one un-editable blob. E.g. 'Never use emojis\nAlways end with a question\nKeep captions under 80 words'.
  - `caption_suffix` string, nullable: Text appended to the end of every generated caption (e.g. a hashtag block or a link).
  - `custom_caption_prompt` string, nullable: A custom instruction injected into caption generation for this business.
  - `custom_meme_prompt` string, nullable: A custom instruction injected into meme generation for this business.
  - `custom_carousel_prompt` string, nullable: A custom instruction injected into carousel generation for this business.
  - `design_style` string, nullable: Free-text/markdown guidance on how this brand's graphics should be COMPOSED — which palette colour leads, how gradients are used, where the logo sits, whitespace, type treatment. Do NOT restate the raw brand tokens here (colours, fonts, logo file); those live in palettes / header_font / body_font / logo_url. This is the judgement the tokens can't express. SCOPE: it is added to the prompt for AI-GENERATED images and sets the look of theme covers. It does NOT reach a template design, so it will not change a batch generated from templates — for those, use palettes / header_font / body_font / logo_url, creative_types and include_stock. SIZE: 5000 characters, and writing this field REPLACES the whole value. Plan to the cap before composing; the response's `field_budgets` entry tells you how much room is left.
  - `brand_style_grid_url` string, nullable: URL of a rendered 2x2 grid of four sample posts, all in ONE of the treatments from the design_style table — the first look the user kept when they ran /brand-setup. Written by /brand-setup at the end of that run; the app shows it so someone can SEE their look instead of reading it.
  - `strategy` string, nullable: Social strategy doc as MARKDOWN — the goal we're working toward, what we're trying right now, what we won't do, cadence and mix, plus a running log of experiments and what we learned. This is the layer an agency revisits each quarter. Write plain markdown (## headings, - bullets, | tables |); the app renders it in a rich-text editor, so no HTML tags — they show up as literal text and spend the size budget without adding meaning. Keep the pillars themselves in topics, the brand voice in tone/audience_combined, and how graphics look in design_style; strategy holds what none of those can express — what we're trying to ACHIEVE and what we've learned. SIZE: 6000 characters, and writing this field REPLACES the whole doc. A longer value is still saved, but it comes back with a warning you have to act on in the same turn — so plan the doc to the cap BEFORE you compose it, rather than writing long and compacting after. The response's `field_budgets` entry for this field tells you exactly how much room is left.
  - `tagline` string, nullable: Brand tagline shown on designs.
  - `ctas` string[], nullable: Call-to-action phrases Marky can use on designs (e.g. 'Call today', 'Book now').
  - `palettes` Palette[], nullable: Brand color palettes used on generated designs.
    - `name` string: Label for this palette
    - `colors` string[]: Hex color codes in the palette, e.g. ['#0d0c0c', '#FFFFFF', '#121212'].
    - `text_color` string, nullable: Hex color used for body text on designs
    - `accent_color` string, nullable: Hex accent/brand color
    - `background_color` string, nullable: Hex background color for designs
  - `header_font` FontSetting
    - `name` string, required: Font family name, e.g. 'Montserrat'. Must be a font Marky can load (a Google Font, or one with a direct url below).
    - `url` string, nullable: Direct font file URL. Leave null for a Google Font (Marky resolves it by name).
  - `body_font` FontSetting
    - `name` string, required: Font family name, e.g. 'Montserrat'. Must be a font Marky can load (a Google Font, or one with a direct url below).
    - `url` string, nullable: Direct font file URL. Leave null for a Google Font (Marky resolves it by name).
  - `logo_url` string, nullable: URL of the brand logo.
  - `logo_background_color` string, nullable: Background color behind the logo on designs (hex, or '#00000000' for transparent).
  - `logo_width` integer, nullable: Logo width in pixels, used when laying the logo onto designs.
  - `id` string, required: Business ID
  - `name` string, nullable: Business name
  - `description` string, nullable: Business description
  - `industry` string, nullable: Industry category
  - `website` string, nullable: Business website URL
  - `language` string: Content language as an ISO 639-1 code (e.g. 'en', 'fr', 'es').
  - `platform_writing_instructions` object, nullable: The user's customized per-platform caption-writing instructions (empty when none set). Keys are canonical platform names (e.g. 'instagram', 'linkedIn') plus 'common' (applies to all platforms). Follow the matching entry when writing a caption or platform_overrides caption — the user's instructions ALWAYS outrank generic platform best practices. Update via PATCH (merge semantics). Returned by get_business only, not the list endpoint.
  - `events` BusinessEvent[]: The business's own dated moments: launches, openings, sales, events (e.g. {'name': 'Hope Shop opening', 'date': '2026-10-10', 'kind': 'opening'}). They show up in list_upcoming_moments, and a caption that names one is dated to it. At most 20.
    - `name` string, required: e.g. 'Hope Shop opening'.
    - `date` string, date, required: The day it happens, YYYY-MM-DD, on the business's calendar.
    - `kind` 'launch' | 'opening' | 'sale' | 'event' | 'other': What sort of moment it is.
    - `note` string, nullable: Optional detail, e.g. '20% off'.
  - `include_stock` boolean: Whether generated posts may use stock photos. True when never set, because stock is allowed by default. Set with update_business.
  - `aspect_ratio` string, nullable: Default aspect ratio for generated designs ('1:1', '4:5' or '9:16'). Null when never set. Set with update_business.
  - `creative_types` object: Stored content-mix weights per creative format (keys: design, image-only, ai-image, gif, meme, video, carousel). Empty when never set, and generation then uses the default mix. Set with update_business.
  - `timezone` string, nullable: The business's IANA timezone (e.g. 'Europe/Warsaw'). Posting-schedule slots and `*_local` times use it, and holidays in moments come from its country. Null when unset: times are then UTC and holidays default to the US. Set with update_business.
  - `created_at` string, required: When the business was created
  - `updated_at` string, nullable: Last update time
  - `revision_id` string, nullable: Id of the undo record this write created. Pass it to revert_revisions to put the record back exactly as it was before this call. Set only on the response to a write; null when you read the record.
  - `logo_source_size` LogoSourceSize: The width and height of a logo file as it was given to us, before squaring.
    - `width` integer, required: Width in px of the logo file you sent
    - `height` integer, required: Height in px of the logo file you sent
  - `warnings` FieldWarning[], required: Non-blocking notes about fields that need attention, empty when there is nothing to do. Act on them in the same turn you see them — that is while you still have the content in context.
    - `field` string, required: The field this warning is about, e.g. 'strategy', 'caption' or 'platform_overrides[0].caption'.
    - `code` string, nullable: Stable machine-readable code, e.g. 'cta_without_contact'. Branch on this, never on the message. Null on the older size-budget warnings.
    - `level` 'approaching_limit' | 'over_limit' | 'advisory', required: 'approaching_limit' = past the soft limit, act soon. 'over_limit' = past the hard limit, act now. 'advisory' = worth fixing before this publishes, but it may be intended.
    - `message` string, required: Plain-language explanation of what is wrong and how to fix it.
  - `field_budgets` FieldBudget[], required: Size ceilings for the fields that get pasted into the prompt for every generated post. READ THIS BEFORE COMPOSING a value for one of these fields — `remaining` is the room you have, and a budgeted field is REPLACED whole on write, so `limit` is the real target. Over-budget writes are accepted, not rejected, but they cost a full rewrite to fix.
    - `field` string, required: The field this budget applies to.
    - `limit` integer, required: Hard ceiling, in characters.
    - `used` integer, required: Length of the field's current value, 0 when unset.
    - `remaining` integer, required: Characters left before the hard limit, floored at 0. This is the room a REPLACEMENT value has, since writing a budgeted field replaces it whole.

## Other responses

- `400`: Bad request — the input was malformed or otherwise invalid.
- `401`: Authentication failed — the API key is missing or invalid.
- `409`: Conflict — a resource like this already exists.
- `422`: Validation error — one or more fields failed validation.
- `429`: Rate limited — retry after the window resets (see Retry-After).
- `500`: Server error — something failed on our side; retry or quote X-Request-Id.

---

[API](https://skmtc.dev/mymarky/apis/marky-public-api.md) · [All operations](https://skmtc.dev/mymarky/apis/marky-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/mymarky/apis/marky-public-api/revisions/25aeacae455c?raw)
