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

# (Beta) Update messages of a campaign in batch

> Update up to 100 messages of a campaign in review, each with the fields `PATCH /v1/campaigns/:campaignId/messages/:messageId` accepts. Each record is updated on its own, in order: one that fails does not prevent the others from being updated. A campaign that is not in review fails the whole request with a 409.

Edit a message of a campaign in review, as the app does: only the fields given change. The content of a message is final, so `{{variables}}` are rejected, apart from `{{signature}}` and `{{unsubscribeLink}}`. A body read back ends with `<p>{{signature}}</p>` when signed: keep it to keep the message's signature as it is, edited or not; a body without it has no signature. `{{unsubscribeLink}}` links to the unsubscribe page of that message.

A blank subject or body is rejected. A follow-up sent in the same thread takes no subject; a new subject on a message of the first step carries to the follow-ups of its thread. Edits are lost if the campaign goes back to draft, as its messages are generated again on the next review.<br/><Warning>This endpoint is currently in open beta. The API surface may change as we iterate based on feedback.</Warning>



## OpenAPI

````yaml /schemas/2025-06-09.json post /v1/campaigns/{campaignId}/messages/batch/update
openapi: 3.1.0
info:
  title: Folk External API
  description: >-
    Folk's public REST API lets you manage workspaces, groups, contacts, and
    real-time triggers.
  version: '2025-06-09'
  contact:
    name: folk
    email: tech@folk.app
    url: https://folk.app
servers:
  - url: https://api.folk.app
    description: Folk's public API production base URL.
    x-internal: false
security: []
tags:
  - name: Campaigns
    description: >-
      Operations related to campaigns: emails, or sequences of emails, sent to
      people or companies, and their messages.
  - name: Companies
    description: Operations related to companies.
  - name: Credits
    description: Operations related to credits.
  - name: Custom objects
    description: >-
      Operations related to objects of any type in a group, such as deals. Every
      object type shares these endpoints, with its name given as the
      `objectType` path parameter.
  - name: Groups
    description: Operations related to groups.
  - name: Group members
    description: Operations related to group members.
  - name: Group custom fields
    description: Operations related to group custom fields.
  - name: Interactions
    description: Operations related to interactions.
  - name: Notes
    description: Operations related to notes.
  - name: People
    description: Operations related to people.
  - name: Person enrichments
    description: Operations related to person enrichments.
  - name: Reminders
    description: Operations related to reminders.
  - name: Tasks
    description: Operations related to tasks.
  - name: Users
    description: Operations related to users.
  - name: Views
    description: Operations related to views.
  - name: Webhooks
    description: Operations related to webhooks.
paths:
  /v1/campaigns/{campaignId}/messages/batch/update:
    post:
      tags:
        - Campaigns
      summary: Update messages of a campaign in batch
      description: >-
        Update up to 100 messages of a campaign in review, each with the fields
        `PATCH /v1/campaigns/:campaignId/messages/:messageId` accepts. Each
        record is updated on its own, in order: one that fails does not prevent
        the others from being updated. A campaign that is not in review fails
        the whole request with a 409.


        Edit a message of a campaign in review, as the app does: only the fields
        given change. The content of a message is final, so `{{variables}}` are
        rejected, apart from `{{signature}}` and `{{unsubscribeLink}}`. A body
        read back ends with `<p>{{signature}}</p>` when signed: keep it to keep
        the message's signature as it is, edited or not; a body without it has
        no signature. `{{unsubscribeLink}}` links to the unsubscribe page of
        that message.


        A blank subject or body is rejected. A follow-up sent in the same thread
        takes no subject; a new subject on a message of the first step carries
        to the follow-ups of its thread. Edits are lost if the campaign goes
        back to draft, as its messages are generated again on the next
        review.<br/><Warning>This endpoint is currently in open beta. The API
        surface may change as we iterate based on feedback.</Warning>
      operationId: batchUpdateCampaignMessages
      parameters:
        - schema:
            type: string
            minLength: 40
            maxLength: 40
          required: true
          description: The ID of the campaign.
          name: campaignId
          in: path
        - schema:
            type: string
            maxLength: 255
            description: >-
              A unique key, such as a UUID, that makes retrying this request
              safe: a retry with the same key and body returns the original
              response without running the operation again. Keys are kept for 24
              hours after the request completes.
            example: 8e03978e-40d5-43e8-bc93-6894a57f9324
          required: false
          name: Idempotency-Key
          in: header
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                records:
                  type: array
                  items:
                    type: object
                    properties:
                      id:
                        type: string
                        minLength: 40
                        maxLength: 40
                        description: The ID of the message to update.
                      subject:
                        type: string
                        maxLength: 1000
                        description: >-
                          The subject of the message, in plain text. A follow-up
                          sent in the same thread has the first step's subject,
                          so it takes none. Leave it out to keep the current
                          one.
                        example: Congrats on the round, Ana
                      body:
                        type: string
                        maxLength: 200000
                        description: >-
                          The body of the message, in HTML (or plain text with
                          `bodyFormat: "text"`). Its content is final:
                          `{{variables}}` are rejected, apart from
                          `{{signature}}` and `{{unsubscribeLink}}`. End it with
                          `<p>{{signature}}</p>` to keep the message's signature
                          as it is, edited or not; a body without it has no
                          signature. An unsubscribe link, for SendGrid senders
                          only, is `<a href="{{unsubscribeLink}}">`. Leave it
                          out to keep the current body.
                        example: >-
                          <p>Hi Ana, congrats on the
                          round!</p><p>{{signature}}</p>
                      bodyFormat:
                        type: string
                        enum:
                          - html
                          - text
                        description: >-
                          How `body` is written. `html` (default) is read as
                          HTML. `text` is plain text: a blank line starts a new
                          paragraph, each further blank line adds an empty
                          paragraph, a single newline is a line break, and `<`
                          and `&` are literal characters. Bodies always read
                          back as HTML.
                        example: html
                      cc:
                        type: array
                        items:
                          type: string
                          maxLength: 254
                        maxItems: 50
                        description: >-
                          Email addresses copied on the message. Leave it out to
                          keep the current ones. At most 5 distinct addresses;
                          duplicates are removed.
                        example:
                          - jane.doe@example.com
                      bcc:
                        type: array
                        items:
                          type: string
                          maxLength: 254
                        maxItems: 50
                        description: >-
                          Email addresses blind-copied on the message. Leave it
                          out to keep the current ones. At most 5 distinct
                          addresses; duplicates are removed.
                        example:
                          - jane.doe@example.com
                    required:
                      - id
                    additionalProperties: false
                    description: >-
                      The final content of one message: only the fields given
                      change.
                    example:
                      id: msg_4c8a0e5b-6f1d-4b8a-9d2e-7a3b5c1d9e0f
                      subject: Congrats on the round, Ana
                      body: >-
                        <p>Hi Ana, congrats on the
                        round!</p><p>{{signature}}</p>
                  maxItems: 100
              required:
                - records
              example:
                records:
                  - id: msg_4c8a0e5b-6f1d-4b8a-9d2e-7a3b5c1d9e0f
                    subject: Congrats on the round, Ana
                    body: <p>Hi Ana, congrats on the round!</p><p>{{signature}}</p>
      responses:
        '200':
          description: The outcome of each record, with each updated message.
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-RateLimit-Limit-Burst:
              $ref: '#/components/headers/X-RateLimit-Limit-Burst'
            X-RateLimit-Remaining-Burst:
              $ref: '#/components/headers/X-RateLimit-Remaining-Burst'
            X-RateLimit-Reset-Burst:
              $ref: '#/components/headers/X-RateLimit-Reset-Burst'
            RateLimit-Policy:
              $ref: '#/components/headers/RateLimit-Policy'
            RateLimit:
              $ref: '#/components/headers/RateLimit'
            Retry-After:
              $ref: '#/components/headers/Retry-After'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      results:
                        type: array
                        items:
                          oneOf:
                            - type: object
                              properties:
                                status:
                                  type: string
                                  enum:
                                    - succeeded
                                data:
                                  $ref: '#/components/schemas/MSG_Message'
                                warnings:
                                  type: array
                                  items:
                                    type: string
                                  description: >-
                                    What could not be applied to this record
                                    although it succeeded, such as a group it
                                    could not be added to.
                              required:
                                - status
                                - data
                            - type: object
                              properties:
                                status:
                                  type: string
                                  enum:
                                    - failed
                                error:
                                  $ref: '#/components/schemas/BatchRecordError'
                              required:
                                - status
                                - error
                        description: >-
                          One result per record, in the order of `records`: the
                          first result is the outcome of the first record.
                    required:
                      - results
                    example:
                      results:
                        - status: succeeded
                          data:
                            id: msg_1d2c3b4a-5e6f-4a7b-8c9d-0e1f2a3b4c5d
                            campaignId: cmp_9b2f1c1e-2b8a-4d1e-8f5a-3c2d1e0f9a8b
                            step: 1
                            recipient:
                              contact:
                                id: per_55175e81-9a52-4ac3-930e-82792c23499b
                                entityType: person
                              name: John Doe
                              email: john.doe@example.com
                            sender:
                              id: snd_4c3b2a19-8f7e-4d6c-9b5a-1e2f3d4c5b6a
                              email: john.doe@example.com
                              displayName: John Doe
                            subject: Quick question, John
                            body: <p>Hi John,</p><p>{{signature}}</p>
                            cc: []
                            bcc: []
                            status: draft
                            notSentReason: null
                            unsubscribed: false
                        - status: failed
                          error:
                            code: NOT_FOUND
                            message: Not found.
                            documentationUrl: >-
                              https://developer.folk.app/api-reference/errors#not-found
                  deprecations:
                    type: array
                    items:
                      type: string
                    example:
                      - This field is deprecated
                required:
                  - data
              example:
                data:
                  results:
                    - status: succeeded
                      data:
                        id: msg_1d2c3b4a-5e6f-4a7b-8c9d-0e1f2a3b4c5d
                        campaignId: cmp_9b2f1c1e-2b8a-4d1e-8f5a-3c2d1e0f9a8b
                        step: 1
                        recipient:
                          contact:
                            id: per_55175e81-9a52-4ac3-930e-82792c23499b
                            entityType: person
                          name: John Doe
                          email: john.doe@example.com
                        sender:
                          id: snd_4c3b2a19-8f7e-4d6c-9b5a-1e2f3d4c5b6a
                          email: john.doe@example.com
                          displayName: John Doe
                        subject: Quick question, John
                        body: <p>Hi John,</p><p>{{signature}}</p>
                        cc: []
                        bcc: []
                        status: draft
                        notSentReason: null
                        unsubscribed: false
                    - status: failed
                      error:
                        code: NOT_FOUND
                        message: Not found.
                        documentationUrl: >-
                          https://developer.folk.app/api-reference/errors#not-found
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
      security:
        - bearerApiKeyAuth: []
components:
  headers:
    X-RateLimit-Limit:
      schema:
        type: integer
        example: 1000
      description: >-
        The maximum number of requests that you can make in the current rate
        limit window.
    X-RateLimit-Remaining:
      schema:
        type: integer
        example: 998
      description: The number of requests remaining in the current rate limit window.
    X-RateLimit-Reset:
      schema:
        type: integer
        example: 1747322958
      description: >-
        The time at which the current rate limit window resets, in UTC epoch
        seconds.
    X-RateLimit-Limit-Burst:
      schema:
        type: integer
        example: 20
      description: >-
        The maximum number of requests that you can make in the current burst
        rate limit window.
    X-RateLimit-Remaining-Burst:
      schema:
        type: integer
        example: 18
      description: The number of requests remaining in the current burst rate limit window.
    X-RateLimit-Reset-Burst:
      schema:
        type: integer
        example: 1747322902
      description: >-
        The time at which the current burst rate limit window resets, in UTC
        epoch seconds.
    RateLimit-Policy:
      schema:
        type: string
        example: '"default";q=600;w=60, "burst";q=20;w=2'
      description: >-
        The rate limit policies applied to the request, as defined by the IETF
        RateLimit header fields draft. `q` is the number of requests allowed per
        window and `w` the window length in seconds.
    RateLimit:
      schema:
        type: string
        example: '"default";r=598;t=42, "burst";r=18;t=1'
      description: >-
        The current usage of each rate limit policy, as defined by the IETF
        RateLimit header fields draft. `r` is the number of requests remaining
        and `t` the number of seconds until the window resets.
    Retry-After:
      schema:
        type: integer
        example: 60
      description: >-
        The number of seconds to wait before making a new request after hitting
        the rate limit.
  schemas:
    MSG_Message:
      type: object
      properties:
        id:
          type: string
        campaignId:
          type: string
        step:
          type: integer
          minimum: 1
          description: The position of the step the message belongs to.
          example: 1
        recipient:
          type: object
          properties:
            contact:
              type:
                - object
                - 'null'
              properties:
                id:
                  type: string
                  example: per_55175e81-9a52-4ac3-930e-82792c23499b
                entityType:
                  type: string
                  enum:
                    - person
                    - company
                  description: Whether the recipients are people or companies.
                  example: person
              required:
                - id
                - entityType
              description: >-
                The person or company the message is for, or null once it was
                deleted.
            name:
              type:
                - string
                - 'null'
              description: >-
                The recipient's name: the one the message was addressed to once
                sent or not sent, the contact's current one while draft.
              example: John Doe
            email:
              type:
                - string
                - 'null'
              description: >-
                The recipient's email address: the one the message was addressed
                to once sent or not sent, the contact's current primary one
                while draft.
              example: john.doe@example.com
          required:
            - contact
            - name
            - email
          description: Who the message is addressed to.
        sender:
          type:
            - object
            - 'null'
          properties:
            id:
              type:
                - string
                - 'null'
              description: >-
                The ID of the sender, or null once it was deleted. `email` and
                `displayName` are then those the email was set up with.
              example: snd_4c3b2a19-8f7e-4d6c-9b5a-1e2f3d4c5b6a
            email:
              type: string
              description: The email address the email is sent from.
              example: john.doe@example.com
            displayName:
              type:
                - string
                - 'null'
              description: The name the email is sent under.
              example: John Doe
          required:
            - id
            - email
            - displayName
          description: >-
            Who the message is from: the address sending used, once it was
            attempted; the step's sender otherwise, while draft or when stopped
            before sending. `id` is null once the sender was deleted. Null when
            there is no sender.
        subject:
          type: string
          description: The subject of the message, in plain text.
          example: Quick question, John
        body:
          type: string
          description: >-
            The body of the message, in HTML. A signed body ends with
            `<p>{{signature}}</p>`. Some older messages instead end with the
            signature written out as ordinary HTML.
          example: <p>Hi John,</p><p>{{signature}}</p>
        cc:
          type: array
          items:
            type: string
          description: Email addresses copied on the message.
          example: []
        bcc:
          type: array
          items:
            type: string
          description: Email addresses blind-copied on the message.
          example: []
        status:
          type: string
          enum:
            - draft
            - sent
            - not_sent
          description: 'The status of the message. One of: draft, sent, not_sent.'
          example: draft
        notSentReason:
          type:
            - string
            - 'null'
          description: >-
            Why the message was not sent, when its status is `not_sent`. Known
            values: no_recipient, recipient_not_found, recipient_no_email,
            recipient_invalid_email, too_many_copies, invalid_sender, stopped,
            stopped_after_reply, previous_messages_not_sent,
            dropped_unsubscribed_address, dropped_bounced_address,
            dropped_spam_reporting_address, dropped_spam_content,
            dropped_invalid, bounce_invalid_address, bounce_technical,
            bounce_content, bounce_reputation,
            bounce_frequency_or_volume_too_high, bounce_mailbox_unavailable,
            bounce_unclassified, send_failed. New values may be added in the
            future: handle unknown values gracefully. Treat unknown ones as
            `send_failed`.
          example: null
        unsubscribed:
          type: boolean
          description: >-
            Whether the recipient unsubscribed through the link in this message.
            The message stays sent.
          example: false
      required:
        - id
        - campaignId
        - step
        - recipient
        - sender
        - subject
        - body
        - cc
        - bcc
        - status
        - notSentReason
        - unsubscribed
      description: >-
        A message of a campaign: the email of one step for one recipient, with
        the variables of the step filled in for that recipient. There is one
        message per recipient and per step.
      example:
        id: msg_1d2c3b4a-5e6f-4a7b-8c9d-0e1f2a3b4c5d
        campaignId: cmp_9b2f1c1e-2b8a-4d1e-8f5a-3c2d1e0f9a8b
        step: 1
        recipient:
          contact:
            id: per_55175e81-9a52-4ac3-930e-82792c23499b
            entityType: person
          name: John Doe
          email: john.doe@example.com
        sender:
          id: snd_4c3b2a19-8f7e-4d6c-9b5a-1e2f3d4c5b6a
          email: john.doe@example.com
          displayName: John Doe
        subject: Quick question, John
        body: <p>Hi John,</p><p>{{signature}}</p>
        cc: []
        bcc: []
        status: draft
        notSentReason: null
        unsubscribed: false
    BatchRecordError:
      type: object
      properties:
        code:
          type: string
          example: NOT_FOUND
        message:
          type: string
          example: Not found.
        documentationUrl:
          type: string
          format: uri
          example: https://developer.folk.app/api-reference/errors#not-found
        details:
          type: object
          additionalProperties: true
      required:
        - code
        - message
        - documentationUrl
      description: Why this record did not succeed.
      example:
        code: NOT_FOUND
        message: Not found.
        documentationUrl: https://developer.folk.app/api-reference/errors#not-found
    Error:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
              example: TOO_MANY_REQUESTS
            message:
              type: string
              example: You have exceeded your rate limit.
            documentationUrl:
              type: string
              format: uri
              example: https://developer.folk.app/api-reference/errors#rate-limiting
            requestId:
              type: string
              format: uuid
              example: 123e4567-e89b-12d3-a456-426614174000
            timestamp:
              type: string
              format: date-time
              example: '2025-10-01T12:00:00Z'
            details:
              type: object
              additionalProperties: true
              example:
                policy: burst
                limit: 20
                remaining: 0
                windowSeconds: 2
                retryAfter: '2025-10-01T12:00:02.000Z'
          required:
            - code
            - message
            - documentationUrl
            - requestId
            - timestamp
      required:
        - error
      description: Error response containing error details.
    RateLimitError:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
              example: TOO_MANY_REQUESTS
            message:
              type: string
              example: You have exceeded your rate limit.
            documentationUrl:
              type: string
              format: uri
              example: https://developer.folk.app/api-reference/errors#rate-limiting
            requestId:
              type: string
              format: uuid
              example: 123e4567-e89b-12d3-a456-426614174000
            timestamp:
              type: string
              format: date-time
              example: '2025-10-01T12:00:00Z'
            details:
              type: object
              properties:
                policy:
                  type: string
                  enum:
                    - default
                    - burst
                  description: The name of the rate limit policy.
                limit:
                  type: integer
                  description: The maximum number of requests allowed per window.
                remaining:
                  type: integer
                  description: The number of requests remaining in the current window.
                windowSeconds:
                  type: integer
                  description: The length of the window, in seconds.
                retryAfter:
                  type: string
                  format: date-time
                  description: When the current window resets.
                policies:
                  type: array
                  items:
                    type: object
                    properties:
                      policy:
                        type: string
                        enum:
                          - default
                          - burst
                        description: The name of the rate limit policy.
                      limit:
                        type: integer
                        description: The maximum number of requests allowed per window.
                      remaining:
                        type: integer
                        description: >-
                          The number of requests remaining in the current
                          window.
                      windowSeconds:
                        type: integer
                        description: The length of the window, in seconds.
                      retryAfter:
                        type: string
                        format: date-time
                        description: When the current window resets.
                    required:
                      - policy
                      - limit
                      - remaining
                      - windowSeconds
                      - retryAfter
                  description: >-
                    The status of every rate limit policy applied to the
                    request.
              required:
                - policy
                - limit
                - remaining
                - windowSeconds
                - retryAfter
                - policies
              description: >-
                The exceeded rate limit policy. When several are exceeded, the
                one resetting last.
          required:
            - code
            - message
            - documentationUrl
            - requestId
            - timestamp
            - details
      required:
        - error
      description: Error response returned when a rate limit is exceeded.
  responses:
    BadRequest:
      description: The request was unacceptable, often due to missing an invalid parameter.
      headers:
        X-RateLimit-Limit:
          $ref: '#/components/headers/X-RateLimit-Limit'
        X-RateLimit-Remaining:
          $ref: '#/components/headers/X-RateLimit-Remaining'
        X-RateLimit-Reset:
          $ref: '#/components/headers/X-RateLimit-Reset'
        X-RateLimit-Limit-Burst:
          $ref: '#/components/headers/X-RateLimit-Limit-Burst'
        X-RateLimit-Remaining-Burst:
          $ref: '#/components/headers/X-RateLimit-Remaining-Burst'
        X-RateLimit-Reset-Burst:
          $ref: '#/components/headers/X-RateLimit-Reset-Burst'
        RateLimit-Policy:
          $ref: '#/components/headers/RateLimit-Policy'
        RateLimit:
          $ref: '#/components/headers/RateLimit'
        Retry-After:
          $ref: '#/components/headers/Retry-After'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: INVALID_REQUEST
              message: The request was invalid.
              documentationUrl: https://developer.folk.app/api-reference/errors#bad-request
              requestId: 123e4567-e89b-12d3-a456-426614174000
              timestamp: '2025-10-01T12:00:00Z'
    Unauthorized:
      description: No valid API key provided.
      headers:
        X-RateLimit-Limit:
          $ref: '#/components/headers/X-RateLimit-Limit'
        X-RateLimit-Remaining:
          $ref: '#/components/headers/X-RateLimit-Remaining'
        X-RateLimit-Reset:
          $ref: '#/components/headers/X-RateLimit-Reset'
        X-RateLimit-Limit-Burst:
          $ref: '#/components/headers/X-RateLimit-Limit-Burst'
        X-RateLimit-Remaining-Burst:
          $ref: '#/components/headers/X-RateLimit-Remaining-Burst'
        X-RateLimit-Reset-Burst:
          $ref: '#/components/headers/X-RateLimit-Reset-Burst'
        RateLimit-Policy:
          $ref: '#/components/headers/RateLimit-Policy'
        RateLimit:
          $ref: '#/components/headers/RateLimit'
        Retry-After:
          $ref: '#/components/headers/Retry-After'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: UNAUTHORIZED
              message: No valid API key provided.
              documentationUrl: https://developer.folk.app/api-reference/errors#unauthorized
              requestId: 123e4567-e89b-12d3-a456-426614174000
              timestamp: '2025-10-01T12:00:00Z'
    Forbidden:
      description: The API key doesn’t have permissions to perform the request.
      headers:
        X-RateLimit-Limit:
          $ref: '#/components/headers/X-RateLimit-Limit'
        X-RateLimit-Remaining:
          $ref: '#/components/headers/X-RateLimit-Remaining'
        X-RateLimit-Reset:
          $ref: '#/components/headers/X-RateLimit-Reset'
        X-RateLimit-Limit-Burst:
          $ref: '#/components/headers/X-RateLimit-Limit-Burst'
        X-RateLimit-Remaining-Burst:
          $ref: '#/components/headers/X-RateLimit-Remaining-Burst'
        X-RateLimit-Reset-Burst:
          $ref: '#/components/headers/X-RateLimit-Reset-Burst'
        RateLimit-Policy:
          $ref: '#/components/headers/RateLimit-Policy'
        RateLimit:
          $ref: '#/components/headers/RateLimit'
        Retry-After:
          $ref: '#/components/headers/Retry-After'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: FORBIDDEN
              message: The API key doesn’t have permissions to perform the request.
              documentationUrl: https://developer.folk.app/api-reference/errors#forbidden
              requestId: 123e4567-e89b-12d3-a456-426614174000
              timestamp: '2025-10-01T12:00:00Z'
    NotFound:
      description: The requested resource doesn’t exist.
      headers:
        X-RateLimit-Limit:
          $ref: '#/components/headers/X-RateLimit-Limit'
        X-RateLimit-Remaining:
          $ref: '#/components/headers/X-RateLimit-Remaining'
        X-RateLimit-Reset:
          $ref: '#/components/headers/X-RateLimit-Reset'
        X-RateLimit-Limit-Burst:
          $ref: '#/components/headers/X-RateLimit-Limit-Burst'
        X-RateLimit-Remaining-Burst:
          $ref: '#/components/headers/X-RateLimit-Remaining-Burst'
        X-RateLimit-Reset-Burst:
          $ref: '#/components/headers/X-RateLimit-Reset-Burst'
        RateLimit-Policy:
          $ref: '#/components/headers/RateLimit-Policy'
        RateLimit:
          $ref: '#/components/headers/RateLimit'
        Retry-After:
          $ref: '#/components/headers/Retry-After'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: RESOURCE_NOT_FOUND
              message: The requested resource was not found.
              documentationUrl: https://developer.folk.app/api-reference/errors#not-found
              requestId: 123e4567-e89b-12d3-a456-426614174000
              timestamp: '2025-10-01T12:00:00Z'
    Conflict:
      description: >-
        A request with the same `Idempotency-Key` is still being processed, or
        the resource is in a state that does not allow the operation.
      headers:
        X-RateLimit-Limit:
          $ref: '#/components/headers/X-RateLimit-Limit'
        X-RateLimit-Remaining:
          $ref: '#/components/headers/X-RateLimit-Remaining'
        X-RateLimit-Reset:
          $ref: '#/components/headers/X-RateLimit-Reset'
        X-RateLimit-Limit-Burst:
          $ref: '#/components/headers/X-RateLimit-Limit-Burst'
        X-RateLimit-Remaining-Burst:
          $ref: '#/components/headers/X-RateLimit-Remaining-Burst'
        X-RateLimit-Reset-Burst:
          $ref: '#/components/headers/X-RateLimit-Reset-Burst'
        RateLimit-Policy:
          $ref: '#/components/headers/RateLimit-Policy'
        RateLimit:
          $ref: '#/components/headers/RateLimit'
        Retry-After:
          schema:
            type: integer
            example: 5
          description: >-
            When the conflict resolves on its own, the number of seconds to wait
            before retrying.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: IDEMPOTENCY_REQUEST_IN_PROGRESS
              message: >-
                A request with the same Idempotency-Key is still being
                processed. Retry once it has completed.
              documentationUrl: https://developer.folk.app/api-reference/idempotency#errors
              requestId: 123e4567-e89b-12d3-a456-426614174000
              timestamp: '2025-10-01T12:00:00Z'
    UnprocessableEntity:
      description: >-
        The request was unacceptable, often due to missing or invalid
        parameters.
      headers:
        X-RateLimit-Limit:
          $ref: '#/components/headers/X-RateLimit-Limit'
        X-RateLimit-Remaining:
          $ref: '#/components/headers/X-RateLimit-Remaining'
        X-RateLimit-Reset:
          $ref: '#/components/headers/X-RateLimit-Reset'
        X-RateLimit-Limit-Burst:
          $ref: '#/components/headers/X-RateLimit-Limit-Burst'
        X-RateLimit-Remaining-Burst:
          $ref: '#/components/headers/X-RateLimit-Remaining-Burst'
        X-RateLimit-Reset-Burst:
          $ref: '#/components/headers/X-RateLimit-Reset-Burst'
        RateLimit-Policy:
          $ref: '#/components/headers/RateLimit-Policy'
        RateLimit:
          $ref: '#/components/headers/RateLimit'
        Retry-After:
          $ref: '#/components/headers/Retry-After'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: UNPROCESSABLE_ENTITY
              message: Invalid query parameters
              documentationUrl: >-
                https://developer.folk.app/api-reference/errors#unprocessable-entity
              details:
                issues:
                  - code: too_small
                    minimum: 1
                    type: number
                    inclusive: true
                    exact: false
                    message: Number must be greater than or equal to 1
                    path:
                      - limit
              requestId: 123e4567-e89b-12d3-a456-426614174000
              timestamp: '2025-10-01T12:00:00Z'
    TooManyRequests:
      description: >-
        Too many requests hit the API too quickly. We recommend an exponential
        backoff of your requests.
      headers:
        X-RateLimit-Limit:
          $ref: '#/components/headers/X-RateLimit-Limit'
        X-RateLimit-Remaining:
          $ref: '#/components/headers/X-RateLimit-Remaining'
        X-RateLimit-Reset:
          $ref: '#/components/headers/X-RateLimit-Reset'
        X-RateLimit-Limit-Burst:
          $ref: '#/components/headers/X-RateLimit-Limit-Burst'
        X-RateLimit-Remaining-Burst:
          $ref: '#/components/headers/X-RateLimit-Remaining-Burst'
        X-RateLimit-Reset-Burst:
          $ref: '#/components/headers/X-RateLimit-Reset-Burst'
        RateLimit-Policy:
          $ref: '#/components/headers/RateLimit-Policy'
        RateLimit:
          $ref: '#/components/headers/RateLimit'
        Retry-After:
          $ref: '#/components/headers/Retry-After'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/RateLimitError'
          example:
            error:
              code: TOO_MANY_REQUESTS
              message: You have exceeded your rate limit.
              documentationUrl: https://developer.folk.app/api-reference/errors#rate-limiting
              requestId: 123e4567-e89b-12d3-a456-426614174000
              timestamp: '2025-10-01T12:00:00Z'
              details:
                policy: burst
                limit: 20
                remaining: 0
                windowSeconds: 2
                retryAfter: '2025-10-01T12:00:02.000Z'
                policies:
                  - policy: default
                    limit: 600
                    remaining: 412
                    windowSeconds: 60
                    retryAfter: '2025-10-01T12:01:00.000Z'
                  - policy: burst
                    limit: 20
                    remaining: 0
                    windowSeconds: 2
                    retryAfter: '2025-10-01T12:00:02.000Z'
    InternalServerError:
      description: Something went wrong on our end.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: INTERNAL_SERVER_ERROR
              message: An internal server error occurred.
              documentationUrl: >-
                https://developer.folk.app/api-reference/errors#internal-server-error
              requestId: 123e4567-e89b-12d3-a456-426614174000
              timestamp: '2025-10-01T12:00:00Z'
    ServiceUnavailable:
      description: The server is overloaded or down for maintenance.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: SERVICE_UNAVAILABLE
              message: The service is currently unavailable.
              documentationUrl: >-
                https://developer.folk.app/api-reference/errors#service-unavailable
              requestId: 123e4567-e89b-12d3-a456-426614174000
              timestamp: '2025-10-01T12:00:00Z'
  securitySchemes:
    bearerApiKeyAuth:
      type: http
      scheme: bearer
      description: API key for authentication

````

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