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

# Order placed

> Report an order placed in your store.

This is an **idempotent upsert** keyed on `order_id`:
the first call for an `order_id` creates the order and returns `201 Created`;
subsequent calls with the same `order_id` update it and return `200 OK`.
The order carries the full current state each time —
omitted optional fields keep their previously stored value.

The order is associated to a contact by `email` (or, when no email is sent, by `phone`),
creating the contact if needed.

`accepts_email_marketing` and  `accepts_sms_marketing`  drive the contact's marketing consent —
see the field descriptions for the exact semantics.

Optionally send the `X-Privy-Integration-Token` header to tie the order to a specific
Custom Integration (see the header parameter below).

**Required scope:** `orders_write`


<Note>
  To trigger Privy **Flows** (such as Order Placed and Order Received) from orders sent to this
  endpoint, you must first connect a [Custom Integration](/docs/learn/integrations/custom-integration)
  for your store. See [Flows currently available](/docs/learn/integrations/custom-integration#flows-currently-available)
  for the supported triggers and conditions.
</Note>


## OpenAPI

````yaml openapi/privy-api.yaml POST /orders/placed
openapi: 3.1.0
info:
  title: Privy API
  version: '1.0'
  description: |
    The Privy API lets you programmatically manage your contact list.
    Create, update, unsubscribe, and remove contacts — or retrieve your
    full contact list with filtering and pagination.
servers:
  - url: https://api.privy.com/v1
    description: Production
security:
  - bearerAuth: []
tags:
  - name: Account
    description: Retrieve information about the authenticated Privy account.
  - name: Contacts
    description: Manage your contact list.
  - name: Orders
    description: Report orders placed in your store.
  - name: Events
    description: Ingest custom events to trigger Flows and other automations.
paths:
  /orders/placed:
    post:
      tags:
        - Orders
      summary: Order placed
      description: >
        Report an order placed in your store.


        This is an **idempotent upsert** keyed on `order_id`:

        the first call for an `order_id` creates the order and returns `201
        Created`;

        subsequent calls with the same `order_id` update it and return `200 OK`.

        The order carries the full current state each time —

        omitted optional fields keep their previously stored value.


        The order is associated to a contact by `email` (or, when no email is
        sent, by `phone`),

        creating the contact if needed.


        `accepts_email_marketing` and  `accepts_sms_marketing`  drive the
        contact's marketing consent —

        see the field descriptions for the exact semantics.


        Optionally send the `X-Privy-Integration-Token` header to tie the order
        to a specific

        Custom Integration (see the header parameter below).


        **Required scope:** `orders_write`
      operationId: placeOrder
      parameters:
        - name: X-Privy-Integration-Token
          in: header
          required: false
          description: >
            Optional. The integration token of a Custom Integration, sent **in
            addition to**

            the `Authorization: Bearer` token, to tie the order to that specific

            integration. Find it in your Privy dashboard under

            **Settings → Integrations Hub → Connected**, or generate a new one
            in the

            same **Integrations Hub** section under **Custom Integration**.


            When omitted and the business has exactly one Custom Integration,
            the order

            is auto-tied to it; otherwise no integration is attributed. If the
            value

            doesn't match an active Custom Integration for your business, the
            request

            returns `422`. This token only narrows attribution within the
            business

            already established by the bearer token — it is not a standalone
            credential.
          schema:
            type: string
          example: prv_a1b2c3d4e5f6g7h8
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PlaceOrderRequest'
            example:
              order_id: 1001
              email: buyer@example.com
              phone: '+12025550123'
              customer_id: ext-42
              subtotal: 90
              discounts:
                - code: SAVE10
                  amount: 10
              tax_lines:
                - title: VAT
                  amount: 5
              total: 95
              currency: USD
              total_items: 2
              financial_status: paid
              fulfillment_status: fulfilled
              shipment_status: delivered
              line_items:
                - sku: SKU-1
                  quantity: 2
                  price: 45
              billing_address:
                first_name: Janet
                last_name: Biller
                city: Boston
                state_code: MA
                country_code: US
                postal_code: '02118'
              shipping_address:
                first_name: Jane
                last_name: Shopper
                city: Boston
                state_code: MA
                country_code: US
                postal_code: '02118'
              accepts_email_marketing: true
              accepts_sms_marketing: true
              order_date: '2026-06-01T12:00:00Z'
      responses:
        '200':
          description: Existing order updated.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/Order'
              example:
                data:
                  order_id: 1001
                  source: api
                  email: buyer@example.com
                  phone: '+12025550123'
                  total_amount: '95.00'
                  currency_code: USD
                  placed_at: '2026-06-01T12:00:00Z'
                  financial_status: paid
                  fulfillment_status: fulfilled
                  shipment_status: delivered
                  customer_id: ext-42
                  total_items: 2
                  accepts_email_marketing: true
                  accepts_sms_marketing: true
                  created_at: '2026-06-01T12:00:05Z'
                  updated_at: '2026-06-02T09:14:00Z'
        '201':
          description: Order created.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/Order'
              example:
                data:
                  order_id: 1001
                  source: api
                  email: buyer@example.com
                  phone: '+12025550123'
                  total_amount: '95.00'
                  currency_code: USD
                  placed_at: '2026-06-01T12:00:00Z'
                  financial_status: paid
                  fulfillment_status: fulfilled
                  shipment_status: delivered
                  customer_id: ext-42
                  total_items: 2
                  accepts_email_marketing: true
                  accepts_sms_marketing: true
                  integration:
                    store_name: My Store
                    store_url: https://mystore.example.com
                  created_at: '2026-06-01T12:00:05Z'
                  updated_at: '2026-06-01T12:00:05Z'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/InsufficientScope'
        '422':
          $ref: '#/components/responses/ValidationFailed'
        '429':
          $ref: '#/components/responses/RateLimited'
      security:
        - bearerAuth: []
components:
  schemas:
    PlaceOrderRequest:
      type: object
      description: >
        `order_id`, `total`, `currency`, and `order_date` are required on every
        call,

        plus at least one of `email` or `phone`. All other fields are optional;

        on an update, omitted optional fields keep their previously  stored
        value.
      required:
        - order_id
        - total
        - currency
        - order_date
      properties:
        order_id:
          type: integer
          format: int64
          description: >
            Your unique identifier for the order. Must be a positive integer (a
            digits-only string is also accepted).

            This is the idempotency key: the first call for an `order_id`
            creates the order, subsequent calls update it.
          example: 1001
        email:
          type: string
          format: email
          description: |
            Buyer's email. Used to find or create the associated contact.
            At least one of `email` or `phone` is required.
          example: buyer@example.com
        phone:
          type: string
          description: >
            Buyer's phone number. Loosely formatted input is accepted and
            normalized to E.164.

            Required when `accepts_sms_marketing` is `true`.
          example: '+12025550123'
        customer_id:
          type: string
          description: Your external identifier for the customer.
          example: ext-42
        subtotal:
          type: number
          description: Order subtotal before tax, shipping, and discounts.
          example: 90
        discounts:
          type: array
          description: Discounts applied to the order.
          items:
            $ref: '#/components/schemas/Discount'
        tax_lines:
          type: array
          description: Tax lines applied to the order.
          items:
            $ref: '#/components/schemas/TaxLine'
        total:
          type: number
          description: Order grand total. Required.
          example: 95
        currency:
          type: string
          description: ISO 4217 three-letter currency code. Required.
          example: USD
        total_items:
          type: integer
          description: Total number of items in the order.
          example: 2
        financial_status:
          type: string
          enum:
            - authorized
            - expired
            - paid
            - partially_paid
            - partially_refunded
            - pending
            - refunded
            - voided
          description: |
            Payment status of the order.
          example: paid
        fulfillment_status:
          type: string
          enum:
            - fulfilled
            - in_progress
            - on_hold
            - open
            - partially_fulfilled
            - pending
            - pending_fulfillment
            - request_declined
            - restocked
            - scheduled
            - unfulfilled
          description: >
            The order's overall fulfillment state (mirrors Shopify's
            OrderDisplayFulfillmentStatus).

            Stored on the order but does not affect delivery-based flow triggers
            — use `shipment_status` for that.
          example: fulfilled
        shipment_status:
          type: string
          enum:
            - attempted_delivery
            - carrier_picked_up
            - confirmed
            - delayed
            - delivered
            - failure
            - in_transit
            - label_printed
            - label_purchased
            - out_for_delivery
            - picked_up
            - ready_for_pickup
          description: >
            Carrier delivery status of the shipment (mirrors Shopify's
            FulfillmentEventStatus).

            Setting this to `delivered` triggers any "Order Received" flows for
            the customer.
          example: delivered
        line_items:
          type: array
          description: The products purchased.
          items:
            $ref: '#/components/schemas/LineItem'
        billing_address:
          $ref: '#/components/schemas/Address'
        shipping_address:
          $ref: '#/components/schemas/Address'
        accepts_email_marketing:
          type: boolean
          description: >
            Whether the buyer opted into email marketing. Subscribes the contact
            on signup;

            never unsubscribes an existing contact.
          example: true
        accepts_sms_marketing:
          type: boolean
          description: |
            Whether the buyer opted into SMS marketing. Requires `phone`.
            Records an SMS opt-in for newly created contacts only;
            existing contacts' SMS consent is left untouched.
          example: true
        order_date:
          type: string
          format: date-time
          description: >
            ISO 8601 date-time the order was placed. Required. Expected to be in
            UTC

            (zero offset) — end the timestamp with `Z` (e.g.
            `2026-06-01T12:00:00Z`).
          example: '2026-06-01T12:00:00Z'
        initial_sync:
          type: boolean
          default: false
          description: >
            Set to `true` for bulk historical imports. Suppresses real-time side
            effects

            (Flows and other automations, attribution, and order-stat  updates)

            while still recording the order and associating the contact.
          example: false
    Order:
      type: object
      description: |
        An order as persisted. Echoes back the fields you sent
        (column-backed fields normalized, the rest verbatim).
        Empty values are omitted from the response.
      properties:
        order_id:
          type: integer
          format: int64
          description: >-
            Your order identifier, echoed back. The only public identifier for
            the order.
          example: 1001
        source:
          type: string
          example: api
        email:
          type: string
          format: email
          example: buyer@example.com
        phone:
          type: string
          description: Normalized to E.164.
          example: '+12025550123'
        total_amount:
          type: string
          description: Order grand total, as a decimal string.
          example: '95.00'
        currency_code:
          type: string
          example: USD
        placed_at:
          type: string
          format: date-time
          example: '2026-06-01T12:00:00Z'
        financial_status:
          type: string
          example: paid
        fulfillment_status:
          type: string
          example: fulfilled
        shipment_status:
          type: string
          example: in_transit
        customer_id:
          type: string
          example: ext-42
        subtotal:
          type: number
          example: 90
        discounts:
          type: array
          items:
            $ref: '#/components/schemas/Discount'
        tax_lines:
          type: array
          items:
            $ref: '#/components/schemas/TaxLine'
        total_items:
          type: integer
          example: 2
        line_items:
          type: array
          items:
            $ref: '#/components/schemas/LineItem'
        billing_address:
          $ref: '#/components/schemas/Address'
        shipping_address:
          $ref: '#/components/schemas/Address'
        accepts_email_marketing:
          type: boolean
          example: true
        accepts_sms_marketing:
          type: boolean
          example: true
        integration:
          $ref: '#/components/schemas/OrderIntegration'
        created_at:
          type: string
          format: date-time
          example: '2026-06-01T12:00:05Z'
        updated_at:
          type: string
          format: date-time
          example: '2026-06-01T12:00:05Z'
    Discount:
      type: object
      description: A discount applied to the order. Stored and echoed back verbatim.
      additionalProperties: true
      properties:
        code:
          type: string
          example: SAVE10
        amount:
          type: number
          example: 10
    TaxLine:
      type: object
      description: A tax line on the order. Stored and echoed back verbatim.
      additionalProperties: true
      properties:
        title:
          type: string
          example: VAT
        amount:
          type: number
          example: 5
    LineItem:
      type: object
      description: A product line on the order. Stored and echoed back verbatim.
      additionalProperties: true
      properties:
        product_id:
          type: number
          example: 1001
        variant_id:
          type: number
          example: 1002
        sku:
          type: string
          example: SKU-1
        title:
          type: string
          example: Sample Product
        quantity:
          type: integer
          example: 2
        price:
          type: number
          example: 45
    Address:
      type: object
      description: |
        A billing or shipping address. Stored and echoed back verbatim.
        When a new contact is created, its name is taken from the address —
        shipping first, billing as fallback — using `first_name`/`last_name`,
        or a single `name` field split on whitespace.
      additionalProperties: true
      properties:
        first_name:
          type: string
          example: Jane
        last_name:
          type: string
          example: Shopper
        name:
          type: string
          description: Full name; used when `first_name`/`last_name` are absent.
          example: Jane Shopper
        address1:
          type: string
          example: 123 Main St
        address2:
          type: string
          example: Apt 101
        city:
          type: string
          example: Boston
        state_code:
          type: string
          example: MA
        country_code:
          type: string
          example: US
        postal_code:
          type: string
          example: '02118'
    OrderIntegration:
      type: object
      description: >
        The Custom Integration the order is tied to. Present only when the order
        was attributed to an integration

        (via the `X-Privy-Integration-Token` header or auto-tie).
      properties:
        store_name:
          type: string
          example: My Store
        store_url:
          type: string
          example: https://mystore.example.com
    ErrorResponse:
      type: object
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              enum:
                - invalid_client
                - invalid_scope
                - unauthorized
                - insufficient_scope
                - not_found
                - conflict
                - validation_failed
                - rate_limited
              example: validation_failed
            message:
              type: string
              example: One or more fields are invalid
            details:
              type: array
              items:
                type: object
                properties:
                  field:
                    type: string
                    example: email
                  message:
                    type: string
                    example: is required
  responses:
    Unauthorized:
      description: Missing or invalid bearer token.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: unauthorized
              message: Bearer token is missing or invalid
    InsufficientScope:
      description: Token lacks the required scope for this endpoint.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: insufficient_scope
              message: Token does not have the required scope
    ValidationFailed:
      description: One or more fields failed validation.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: validation_failed
              message: One or more fields are invalid
              details:
                - field: email
                  message: is required
    RateLimited:
      description: Rate limit exceeded. Retry after the specified time.
      headers:
        Retry-After:
          description: Seconds to wait before retrying.
          schema:
            type: integer
          example: 42
        X-RateLimit-Limit-Minute:
          description: Maximum requests allowed per minute.
          schema:
            type: integer
          example: 60
        X-RateLimit-Remaining-Minute:
          description: Requests remaining in the current minute window.
          schema:
            type: integer
          example: 0
        X-RateLimit-Reset-Minute:
          description: Unix timestamp when the minute window resets.
          schema:
            type: integer
          example: 1711929600
        X-RateLimit-Limit-Day:
          description: Maximum requests allowed per day.
          schema:
            type: integer
          example: 10000
        X-RateLimit-Remaining-Day:
          description: Requests remaining in the current day window.
          schema:
            type: integer
          example: 9500
        X-RateLimit-Reset-Day:
          description: Unix timestamp when the day window resets.
          schema:
            type: integer
          example: 1712016000
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: rate_limited
              message: Rate limit exceeded
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API token or OAuth access token
      description: >
        Send either an API token or an OAuth access token as

        `Authorization: Bearer <token>`. See the Authentication page for
        details.

````