View Categories

Order Create

7 min read

The Order Create API allows you to send bulk cart paid notifications to Releva. Any cart paid notifications submitted through this API will be live within 1 minute of receiving a successful response.

Do I need to call it? #

You need to call this in order to fully use Releva. Without implementing this, store revenue, attribution tracking, and order-based segmentation will not function.

Endpoint #

URL POST https://releva.ai/api/v0/carts
Authentication Authorization: Bearer <secretKey> โ€” the secret key of the domain the order belongs to.
Content type application/json
Max request body 800 KB. Send large order backfills in several requests.

Request Parameters #

You may perform requests to the API using the following curl equivalent:

curl -H 'Content-Type: application/json' -H 'Authorization: Bearer <secretKey>' -XPOST https://releva.ai/api/v0/carts -d'{
  "carts": [
    {
      "orderId": "orderId1",
      "cartPaid": true,
      "email": "user@email.com",
      "phoneNumber": "+359888123456",
      "timestamp": "2026-03-27T14:05:00.000Z",
      "products": [
        {
          "id": "1",
          "variantId": "1001",
          "price": 10,
          "currency": "BGN",
          "quantity": 2,
          "custom": {
            "string": [
              {"key": "color", "values": ["red"]}
            ],
            "numeric": [
              {"key": "size", "values": [18]}
            ]
          }
        }
      ],
      "custom": {
        "string": [
          {"key": "city", "values": ["San Francisco"]}
        ],
        "numeric": [
          {"key": "rewardPoints", "values": [18]}
        ]
      }
    }
  ]
}'

Note: timestamp must be a full ISO-8601 date-time with a timezone offset โ€” 2026-03-27T14:05:00.000Z, 2026-03-27T14:05:00Z or 2026-03-27T14:05:00+0200. A date on its own, or a date-time without an offset, is rejected with HTTP 400.

The id of each product must be the same id you send to the Product Create / Update API. Releva looks the line item up in your catalog and copies the product’s name, categories and custom fields onto the order โ€” that is what makes segments such as โ€œbought in category X in the last 30 daysโ€ work. A line item whose id matches nothing in the catalog is still counted towards revenue, but carries no product attributes.

Identifying the shopper #

Every cart needs at least one of email, phoneNumber or profileId โ€” this is how the order is attached to a profile. Send as many of them as you have; Releva resolves them to a single profile.

email / phoneNumber The shopper’s contact details as they appear on the order. Phone numbers should be in international format (+ followed by digits).
profileId Your own customer id, if you have one. Use it consistently across the Profile APIs and this one, and orders will be attached to the right profile even for shoppers who change their email address.
mergeProfileIds Ids of profiles to fold into this one. On a guest checkout, pass the anonymous id the shopper browsed under so their pre-purchase browsing history and campaign attribution follow them onto the identified profile.

Carts that carry none of the three are skipped. In a batch, the remaining carts are still processed; if no cart in the request carries an identifier, the whole request is answered with HTTP 400.

Improving ad platform attribution #

Orders reported from your backend carry none of the browser context the ad platforms use to match a purchase to an ad click, because the request comes from your server and not from the shopper’s device. Forward what you have and the Purchase events Releva sends to Meta, Google and TikTok get materially better match quality:

curl -H 'Content-Type: application/json' -H 'Authorization: Bearer <secretKey>' -XPOST https://releva.ai/api/v0/carts -d'{
  "carts": [
    {
      "orderId": "orderId1",
      "cartPaid": true,
      "email": "user@email.com",
      "timestamp": "2026-03-27T14:05:00.000Z",
      "ip": "78.90.12.34",
      "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1",
      "url": "https://my-awesome-shop.com/checkout/thank-you",
      "address": {
        "city": "Sofia",
        "region": "23",
        "postalCode": "1000",
        "country": "BG"
      },
      "eventId": "b7f3c1e2-4a5d-4f0a-9c3e-1d2b3a4c5d6e",
      "products": [
        {"id": "1", "price": 10, "currency": "BGN", "quantity": 2}
      ]
    }
  ]
}'

Send the shopper’s values, not your server’s: ip and userAgent are the ones the shopper was browsing with (most platforms let you stash them on the cart or session during checkout), and url is the storefront page the order was completed on. Omit any of them you cannot supply โ€” no value at all is better than your datacenter’s IP address or your HTTP client’s user agent, both of which would be matched as if they were the customer’s.

One order, one record #

An orderId is recorded once per shop. If the same order reaches Releva twice โ€” a webhook redelivery, a retry after a timeout, a backfill that overlaps live traffic โ€” only the first one counts, so repeating a call can never double-count revenue. The flip side is that a mistake cannot be corrected by re-sending the same orderId; contact support if an order needs changing.

Keep orderId under 255 characters, and use the order identifier your own systems use โ€” it is what support, refunds and order-level reports match on.

Orders are held for about 30 seconds before processing, so that a matching browser event from the same checkout can be merged with them.

The cart Object #

Each entry in carts is an object with the following properties. Any property that is not listed below is rejected with HTTP 400.

Field Type Description
carts[].orderId String A unique order ID that identifies the completed order once a cart has been checked out. Max 255 characters. An order ID is only ever recorded once per shop.
carts[].cartPaid Boolean Send true. This endpoint reports paid orders; a cart sent with false records no order, no revenue and no event. Use the JavaScript SDK (or the Cart Update API) for carts that have not been paid for.
carts[].email String (Optional) The email of the user who has placed the order. You need to pass an email, a phone number, or a profileId.
carts[].phoneNumber String (Optional) The phone number of the user who has placed the order. Phone numbers must start with โ€œ+โ€ followed by a sequence of numbers. Valid phone number: +49875345976. You need to pass an email, a phone number, or a profileId.
carts[].profileId String (Optional) Your own id for the customer who placed the order. You need to pass an email, a phone number, or a profileId.
carts[].mergeProfileIds Array[String] (Optional) Ids of other profiles to merge into this shopper’s profile โ€” typically the anonymous id a guest browsed under before checking out.
carts[].timestamp ISO-8601 String (Optional) The date and time when this visitor created their order. Must include the time and a timezone offset, e.g. 2026-03-27T14:05:00.000Z. We will use the current date and time if you don’t send this field.
carts[].custom Object (Optional) The custom fields associated with the cart, for example the reward points gained for this order, and/or the order address. See custom for details.
carts[].companyId String (Optional) The id of the company to associate this cart with.
carts[].acceptPrivacyPolicy Boolean (Optional) The consent of the user with our privacy policy. When true, the consent is recorded on the shopper’s profile.
carts[].ip String (Optional) The shopper’s IP address, forwarded from the storefront session. Used for ad platform match quality and geo. Max 45 characters. Do not send your server’s IP address.
carts[].userAgent String (Optional) The shopper’s browser user agent, forwarded from the storefront session. Max 1024 characters. Do not send your HTTP client’s user agent.
carts[].url Absolute URL String (Optional) The storefront URL the order was completed on. Max 2048 characters. Lets ad platforms record the purchase as a website conversion rather than an offline one.
carts[].address Object (Optional) The order’s postal address, used for advanced matching with the ad platforms.
carts[].address.city String (Optional) City. Max 128 characters.
carts[].address.region String (Optional) Region / state / province code, not the display name. Max 128 characters.
carts[].address.postalCode String (Optional) Postal code. Max 32 characters.
carts[].address.country String (Optional) Two-letter ISO-3166-1 alpha-2 country code, e.g. BG, not the display name. Max 32 characters.
carts[].eventId String (Optional) A deduplication id shared with your browser pixel for the same purchase, forwarded to the ad platforms as their event id so one purchase is not counted twice. Max 200 characters.
carts[].products[] Array[Object] A list of products in the cart. Required; may be empty for an order with no line items.
carts[].products[].id String (Optional) The id of the product in the cart. Use the same id you send to the Product Create / Update API, including the locale and market suffix if your catalog uses one.
carts[].products[].variantId String (Optional) The id of the purchased variant, when id identifies the product rather than the variant. Recorded on the order for variant-level reporting.
carts[].products[].price Float The unit price at which the product was purchased. Revenue is this price multiplied by quantity, summed over the line items.
carts[].products[].quantity Integer The units purchased.
carts[].products[].currency ISO-4217 String (Optional) The currency of the product. Omit it only when the price is already in your shop’s currency โ€” a price with no currency is not converted.
carts[].products[].custom Object (Optional) The custom fields associated with the product in the cart, for example the chosen size and color. See custom for details.

Response Format #

A successful response will return HTTP Status 202 with an empty response body ({}).

An error response will return a HTTP 4xx or 5xx status code and have the following structure:

{
  "message": "A description of the error and how to fix it, if it's a client error."
}
Status Meaning
202 Accepted. The orders will be live within a minute.
400 The request body failed validation, no cart carried an identifier, or the Authorization header is missing, malformed or does not match a known domain. message names the offending field.
402 The domain is disabled. Please reach out to support@releva.ai to enable it.
413 The request body is larger than 800 KB. Send the orders in smaller batches.