SBCoreX · Integration Guide

Connect to the
SmartBamboo POS API

A single GraphQL endpoint for products, customers, orders, and payments — the same data the point-of-sale runs on. This guide gets you authenticated and reading the schema in a few minutes.

Protocol  GraphQL over HTTPS Transport  AWS AppSync Method  POST Encoding  application/json
POST /graphql
# every call is a POST with a query body
{ "query": "{ ping }" }
200 response
{
  "data": {
    "ping": "pong"
  }
}
01

Connect

The API lives behind one GraphQL endpoint. We hand you three values at onboarding — keep the key secret and out of client-side code.

ValueShapeWhat it's for
Endpoint URLhttps://<id>.appsync-api.<region>.amazonaws.com/graphqlWhere every request is POSTed.
API keyda2-… (AWS AppSync format)Opens the public endpoints (login, ping). Sent as x-api-key.
Regionus-east-2The AWS region the endpoint runs in.
serverUrlhttps://dev.odoo-smartbamboo.mx (test)Passed to login — identifies the backing ERP for your environment.
databasesmart-bamboo-dev (test)Passed to login alongside serverUrl.
EnvironmentsTest against the dev endpoint first — it exposes the same schema as production but must be paired with the test serverUrl and database above. Do not point a test integration at the production values: the endpoint will accept them and you will be reading (and writing) live data. You get the production URL, key, and login parameters once integration is signed off.
02

Authenticate

Authentication is two-tier. The API key gets you to the public endpoints; logging in returns a short-lived JWT that unlocks everything else. Pick the header that matches what you're calling.

Primary

JWT token

Sent on every protected query and mutation. Obtained from login.

authorizationToken: <jwt>
Public

API key

For the open endpoints — login, ping, isTokenValid.

x-api-key: <key>
Internal

AWS IAM

SigV4-signed, reserved for our own service-to-service webhooks.

Authorization: AWS4-HMAC-…

Step 1 — Exchange credentials for a token

Call login with the API key in the header. It returns a JWT valid for roughly 24 hours, plus the signed-in user and company.

POST /graphql · x-api-key
mutation Login {
  login(
    serverUrl: "https://dev.odoo-smartbamboo.mx"  # test env
    database:  "smart-bamboo-dev"                # test env
    username:  "partner@example.com"
    password:  "••••••••"
  ) {
    token           # put this in authorizationToken
    user {
      id
      name
      email
      company { id name }
    }
  }
}

Step 2 — Send the token on protected calls

From here on, set authorizationToken to the JWT. The API key is no longer needed for these requests.

Step 3 — Refresh before it expires

Call refreshToken with a still-valid token to get a fresh one — no need to re-enter credentials.

POST /graphql · authorizationToken
mutation Refresh {
  refreshToken { token }
}
03

Make a request

Every call — query or mutation — is a single POST with a JSON body containing query and optional variables. Here's a complete authenticated request over curl.

POST curl
curl -X POST "$ENDPOINT" \
  -H "authorizationToken: $JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query Products($pl: ID!) { getProducts(pricelistId: $pl) { product { id name basePrice } pricedVariants { variantId price } } }",
    "variables": { "pl": "<your pricelistId>" }
  }'

A successful response wraps results under data, keyed by the operation name:

200 response
{
  "data": {
    "getProducts": [
      {
        "product": { "id": "5659", "name": "Almohada Memory", "basePrice": 499.00 },
        "pricedVariants": [ { "variantId": "7210", "price": 449.00 } ]
      }
    ]
  }
}
04

Explore live

Run real queries against the endpoint right here. Open the Headers tab in the explorer and add x-api-key (for public operations) or authorizationToken (for everything else), then hit run. The full schema loads by introspection once your headers are accepted.

Loading the GraphQL explorer… if this doesn't appear, your network may block the Apollo embed. Use the curl example above instead.

Powered by Apollo's embedded Explorer. Nothing you type here is stored on this page.

05

Schema

The API exposes queries for reading and mutations for writing — roughly 98 of each. Below are the operations most external integrations use, with their exact signatures. The full schema is browsable by introspection in the explorer above (works with x-api-key alone), and the SDL is available on request.

Queries — read data

Query
getProducts(pricelistId: ID!, categoryId: ID, posConfigId: ID): [ProductForSale!]!
The catalog priced against a pricelist. Each entry is product + pricedVariants.
Query
getProductCategories(posConfigId: ID): [ProductCategory!]!
The category tree used to group products.
Query
getPricelists(ids: [ID!]): [Pricelist!]!
Pricelists visible to your user.
Query
getPricelistVersions(ids: [ID!]): [PricelistVersion!]!
lastModified per pricelist — poll it to detect price changes.
Query
searchPartners(query: String!): [User!]!
Look up customers by name. Returns the lightweight User shape (no phone/vat).
Query
getOrderById(orderId: ID!): PosOrderDetail
A single order with lines, payments, and totals. The receipt reference is posReference.
Query
searchOrders(query: String!, sessionId: ID, limit: Int): [Order!]!
Search orders by reference or customer text.
Query
getCustomerHistory(partnerId: ID!, limit: Int, offset: Int): [OrderSummary!]!
A customer's purchase history, paginated.
Query
getPaymentMethods(posId: ID!): [PaymentMethod!]!
Payment methods available to a point of sale.
Query
getQuotation(quotationId: ID!): Quotation
Retrieve a saved quotation / wishlist.
Query
getHomeDeliveries(posConfigId: ID!, automaticPurchaseSale: Boolean!, filter: HomeDeliveryFilter, offset: Int, limit: Int): HomeDeliveryPage!
Delivery orders and their fulfillment status, paginated.

Mutations — write data

Mutation
login(serverUrl: String!, database: String!, username: String!, password: String!): AuthPayload!
Authenticate and receive a JWT (token + user).
Mutation
refreshToken: RefreshTokenPayload!
Renew a valid token.
Mutation
createPartner(input: CreatePartnerInput!): Partner!
Register a new customer. Returns the full Partner (phone, vat, address).
Mutation
updatePartner(id: ID!, input: UpdatePartnerInput!): Partner!
Edit an existing customer.
Mutation
createOrderFromCart(cartId: ID!, tabNumber: Int, posSessionId: ID, loginNumber: Int): Order!
Turn a built-up cart into an order.
Mutation
saveWishlist(input: SaveWishlistInput!): Quotation!
Save a quotation for later checkout.
NoteCart-building (createCart, addItemToCart, …) and terminal payments exist too, but they're tuned for the live POS session. Talk to us before driving the checkout flow externally so we can scope the right operations.
06

Core types

The shapes you'll read most often, exactly as the schema defines them — request only what you need; GraphQL returns exactly the fields you select.

type catalog — ProductForSale · Product · ProductVariant
type ProductForSale {        # what getProducts returns
  product: Product!
  pricedVariants: [PricedVariant!]!  # price per variant on the requested pricelist
}

type Product {
  id: ID!
  name: String!
  imageUrl: String
  basePrice: Float!
  productType: String
  category: ProductCategory!
  posCategory: ProductCategory
  attributeOptions: [ProductAttribute!]!
  variants: [ProductVariant!]!
}

type ProductVariant {
  id: ID!                  # the sellable unit — use this id everywhere
  basePrice: Float!
  imageUrl: String
  selectedAttributes: [SelectedAttribute!]!
}

type PricedVariant { variantId: ID!, price: Float! }
type Pricelist { id: ID!, name: String! }
type PricelistVersion { pricelistId: ID!, lastModified: String }
Heads-upSKU (defaultCode) and barcode are not exposed on the catalog types yet. Map products by ProductVariant.id for now — it's stable and unique per sellable unit. Ask us if your integration needs SKU/barcode; it's on the roadmap.
type people — User · Partner
type User {                  # what searchPartners returns
  id: ID!
  name: String!
  username: String!
  email: String!
  company: CompanyInfo!     # { id, name }
}

type Partner {               # returned by createPartner / updatePartner
  id: ID!
  name: String!
  email: String
  phone: String
  mobile: String
  vat: String              # tax id (RFC)
  street: String
  city: String
  zip: String
}
type orders — Order · PosOrderDetail · lines
type Order {                 # what searchOrders returns
  id: ID!
  name: String!
  posReference: String      # receipt reference (not "reference")
  customerId: ID
  customerName: String
  dateOrder: String!
  state: OrderState!        # enum
  amountTotal: Float!
  amountTax: Float!
  amountPaid: Float!
  lines: [OrderLine!]!
  payments: [OrderPayment!]!
}

type OrderLine {
  id: ID!
  productId: ID!
  productName: String!
  variantId: ID
  quantity: Float!
  unitPrice: Float!
  discount: Float
  taxAmount: Float!
  priceSubtotal: Float!    # before tax
  priceTotal: Float!       # tax-inclusive
}

type PosOrderDetail {       # what getOrderById returns
  id: ID!
  name: String!
  posReference: String
  receiptNumber: String
  customerId: ID
  customerName: String
  dateOrder: String
  datePaid: String
  state: String
  amountSubtotal: Float
  amountTax: Float
  amountTotal: Float
  amountPaid: Float
  lines: [PosOrderLine!]   # id, productId, productName, quantity,
  payments: [PosOrderPayment!] # unitPrice, discount, priceSubtotal, priceTotal
}

Field names follow GraphQL camelCase. Ids are GraphQL ID (strings on the wire) that carry the ERP integer ids. Money is decimal Float; priceSubtotal is pre-tax and priceTotal is tax-inclusive.

07

Errors

The HTTP status is almost always 200 — GraphQL reports problems in an errors array alongside (or instead of) data. Always check for errors before trusting data.

200 error envelope
{
  "errors": [
    { "message": "Not Authorized to access getProducts" }
  ]
}
errorType / messageCauseFix
Not AuthorizedMissing, expired, or wrong-tier token.Re-run login or refresh; confirm you're using authorizationToken.
UnauthorizedExceptionBad or absent x-api-key on a public call.Check the API key header and value.
MissingFieldArgumentA required argument was omitted (e.g. pricelistId on getProducts).Check the signature in the schema section or the explorer.
UnknownArgumentAn argument that doesn't exist in the schema.Introspect the field; argument names are exact.
FieldUndefinedSelecting a field the type doesn't have.Check the type in the explorer's schema tab.
Could not reach the authentication serverlogin couldn't authenticate against the serverUrl/database pair — wrong values or wrong credentials for that database.Confirm you're using the environment's exact serverUrl and database (see Connect) and that your user was provisioned in that database.
08

REST endpoints legacy

A small REST surface exists for backward compatibility. Prefer GraphQL for new work — these routes will not gain features. Base URL: https://<id>.execute-api.<region>.amazonaws.com/<env>.

MethodPathPurpose
POST/auth/loginAuthenticate (use GraphQL login instead).
GET/partnersSearch customers.
POST/partnersCreate a customer.
PUT/partners/{id}Update a customer.
GET/productsSearch products.
GET/pricelistsList pricelists.