Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.dr.green/llms.txt

Use this file to discover all available pages before exploring further.

Carts

Endpoint reference: ✅ Verified live against production on 10 May 2026. Carts are per-client. Each client has at most one active cart. Adding items to a cart doesn’t reserve inventory — items are only committed when an order is placed via POST /dapp/orders.

Conceptual surprise: the API exposes “clients-with-carts”, not “carts directly”

⚠️ Read this before building cart UI. GET /dapp/carts returns a paginated list of clients, each with their clientCart[] and cartItems[] embedded. The top-level field is clients, not carts. This is a small but real footgun — your UI code expecting data.carts will silently render nothing.
If your store has a “carts in progress” view (for the holder, showing all customers who’ve started a cart), this endpoint feeds it. If you’re rendering a single customer’s cart, fetch GET /dapp/clients/{clientId} instead — clientCart[] is included in the detail response.

Endpoints

MethodPathAuthDescription
POST/dapp/cartsAPI-key + sigAdd items to a client’s cart (creates the cart if none exists)
GET/dapp/cartsAPI-key + sigList clients with carts in progress
DELETE/dapp/carts/{cartId}API-key + sigDelete a cart

POST /dapp/carts — add items

Adds one or more strain items to a client’s cart. Creates the cart on first call.

Request body

The shape is CreateCartItemsDto per the live OpenAPI spec — full schema not formally declared, but the working pattern is:
{
  "clientId": "2cbab026-9dc6-46fd-8580-77e3dfd2f086",
  "cartItems": [
    { "strainId": "c77dd198-ec9a-4ced-8105-937fde104424", "quantity": 5 },
    { "strainId": "<other-strain-id>", "quantity": 2 }
  ]
}
FieldTypeRequiredNotes
clientIdstring (UUID)Must belong to the calling holder
cartItemsarrayAt least one item
cartItems[].strainIdstring (UUID)From Strains
cartItems[].quantityintegerPositive integer (units of grams)

Canonical payload (for signing)

JSON.stringify(body) — compact, no whitespace. Send the same exact string as the request body.

Response

201 Created with the cart’s id.
{
  "success": true,
  "statusCode": 201,
  "message": "Success",
  "data": { "id": "<cart-uuid>" }
}

Idempotency

POST /dapp/carts is not idempotent server-side. Calling it twice with the same payload will add the items twice. If the customer hits the “Add to cart” button rapidly, debounce client-side. There’s no Idempotency-Key header support yet (see 04-errors.md § Idempotency).

Errors

StatusCauseFix
400 ["clientId must be a UUID", "cartItems should not be empty"]Validation failureValidate input client-side first
403 “Client does not belong to this holder”clientId is for another holder’s customerRe-fetch the holder’s client list and pick from there
404 “Strain not found”strainId was soft-deleted between catalogue fetch and addRefresh the catalogue, drop stale items

GET /dapp/carts — clients with carts

Returns a paginated list of clients who have an active cart, with the cart and items embedded.

Query parameters

NameTypeDefault
pageinteger1
limitinteger10
searchstring

Canonical payload

urlencode(query) if any present, else "{}".

Response shape (verified)

{
  "success": true,
  "statusCode": 200,
  "message": "Success",
  "data": {
    "clients": [
      {
        "id": "715b0db6-02e9-46b4-8b1a-eb6cac47f9d1",
        "firstName": "Ricardo",
        "lastName": "Capone",
        "email": "ricardo.capone@protonmail.ch",
        "shippings": [ { "countryCode": "ZAF", "currency": null } ],
        "clientCart": [
          {
            "id": "6712f17e-678e-419c-9790-27dff0de7ed2",
            "cartItems": [
              {
                "quantity": 5,
                "createdAt": "2026-05-08T11:46:12.738Z",
                "strain": { /* embedded strain summary */ }
              }
            ]
          }
        ]
      }
    ],
    "pageMetaDto": {
      "page": "1", "take": 10, "itemCount": 1,
      "pageCount": 1, "hasPreviousPage": false, "hasNextPage": false
    }
  }
}
🪲 clientCart is an array even though each client has at most one active cart. Take [0] and treat the rest defensively.
🪲 Cart items have no id in the embedded list — only quantity, createdAt, and the embedded strain. To remove a single item, you delete the whole cart and recreate. There’s no “remove item from cart” endpoint in the current API. 🔒

Worked example (Python)

def carts_in_progress(page=1, limit=10):
    query = {"page": str(page), "limit": str(limit)}
    payload = canonical_payload("GET", query=query)
    headers = auth_headers(API_KEY, SECRET_KEY, payload)
    url = f"https://api.drgreennft.com/api/v1/dapp/carts?{urlencode(query)}"
    r = httpx.get(url, headers=headers)
    r.raise_for_status()
    clients = r.json()["data"]["clients"]
    # Flatten to a "cart progress" list
    return [
        {"client": c, "cart": (c["clientCart"][0] if c["clientCart"] else None)}
        for c in clients
    ]

DELETE /dapp/carts/{cartId} — delete a cart

Removes a cart and all its items. Used when the customer abandons or chooses to start over.

Path parameters

NameTypeDescription
cartIdstring (UUID)The id from clientCart[0].id

Canonical payload

{}

Response

200 OK with data: null or a confirmation id.

Errors

StatusCauseFix
404 “Cart not found”Already deleted, or wrong holderTreat as success on the client side; idempotent in practice
401 “User is not authorized”Signed "" instead of "{}"Use the canonical payload "{}"

Common patterns

Resolve a single client’s cart

async function clientCart(clientId: string): Promise<Cart | null> {
  const client = await getClient(clientId); // GET /dapp/clients/{clientId}
  return client.clientCart[0] ?? null;
}

Replace cart contents (since there’s no “remove item”)

async function setCart(clientId: string, items: { strainId: string; quantity: number }[]) {
  const client = await getClient(clientId);
  const existing = client.clientCart[0];
  if (existing) await deleteCart(existing.id);
  await postCart({ clientId, cartItems: items });
}

Cart-to-order

When the customer checks out, you call POST /dapp/orders with the cart’s contents. The order endpoint takes the same shape as the cart contents, with the addition of shipping and payment details. The cart itself isn’t automatically cleared on order — clean it up with DELETE if you want a fresh slate.

Caching guidance

Don’t cache cart responses. Carts are mutable and customers expect immediate feedback after add/remove operations. Always read fresh.

See also

  • Strains — pricing and strain IDs to populate the cart
  • Clients — client detail also includes clientCart[]
  • Orders — converting a cart into an order