> ## Documentation Index
> Fetch the complete documentation index at: https://docs.joinmarkt.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Create a product

> Create a product. It appears on the storefront according to its `visibility`.

**Scope:** `product:create`

> This changes real data in your store, including when you press **Send** here.



## OpenAPI

````yaml POST /api/merchant/v1/stores/{storeId}/products
openapi: 3.1.0
info:
  title: Join Markt Merchant API
  version: 1.0.0
  description: >-
    Manage your Join Markt store from your own code: products, orders,
    customers, coupons, themes and more.


    Create an API key in **Dashboard → Developers → API keys**, then send it as
    `Authorization: Bearer mk_live_…`. Each key only works on the stores and
    scopes you chose for it.


    Limits: 120 requests per minute per key. Every response is JSON.
  contact:
    name: Join Markt Support
    url: https://joinmarkt.com/contact
servers:
  - url: https://dash.joinmarkt.com
    description: Production
security:
  - bearerAuth: []
tags:
  - name: Store
    description: Store profile and settings.
  - name: Products
    description: Create, update and delete products, and manage license-key stock.
  - name: Categories
    description: Group products into categories.
  - name: Groups
    description: Bundle several products under one storefront card.
  - name: Orders
    description: Read orders, add notes and mark manual deliveries done.
  - name: Invoices
    description: Read invoices issued for orders.
  - name: Customers
    description: Read customers and adjust their store balance.
  - name: Coupons
    description: Create and manage discount codes.
  - name: Reviews
    description: Read buyer reviews and reply to them.
  - name: Tickets
    description: Support tickets from buyers.
  - name: Analytics
    description: Revenue and traffic numbers.
  - name: Balance & payouts
    description: Seller balance and payout requests.
  - name: Payments
    description: Payment method settings. Secrets are never returned.
  - name: Storefront
    description: Storefront appearance and integrations.
  - name: Themes
    description: Apply catalog themes and edit theme projects.
  - name: Domain
    description: Connect a custom domain.
  - name: Security
    description: Blacklist and anti-fraud settings.
  - name: Notifications
    description: Recent store notifications.
  - name: Discord
    description: Discord bot settings.
  - name: Import
    description: Import products and customers from another platform.
  - name: Webhooks
    description: Get events sent to your own server.
paths:
  /api/merchant/v1/stores/{storeId}/products:
    post:
      tags:
        - Products
      summary: Create a product
      description: >-
        Create a product. It appears on the storefront according to its
        `visibility`.


        **Scope:** `product:create`


        > This changes real data in your store, including when you press
        **Send** here.
      operationId: postProducts
      parameters:
        - $ref: '#/components/parameters/storeId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  minLength: 1
                  maxLength: 200
                description:
                  type: string
                  minLength: 1
                  maxLength: 50000
                price:
                  type: number
                  minimum: 0
                  maximum: 1000000
                slashedPrice:
                  anyOf:
                    - type: number
                      minimum: 0
                      maximum: 1000000
                    - type: 'null'
                images:
                  maxItems: 20
                  type: array
                  items:
                    type: string
                    maxLength: 500
                visibility:
                  type: string
                  enum:
                    - public
                    - private
                    - unlisted
                    - on-hold
                categoryId:
                  anyOf:
                    - type: string
                      maxLength: 100
                    - type: 'null'
                variants:
                  type: array
                  items:
                    type: object
                    propertyNames:
                      type: string
                    additionalProperties: {}
                deliveryConfig:
                  type: object
                  properties:
                    methods:
                      minItems: 1
                      type: array
                      items:
                        type: string
                        enum:
                          - license_key
                          - download_file
                          - delivery_instructions
                          - custom_fields
                          - manual_delivery
                    downloadFiles:
                      maxItems: 20
                      type: array
                      items:
                        type: object
                        properties:
                          id:
                            type: string
                            minLength: 1
                            maxLength: 100
                          name:
                            type: string
                            minLength: 1
                            maxLength: 200
                          url:
                            type: string
                            minLength: 1
                            maxLength: 500
                          size:
                            type: integer
                            minimum: 0
                            maximum: 9007199254740991
                        required:
                          - id
                          - name
                          - url
                    manualDelivery:
                      anyOf:
                        - type: object
                          properties:
                            message:
                              type: string
                              maxLength: 2000
                        - type: 'null'
                    deliveryInstructions:
                      anyOf:
                        - type: object
                          properties:
                            content:
                              type: string
                              minLength: 1
                              maxLength: 50000
                          required:
                            - content
                        - type: 'null'
                    customFields:
                      maxItems: 20
                      type: array
                      items:
                        type: object
                        properties:
                          id:
                            type: string
                            minLength: 1
                          label:
                            type: string
                            minLength: 1
                            maxLength: 120
                          identifier:
                            type: string
                            minLength: 1
                            maxLength: 64
                            pattern: ^[a-z][a-z0-9_]*$
                          type:
                            type: string
                            enum:
                              - text
                              - textarea
                              - dropdown
                              - checkbox
                              - radio
                              - number
                          placeholder:
                            type: string
                            maxLength: 200
                          helpText:
                            type: string
                            maxLength: 500
                          required:
                            default: false
                            type: boolean
                          options:
                            maxItems: 20
                            type: array
                            items:
                              type: string
                              minLength: 1
                              maxLength: 120
                        required:
                          - id
                          - label
                          - identifier
                          - type
                    discordRole:
                      anyOf:
                        - type: object
                          properties:
                            guildId:
                              type: string
                              pattern: ^\d{5,32}$
                            roleId:
                              type: string
                              pattern: ^\d{5,32}$
                          required:
                            - guildId
                            - roleId
                        - type: 'null'
                    instructions:
                      anyOf:
                        - type: string
                          maxLength: 50000
                        - type: 'null'
                  required:
                    - methods
                displayConfig:
                  type: object
                  properties:
                    hideStockCount:
                      default: false
                      type: boolean
                    liveViewsEnabled:
                      default: false
                      type: boolean
                    showViewsCount:
                      default: false
                      type: boolean
                    liveSalesEnabled:
                      default: false
                      type: boolean
                    showSalesCount:
                      default: false
                      type: boolean
                    liveSalesNotifications:
                      default: false
                      type: boolean
                    showSalesNotifications:
                      default: false
                      type: boolean
                slug:
                  type: string
                  minLength: 1
                  maxLength: 200
                metaTitle:
                  anyOf:
                    - type: string
                      maxLength: 200
                    - type: 'null'
                metaDescription:
                  anyOf:
                    - type: string
                      maxLength: 500
                    - type: 'null'
                metaImage:
                  anyOf:
                    - type: string
                      maxLength: 500
                    - type: 'null'
                embedCardType:
                  anyOf:
                    - type: string
                      enum:
                        - small
                        - large
                    - type: 'null'
              required:
                - name
                - description
                - price
            example:
              name: Example
              description: example description
              price: 19.99
      responses:
        '201':
          description: The new product.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
      x-codeSamples:
        - lang: bash
          label: cURL
          source: >-
            curl -X POST
            "https://dash.joinmarkt.com/api/merchant/v1/stores/STORE_ID/products"
            \
              -H "Authorization: Bearer $JOIN_MARKT_API_KEY" \
              -H "Content-Type: application/json" \
              -d '{"name":"Example","description":"example description","price":19.99}'
        - lang: javascript
          label: JavaScript
          source: >-
            const res = await
            fetch("https://dash.joinmarkt.com/api/merchant/v1/stores/STORE_ID/products",
            {
              method: "POST",
              headers: {
                Authorization: `Bearer ${process.env.JOIN_MARKT_API_KEY}`,
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                "name": "Example",
                "description": "example description",
                "price": 19.99
              }),
            })

            const data = await res.json()
        - lang: python
          label: Python
          source: |-
            import os, requests

            res = requests.post(
                "https://dash.joinmarkt.com/api/merchant/v1/stores/STORE_ID/products",
                headers={"Authorization": f"Bearer {os.environ['JOIN_MARKT_API_KEY']}"},
                json={
                  "name": "Example",
                  "description": "example description",
                  "price": 19.99
                },
            )
            data = res.json()
components:
  parameters:
    storeId:
      name: storeId
      in: path
      required: true
      description: >-
        Your store id. Find it in Dashboard → Developers, or in `GET /stores`
        with MCP.
      schema:
        type: string
  responses:
    BadRequest:
      description: The request body or a parameter is not valid. `error` names the field.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: The API key is missing, wrong, expired or revoked.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Forbidden:
      description: The key is valid but has no access to this store, or lacks the scope.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    RateLimited:
      description: More than 120 requests in a minute. Wait and try again.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  schemas:
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: string
          description: What went wrong, in plain words.
          examples:
            - Product not found
        code:
          type: string
          description: Stable error code.
          examples:
            - NOT_FOUND
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: mk_live_…
      description: Your Merchant API key. Create one in Dashboard → Developers → API keys.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.