Check out as company user
Prerequisites
- Merchant API key (
X-Api)Key - Authenticated user session (JWT bearer token)
- User associated with a company account
- Existing cart with items (or a quotation cart ID)
Goals
- Check out a regular cart as a company user with company-managed addresses
- Load a quotation cart in checkout and understand its restrictions
- Place an order for a company cart or finalize a quotation order
Architecture at a glance
- Authenticate company user →
create(with company address selection) →Or Update Checkout placeOrder - Authenticate company user →
create(with quotation cart) →Or Update Checkout finalizeQuotation
APIs used
- Merchant API:
https://merchantapi.geins.io/graphql
Step-by-step
Create or update checkout as a company user
When an authenticated company user calls create, the API automatically detects the company membership and applies company rules:
- Addresses are restricted to those defined on the company. Custom
billingandAddress shippingfields are not accepted — useAddress billingandAddress Id shippinginstead.Address Id - The response includes
billingandAddresses shippinglists containing the eligible company addresses.Addresses - If no address ID is provided, the first matching address is selected by default.
Request example
mutation createOrUpdateCheckout(
$cartId: String!
$checkout: CheckoutInputType
$channelId: String
$languageId: String
$marketId: String
) {
createOrUpdateCheckout(
cartId: $cartId
checkout: $checkout
channelId: $channelId
languageId: $languageId
marketId: $marketId
) {
billingAddress {
addressId
company
addressLine1
zip
city
country
}
shippingAddress {
addressId
company
addressLine1
zip
city
country
}
billingAddresses {
addressId
company
addressLine1
zip
city
country
}
shippingAddresses {
addressId
company
addressLine1
zip
city
country
}
shippingOptions {
id
displayName
feeIncVat
isSelected
}
paymentOptions {
id
displayName
feeIncVat
isSelected
}
checkoutStatus
}
}
{
"Accept": "application/json",
"X-ApiKey": "{MERCHANT_API_KEY}",
"Authorization": "Bearer {JWT_TOKEN}"
}
{
"cartId": "{CART_ID}",
"checkout": {
"shippingAddressId": "{SHIPPING_ADDRESS_ID}",
"billingAddressId": "{BILLING_ADDRESS_ID}",
"shippingId": 1,
"paymentId": 2,
"email": "buyer@company.com"
},
"channelId": "{CHANNEL_ID}",
"languageId": "{LANGUAGE_ID}",
"marketId": "{MARKET_ID}"
}
curl -X POST https://merchantapi.geins.io/graphql \
-H "Accept: application/json" \
-H "X-ApiKey: {MERCHANT_API_KEY}" \
-H "Authorization: Bearer {JWT_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"query":"mutation createOrUpdateCheckout($cartId:String!,$checkout:CheckoutInputType,$channelId:String,$languageId:String,$marketId:String){createOrUpdateCheckout(cartId:$cartId,checkout:$checkout,channelId:$channelId,languageId:$languageId,marketId:$marketId){billingAddress{addressId company addressLine1 zip city country}shippingAddress{addressId company addressLine1 zip city country}billingAddresses{addressId company addressLine1 zip city country}shippingAddresses{addressId company addressLine1 zip city country}shippingOptions{id displayName feeIncVat isSelected}paymentOptions{id displayName feeIncVat isSelected}checkoutStatus}}","variables":{"cartId":"{CART_ID}","checkout":{"shippingAddressId":"{SHIPPING_ADDRESS_ID}","billingAddressId":"{BILLING_ADDRESS_ID}","shippingId":1,"paymentId":2,"email":"buyer@company.com"},"channelId":"{CHANNEL_ID}","languageId":"{LANGUAGE_ID}","marketId":"{MARKET_ID}"}}'
shippingAddressId and billingAddressId fields are optional. If omitted, the first eligible address from the company is selected automatically.Response example
200 OK{
"data": {
"createOrUpdateCheckout": {
"billingAddress": {
"addressId": "101",
"company": "Acme Trading AB",
"addressLine1": "Industrivägen 10",
"zip": "11122",
"city": "Stockholm",
"country": "SE"
},
"shippingAddress": {
"addressId": "102",
"company": "Acme Trading AB",
"addressLine1": "Lagervägen 5",
"zip": "11133",
"city": "Stockholm",
"country": "SE"
},
"billingAddresses": [
{
"addressId": "101",
"company": "Acme Trading AB",
"addressLine1": "Industrivägen 10",
"zip": "11122",
"city": "Stockholm",
"country": "SE"
}
],
"shippingAddresses": [
{
"addressId": "102",
"company": "Acme Trading AB",
"addressLine1": "Lagervägen 5",
"zip": "11133",
"city": "Stockholm",
"country": "SE"
}
],
"shippingOptions": [
{ "id": 1, "displayName": "Standard Shipping", "feeIncVat": 49.00, "isSelected": true }
],
"paymentOptions": [
{ "id": 2, "displayName": "Invoice", "feeIncVat": 0.00, "isSelected": true }
],
"checkoutStatus": "OK"
}
}
}
Place an order for a company cart
After setting up the checkout, place the order using place. The same company rules apply — use billing and shipping instead of free-form addresses.
Request example
mutation placeOrder(
$cartId: String!
$checkout: CheckoutInputType!
$channelId: String
$languageId: String
$marketId: String
) {
placeOrder(
cartId: $cartId
checkout: $checkout
channelId: $channelId
languageId: $languageId
marketId: $marketId
) {
orderId
publicId
}
}
{
"Accept": "application/json",
"X-ApiKey": "{MERCHANT_API_KEY}",
"Authorization": "Bearer {JWT_TOKEN}"
}
{
"cartId": "{CART_ID}",
"checkout": {
"shippingAddressId": "{SHIPPING_ADDRESS_ID}",
"billingAddressId": "{BILLING_ADDRESS_ID}",
"shippingId": 1,
"paymentId": 2,
"email": "buyer@company.com"
},
"channelId": "{CHANNEL_ID}",
"languageId": "{LANGUAGE_ID}",
"marketId": "{MARKET_ID}"
}
curl -X POST https://merchantapi.geins.io/graphql \
-H "Accept: application/json" \
-H "X-ApiKey: {MERCHANT_API_KEY}" \
-H "Authorization: Bearer {JWT_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"query":"mutation placeOrder($cartId:String!,$checkout:CheckoutInputType!,$channelId:String,$languageId:String,$marketId:String){placeOrder(cartId:$cartId,checkout:$checkout,channelId:$channelId,languageId:$languageId,marketId:$marketId){orderId publicId}}","variables":{"cartId":"{CART_ID}","checkout":{"shippingAddressId":"{SHIPPING_ADDRESS_ID}","billingAddressId":"{BILLING_ADDRESS_ID}","shippingId":1,"paymentId":2,"email":"buyer@company.com"},"channelId":"{CHANNEL_ID}","languageId":"{LANGUAGE_ID}","marketId":"{MARKET_ID}"}}'
Response example
200 OK{
"data": {
"placeOrder": {
"orderId": "order-id-12345",
"publicId": "ORD-2025-001234"
}
}
}
Check out a quotation cart
Quotation carts can also be loaded in create. This lets you preview shipping and payment options before finalizing. The following restrictions apply:
- Only shipping and payment methods defined in the quotation are available.
- The authenticated user must be the assigned buyer for the quotation.
- The cart cannot be modified (items are locked).
- Orders from quotation carts are placed via
finalize, notQuotation place.Order
Quotation status requirements
A quotation cart can only be used in get and create if it has an eligible status. The API rejects carts with terminal or inactive statuses:
| Status | Allowed in checkout | Notes |
|---|---|---|
PENDING | Only if require is false | If require is true, the buyer must first accept and the seller must confirm |
ACCEPTED | Only if require is false | If require is true, the cart is blocked until the seller confirms |
CONFIRMED | ✅ Yes | Ready for checkout and finalization |
DRAFT | ❌ No | Not yet sent to buyer |
EXPIRED | ❌ No | Validity period has passed |
CANCELED | ❌ No | Canceled by seller |
REJECTED | ❌ No | Rejected by buyer |
FINALIZED | ❌ No | Already converted to an order |
When a quotation has require and is in PENDING status, the API returns an error indicating the quotation must be accepted by the buyer and confirmed by the seller before it can proceed. Similarly, an ACCEPTED quotation with require is blocked until the seller confirms it.
Pass the quotation cart ID as the cart argument:
Request example
mutation createOrUpdateCheckout(
$cartId: String!
$checkout: CheckoutInputType
$channelId: String
$languageId: String
$marketId: String
) {
createOrUpdateCheckout(
cartId: $cartId
checkout: $checkout
channelId: $channelId
languageId: $languageId
marketId: $marketId
) {
shippingOptions {
id
displayName
feeIncVat
isSelected
}
paymentOptions {
id
displayName
feeIncVat
isSelected
}
billingAddress {
addressId
company
addressLine1
city
country
}
shippingAddress {
addressId
company
addressLine1
city
country
}
checkoutStatus
}
}
{
"Accept": "application/json",
"X-ApiKey": "{MERCHANT_API_KEY}",
"Authorization": "Bearer {JWT_TOKEN}"
}
{
"cartId": "{QUOTATION_CART_ID}",
"checkout": {
"shippingId": 1,
"paymentId": 2,
"shippingAddressId": "{SHIPPING_ADDRESS_ID}",
"billingAddressId": "{BILLING_ADDRESS_ID}"
},
"channelId": "{CHANNEL_ID}",
"languageId": "{LANGUAGE_ID}",
"marketId": "{MARKET_ID}"
}
curl -X POST https://merchantapi.geins.io/graphql \
-H "Accept: application/json" \
-H "X-ApiKey: {MERCHANT_API_KEY}" \
-H "Authorization: Bearer {JWT_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"query":"mutation createOrUpdateCheckout($cartId:String!,$checkout:CheckoutInputType,$channelId:String,$languageId:String,$marketId:String){createOrUpdateCheckout(cartId:$cartId,checkout:$checkout,channelId:$channelId,languageId:$languageId,marketId:$marketId){shippingOptions{id displayName feeIncVat isSelected}paymentOptions{id displayName feeIncVat isSelected}billingAddress{addressId company addressLine1 city country}shippingAddress{addressId company addressLine1 city country}checkoutStatus}}","variables":{"cartId":"{QUOTATION_CART_ID}","checkout":{"shippingId":1,"paymentId":2,"shippingAddressId":"{SHIPPING_ADDRESS_ID}","billingAddressId":"{BILLING_ADDRESS_ID}"},"channelId":"{CHANNEL_ID}","languageId":"{LANGUAGE_ID}","marketId":"{MARKET_ID}"}}'
finalizeQuotation mutation — see Finalize a quotation order.Response example
200 OK{
"data": {
"createOrUpdateCheckout": {
"shippingOptions": [
{ "id": 1, "displayName": "Freight", "feeIncVat": 0.00, "isSelected": true }
],
"paymentOptions": [
{ "id": 2, "displayName": "Invoice 30 days", "feeIncVat": 0.00, "isSelected": true }
],
"billingAddress": {
"addressId": "101",
"company": "Acme Trading AB",
"addressLine1": "Industrivägen 10",
"city": "Stockholm",
"country": "SE"
},
"shippingAddress": {
"addressId": "102",
"company": "Acme Trading AB",
"addressLine1": "Lagervägen 5",
"city": "Stockholm",
"country": "SE"
},
"checkoutStatus": "OK"
}
}
}
Options
Multi-market support
All mutations support optional parameters for multi-market functionality:
channel: Target specific sales channelsId language: Set content languageId market: Target specific marketsId
Authenticated access
Authentication is required for company checkout. The API uses the JWT bearer token to identify the user's company membership and apply company-specific rules (addresses, pricing). Without a valid token, the checkout will not apply company logic.
For quotation carts, authentication is also required — the API verifies that the logged-in user matches the assigned buyer on the quotation.
Include the token in the Authorization header:
Authorization: Bearer {JWT_TOKEN}
Common pitfalls
- Passing
billingorAddress shippingdirectly — Company checkouts reject free-form address input. UseAddress billingandAddress Id shippingto select from predefined company addresses.Address Id - Calling
placeon a quotation cart — Quotation carts must be finalized viaOrder finalize. TheQuotation placemutation will return an error for quotation carts.Order - Quotation in wrong status — A quotation cart with status
DRAFT,EXPIRED,CANCELED,REJECTED, orFINALIZEDcannot be loaded ingetorCart create. IfOr Update Checkout requireis enabled, the quotation must reachConfirmation CONFIRMEDstatus before checkout is possible. - Missing authentication — Both company checkout and quotation checkout require a valid JWT token. An unauthenticated request will fail.
- Wrong buyer for quotation — A quotation cart can only be checked out by the user assigned as buyer on that quotation. Attempting to load another user's quotation returns an error.