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

# Create a postcard

> Creates a postcard in the API key's mode. A `pj_live_` key places a real order and uses one credit. A `pj_test_` key creates a free test postcard that is never written or mailed.

With `"draft": true` it saves a free draft instead: every field is optional, no credit is used, and the draft doesn't count toward the daily limit. You can have up to 100 open drafts in each mode. Order the draft with `POST /api/postcards/{id}/submit`.

Send a unique `Idempotency-Key` header with every new postcard. Requires the `postcards:write` ability.




## OpenAPI

````yaml /en/openapi.yaml post /api/postcards
openapi: 3.1.0
info:
  title: Paperjoy API
  version: '2026-10-19'
  description: >-
    Create, preview, and track real handwritten postcards. The API key decides
    whether a request runs in test or live mode.
  termsOfService: https://paperjoy.co/regulamin
  license:
    name: Proprietary
    url: https://paperjoy.co/regulamin
servers:
  - url: https://paperjoy.co
security:
  - bearerAuth: []
tags:
  - name: Account
    description: The authenticated account and its credit balance.
  - name: Postcards
    description: Create, preview, list, and retrieve postcards.
  - name: Signatures
    description: Custom handwritten signatures available to your organization.
paths:
  /api/postcards:
    post:
      tags:
        - Postcards
      summary: Create a postcard
      description: >
        Creates a postcard in the API key's mode. A `pj_live_` key places a real
        order and uses one credit. A `pj_test_` key creates a free test postcard
        that is never written or mailed.


        With `"draft": true` it saves a free draft instead: every field is
        optional, no credit is used, and the draft doesn't count toward the
        daily limit. You can have up to 100 open drafts in each mode. Order the
        draft with `POST /api/postcards/{id}/submit`.


        Send a unique `Idempotency-Key` header with every new postcard. Requires
        the `postcards:write` ability.
      operationId: createPostcard
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          description: >-
            A unique key for this postcard, such as a UUID. Paperjoy remembers
            keys for 7 days. Retrying with the same key and the same body
            returns the original response without creating another postcard.
          schema:
            type: string
            maxLength: 255
          example: 4f1c2a9e-6b0d-4d7e-9a51-3c8e2f7b1d20
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreatePostcardRequest'
            examples:
              typed_signature:
                summary: Typed signature
                value:
                  address:
                    line_1: ul. Marszałkowska 10
                    line_2: m. 4
                    postal_code: 00-001
                    country: PL
                    city: Warszawa
                  recipient:
                    prefix: Pani
                    first_name: Anna
                    last_name: Kowalska
                    company_name: null
                  content: >-
                    Dear Anna,

                    thank you for your first order! We hope the flowers brought
                    you a lot of joy.
                  signature: Marta from the Linden Florist
                  font_id: font-1
                  mistake: false
              custom_signature:
                summary: Custom signature
                value:
                  address:
                    line_1: ul. Długa 5
                    postal_code: 80-001
                    country: PL
                    city: Gdańsk
                  recipient:
                    company_name: Studio Forma
                  content: >-
                    Thank you for the project. We really enjoyed working with
                    your whole team.
                  signature_id: sig_ZeXOkSQjTp
                  font_id: font-2
              draft:
                summary: Draft
                value:
                  draft: true
                  recipient:
                    first_name: Anna
                  content: |-
                    Dear Anna,
                    thank you for your first order!
      responses:
        '201':
          description: The postcard was created.
          headers:
            Idempotency-Relayed:
              description: >-
                Present when this is a replay of an earlier response for the
                same `Idempotency-Key`. Contains the key.
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PostcardResponse'
              example:
                data:
                  id: pc_MXP7a4Ni0c
                  test_mode: true
                  address:
                    line_1: ul. Marszałkowska 10
                    line_2: m. 4
                    postal_code: 00-001
                    country: PL
                    city: Warszawa
                  recipient:
                    prefix: Pani
                    first_name: Anna
                    last_name: Kowalska
                    company_name: null
                  content: >-
                    Dear Anna,

                    thank you for your first order! We hope the flowers brought
                    you a lot of joy.
                  signature: Marta from the Linden Florist
                  signature_id: null
                  font_id: font-1
                  mistake: false
                  status: new
                  submitted_at: '2026-10-17T14:31:48+00:00'
                  sent_at: null
                  created_at: '2026-10-17T14:31:48+00:00'
                  updated_at: '2026-10-17T14:31:48+00:00'
        '400':
          $ref: '#/components/responses/MissingIdempotencyKey'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '402':
          $ref: '#/components/responses/PaymentRequired'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          $ref: '#/components/responses/IdempotencyConflict'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/TooManyRequests'
components:
  schemas:
    CreatePostcardRequest:
      type: object
      description: >-
        `address`, `recipient`, `content`, and `font_id` are required unless you
        send `draft` set to `true`.
      required:
        - address
        - recipient
        - content
        - font_id
      properties:
        address:
          $ref: '#/components/schemas/Address'
        recipient:
          $ref: '#/components/schemas/Recipient'
        content:
          $ref: '#/components/schemas/Content'
        signature:
          $ref: '#/components/schemas/TypedSignature'
        signature_id:
          $ref: '#/components/schemas/SignatureIdInput'
        font_id:
          $ref: '#/components/schemas/FontId'
        mistake:
          $ref: '#/components/schemas/Mistake'
        draft:
          type: boolean
          default: false
          description: >-
            `true` saves a free draft instead of ordering. The other fields are
            then optional.
    PostcardResponse:
      type: object
      required:
        - data
      properties:
        data:
          $ref: '#/components/schemas/Postcard'
    Address:
      type: object
      required:
        - line_1
        - postal_code
        - country
        - city
      properties:
        line_1:
          type: string
          maxLength: 255
          description: Street and building number.
          examples:
            - ul. Marszałkowska 10
        line_2:
          type:
            - string
            - 'null'
          maxLength: 255
          description: Apartment, floor, or other detail.
          examples:
            - m. 4
        postal_code:
          type: string
          pattern: ^\d{2}-\d{3}$
          examples:
            - 00-001
        country:
          type: string
          enum:
            - PL
        city:
          type: string
          maxLength: 255
          examples:
            - Warszawa
    Recipient:
      type: object
      description: Send `first_name`, `company_name`, or both.
      properties:
        prefix:
          type:
            - string
            - 'null'
          maxLength: 30
          examples:
            - Pani
        first_name:
          type:
            - string
            - 'null'
          maxLength: 255
        last_name:
          type:
            - string
            - 'null'
          maxLength: 255
        company_name:
          type:
            - string
            - 'null'
          maxLength: 255
    Content:
      type: string
      maxLength: 300
      description: >-
        The handwritten message. Line breaks (`\n`) and blank lines are kept.
        The text must fit on the card; see the `card_fit` validation error.
    TypedSignature:
      type:
        - string
        - 'null'
      maxLength: 50
      description: >-
        A sign-off written on one line at the bottom of the card. Do not send
        together with `signature_id`.
    SignatureIdInput:
      type:
        - string
        - 'null'
      description: >-
        An active custom signature ID from `GET /api/signatures`. Requires a
        plan with custom signatures. Do not send together with `signature`.
      examples:
        - sig_ZeXOkSQjTp
    FontId:
      type: string
      enum:
        - font-1
        - font-2
      description: >-
        `font-1` is clear, rounded handwriting. `font-2` is a faster, joined-up
        cursive.
    Mistake:
      type: boolean
      default: false
      description: >-
        Cross out one word and write it again, like a real person would. The
        same message always gets the same correction.
    Postcard:
      type: object
      required:
        - id
        - test_mode
        - recipient
        - signature
        - signature_id
        - mistake
        - status
        - submitted_at
        - sent_at
        - created_at
        - updated_at
      properties:
        id:
          type: string
          examples:
            - pc_MXP7a4Ni0c
        test_mode:
          type: boolean
          description: >-
            `true` for a test postcard. Test postcards are free and are never
            written or mailed.
        address:
          description: The delivery address. Can be `null` only in a draft.
          oneOf:
            - $ref: '#/components/schemas/Address'
            - type: 'null'
        recipient:
          oneOf:
            - $ref: '#/components/schemas/Recipient'
            - type: 'null'
        content:
          type:
            - string
            - 'null'
          maxLength: 300
          description: The message. Can be `null` only in a draft.
        signature:
          type:
            - string
            - 'null'
          maxLength: 50
          description: >-
            The typed signature, or `null` when the postcard uses a custom
            signature.
        signature_id:
          type:
            - string
            - 'null'
          description: The custom signature used on the postcard, or `null`.
          examples:
            - sig_ZeXOkSQjTp
        font_id:
          description: The handwriting. Can be `null` only in a draft.
          oneOf:
            - $ref: '#/components/schemas/FontId'
            - type: 'null'
        mistake:
          type: boolean
          description: >-
            Whether one word is crossed out and rewritten to look naturally
            handwritten.
        status:
          $ref: '#/components/schemas/PostcardStatus'
        submitted_at:
          type:
            - string
            - 'null'
          format: date-time
          description: When the postcard was ordered. `null` while it's a draft.
        sent_at:
          type:
            - string
            - 'null'
          format: date-time
          description: When the postcard was mailed. `null` until the status is `sent`.
        created_at:
          type:
            - string
            - 'null'
          format: date-time
        updated_at:
          type:
            - string
            - 'null'
          format: date-time
    Error:
      type: object
      required:
        - message
      properties:
        message:
          type: string
    ValidationError:
      type: object
      required:
        - message
        - errors
      properties:
        message:
          type: string
        errors:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
    PostcardStatus:
      type: string
      description: >-
        Where the postcard is in production. Treat unknown values as "in
        progress".
      enum:
        - draft
        - new
        - queued
        - rejected
        - pair_claimed
        - in_progress
        - pair_completed
        - sent
  responses:
    MissingIdempotencyKey:
      description: The `Idempotency-Key` header is missing.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            message: Idempotency-Key header is required to create or submit a postcard.
    Unauthorized:
      description: The API key is missing, invalid, revoked, or expired.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            message: Unauthenticated.
    PaymentRequired:
      description: The account has less than one credit. Only live mode checks the balance.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            message: You need at least 1 credit to create a postcard.
    Forbidden:
      description: >-
        The API key lacks the required ability, or the resource belongs to
        someone else.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            message: This action is unauthorized.
    IdempotencyConflict:
      description: The `Idempotency-Key` was already used with a different request body.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            message: >-
              Idempotency-Key has already been used with a different postcard
              creation payload.
    ValidationError:
      description: >-
        A field is invalid, the text does not fit on the card or envelope, or
        the `Idempotency-Key` is longer than 255 characters.
      content:
        application/json:
          schema:
            anyOf:
              - $ref: '#/components/schemas/ValidationError'
              - $ref: '#/components/schemas/Error'
          examples:
            field:
              summary: Invalid field
              value:
                message: The selected font id is invalid.
                errors:
                  font_id:
                    - The selected font id is invalid.
            card_fit:
              summary: Message does not fit on the card
              value:
                message: >-
                  The content does not fit on the postcard. Shorten it or remove
                  blank lines.
                errors:
                  content:
                    - >-
                      The content does not fit on the postcard. Shorten it or
                      remove blank lines.
            envelope_fit:
              summary: Address does not fit on the envelope
              value:
                message: The sender or recipient address does not fit on the envelope.
                errors:
                  address:
                    - >-
                      The sender or recipient address does not fit on the
                      envelope.
            draft_limit:
              summary: Too many open drafts
              value:
                message: >-
                  You already have 100 open drafts. Submit or delete some of
                  them before saving another draft.
                errors:
                  draft:
                    - >-
                      You already have 100 open drafts. Submit or delete some of
                      them before saving another draft.
            signature_unavailable:
              summary: Custom signature unavailable
              value:
                message: >-
                  The selected signature is unavailable or is not active for
                  your plan.
                errors:
                  signature_id:
                    - >-
                      The selected signature is unavailable or is not active for
                      your plan.
    TooManyRequests:
      description: A rate limit was exceeded. Wait before retrying.
      headers:
        Retry-After:
          description: Seconds to wait before retrying.
          schema:
            type: integer
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            message: Too Many Attempts.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        A Paperjoy API key. Keys starting with `pj_test_` use test mode; keys
        starting with `pj_live_` use live mode.

````

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