RLD CCD POS Checkout APIInteractive checkout and void documentation

Checkout Retail Dispense

Submits a retail dispense checkout supporting adult-use and medical customers, in-store and delivery dispense types, retailer and courier fulfillment, and multiple ticket items.

Requires the location JWT from the Tokens API in the Authorization: Bearer <token> header.
POST/v1/dispensesCheckout a retail dispense↑ Back to top

Request body fields

NameTypeDescription
internalRequestId requiredUUID stringIdentifies one logical dispense. Persist the UUID before submitting and reuse it when retrying after a timeout; a repeated checkout with an already processed identifier returns DUPLICATE_INTERNAL_REQUEST_ID.
dispenseDateTime required ISO 8601 / RFC 3339UTC timestamp of the checkout request, for example 2026-08-07T16:20:14.000Z.
customerType requiredstringadult-use or medical.
dispenseType requiredstringin-store or delivery.
medicalCannabisCardIdstringRequired when customerType is medical.
items[] requiredarrayOne or more items with inventoryId, quantity, dollarAmount, and taxAmount.
deliveryFulfillmentTypestringretailer or courier; required for delivery.
deliveryAddress, travelRoutestringRequired for delivery dispenses.
retailerDriverId, retailerVehicleIdintegerRequired for retailer-fulfilled delivery.
courierRetailAgreementId, courierDriverId, courierVehicleIdintegerRequired for courier-fulfilled delivery.
Dispense
Items
Inventory ID *Quantity *Dollar amount *Tax amount *

Request URL

Request body preview

Server response

Successful Response

{
    "status": "ok",
    "message": "",
    "data": {
        "retailDispenseTicketId": 4217,
        "barCode": "1234567890123456",
        "internalRequestId": "7693ae51-135b-4755-a15e-f7aac21bc33a",
        "totalItems": 2,
        "totalDollarAmount": 40.00,
        "totalTaxAmount": 3.20,
        "grandTotalAmount": 43.20,
        "totalThcMg": 520.00,
        "delta9ThcMgTotal": 450.00,
        "adultUseCannabisGramsTotal": 7.00,
        "adultUseConcentrateGramsTotal": 0,
        "adultUseCannabisMilligramsTotal": 0,
        "medicalUnitsTotal": 0,
        "plantCountTotal": 0,
        "medicalIdentifierId": null
    }
}

Response Fields

FieldTypeDescription
retailDispenseTicketIdnumberInternal parent ticket identifier.
barCodestringGenerated order number/ticket barcode.
internalRequestIdUUID stringOriginal logical dispense request identifier.
totalItemsnumberNumber of distinct item rows.
totalDollarAmountnumberPre-tax order total.
totalTaxAmountnumberOrder tax total.
grandTotalAmountnumberSum of dollar and tax totals.
totalThcMgnumberTotal THC milligrams calculated for all items.
delta9ThcMgTotalnumberTotal Delta-9 THC milligrams calculated for all items.
adultUseCannabisGramsTotalnumberAdult-Use cannabis-gram total.
adultUseConcentrateGramsTotalnumberAdult-Use concentrate-gram total.
adultUseCannabisMilligramsTotalnumberAdult-Use cannabis-milligram total.
medicalUnitsTotalnumberMedical units used by the order; zero for an Adult-Use response.
plantCountTotalnumberPlants represented by the order.
medicalIdentifierIdstring or nullResolved patient identifier for a Medical dispense; null for Adult-Use.

Endpoint-Specific Errors

Error codeTypical message or conditionMeaning
INVALID_DISPENSEDispense information is required or must be valid JSON.The top-level dispense object was missing or malformed.
DUPLICATE_INTERNAL_REQUEST_IDThis internal request ID has already been processed.The logical sale identifier was already stored; reconcile through order lookup.
DISPENSE_FAILEDCustomer Type is required; Dispense Type is required; or another validation message.A request-field or business-rule validation failed.
ACTIVE_LOCATION_LICENSE_REQUIREDLocation lacks an eligible active license or temporary access.The location cannot perform the requested dispense.
INVENTORY_CASE_RESTRICTIONMessage varies with the active case restriction.One or more selected inventory items are blocked from dispensing.
DISPENSE_FAILEDMedical units used exceed the patient's remaining medical units.The proposed Medical order exceeds the authoritative current balance.
DISPENSE_FAILEDAdult-Use or plant total cannot exceed the configured limit.The proposed order exceeds a purchase limit.
DISPENSE_FAILEDInventory, testing, expiration, quantity, calculation, delivery, driver, vehicle, or courier validation message.The authoritative checkout validation failed.



POST/v1/dispenses/{retailDispenseTicketId}/voidVoid a dispense ticket↑ Back to top

Voids the specified retail dispense ticket and records the reason.

NameInDescription
internalRequestId
required
body
UUID string
Internal request identifier for the void operation. Generated automatically; reuse the same UUID when retrying the same void.
retailDispenseTicketId
required
path Ticket identifier to void.
voidReason
required
body Reason for voiding the ticket.

Try it out

Request URL

Server response


                

Void: Eligibility and Safety Rules

The void is allowed only when all applicable conditions remain true:

The route intentionally does not apply the administrative inventory-case restriction check. A case hold does not by itself prevent a safe void, although all downstream-activity and inventory-integrity checks still apply.

Inventory Restoration

Void Idempotency

Successful Response

{
    "status": "ok",
    "message": "",
    "data": {
        "retailDispenseTicketId": 4217,
        "barCode": "1234567890123456",
        "ticketStatus": "Voided",
        "voidedDateTime": "2026-07-25T16:20:14.000Z",
        "voidedByUserId": 1001,
        "voidReason": "The POS user selected the wrong inventory item and confirmed that no downstream inventory activity occurred.",
        "voidInternalRequestId": "f87a21f8-cf3a-46af-b4df-b25633499f14",
        "restoredItems": [
            {
                "inventoryId": 1789,
                "barCode": "9876543210987654",
                "quantity": 2,
                "unit": "pkg"
            }
        ]
    }
}

Idempotent Retry Response

{
    "status": "ok",
    "message": "",
    "data": {
        "retailDispenseTicketId": 4217,
        "barCode": "1234567890123456",
        "ticketStatus": "Voided",
        "voidedDateTime": "2026-07-25T16:20:14.000Z",
        "voidedByUserId": 1001,
        "voidReason": "The POS user selected the wrong inventory item and confirmed that no downstream inventory activity occurred.",
        "voidInternalRequestId": "f87a21f8-cf3a-46af-b4df-b25633499f14",
        "restoredItems": []
    }
}

Response Fields

FieldTypeDescription
retailDispenseTicketIdnumberVoided parent ticket identifier.
barCodestringOrder number/ticket barcode.
ticketStatusstringVoided after a successful operation.
voidedDateTimedate/timeUTC date/time stored for the void.
voidedByUserIdnumber or stringConfigured internal POS system user that performed the operation.
voidReasonstringStored reason for the void.
voidInternalRequestIdUUID stringLogical void identifier used for idempotency.
restoredItemsarrayInventory rows restored during this call. Empty for a successful idempotent retry.

Restored Item Fields

FieldTypeDescription
inventoryIdnumberInventory record restored.
barCodestringCompliance barcode of the restored inventory.
quantitynumberQuantity restored.
unitstringStored dispense unit: pkg, g, or mL.

Endpoint-Specific Errors

Error codeMeaning
INVALID_DISPENSE_TICKETThe supplied ticket ID was missing or invalid.
VOID_REASON_REQUIREDA reason was not supplied.
VOID_REASON_TOO_SHORTThe trimmed reason contains fewer than 50 characters.
VOID_REASON_TOO_LONGThe reason exceeds 1,000 characters.
DISPENSE_NOT_FOUNDThe ticket was not found for the authorized organization and location.
DISPENSE_ALREADY_VOIDEDThe ticket was already voided with a different request ID.
DISPENSE_NOT_COMPLETEOnly a completed ticket can be voided.
DISPENSE_NOT_CREATED_THROUGH_POSThe ticket originated in the web application rather than the POS API.
INVALID_DISPENSE_ROOMThe original Retail or Consumption room cannot be determined.
ACTIVE_LOCATION_LICENSE_REQUIREDThe location lacks the license or temporary access required for the original room.
DISPENSE_ITEMS_NOT_FOUNDThe ticket's item rows are missing.
INVENTORY_NOT_FOUNDOne or more original inventory records no longer exist.
INVENTORY_LEFT_LOCATIONAn inventory item is no longer at the original organization and location.
INVENTORY_HAS_DOWNSTREAM_ACTIVITYA transfer, manifest, destruction, or later unsafe inventory event prevents automatic reversal.
DISPENSE_HISTORY_LINK_MISSINGThe original inventory-history reference needed for a safe reversal is missing.
INVALID_DISPENSE_ITEM_QUANTITYA stored quantity is invalid for restoration.
DUPLICATE_VOID_INTERNAL_REQUEST_IDThe logical void request ID has already been used elsewhere.
VOID_DISPENSE_FAILEDAn unexpected void-processing error occurred.