Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
The Phone Number object is used in the Marketplace APIs to represent a phone number. This object contains two fields:
prefix
string
Represents the country-specific prefix.
number
string
Represents the phone number.
{
"prefix": "+34",
"number": "660707172"
}The Error object represents an error response returned by the Marketplace API when it encounters a non-2xx HTTP response code. This object includes the following fields:
title
string
A short description of the problem.
id
string
Message identifier used for the localization process.
parameters
object
Parameters that can be used in a message with {{name}} a template.
type
string
A URI reference that identifies the error type (Problem Details / RFC 7807).
status
number
The HTTP status code returned by the server.
details
string
(Optional) A detailed description of the error message.
traceId
string
(Optional) Represents an identifier used to trace a request.
errors
object
(Optional) A detailed list of errors that can be connected to the request data.
message
string
The message text with markdown allowed.
properties
list<string>
{
"title": "Order update failed",
"detail": "External ID is too long",
"status": 400,
"type": "https://docs.platform.softwareone.com/developer-resources/rest-api/errors/commerce#MPTCOM03-0078",
"traceId": "00-00000000000000000000000000000000-000000000000000-00"
} {
"title": "Order update failed",
"detail": "Value of listing does not correspond to a valid listing; External ID is too long",
"status": 400,
"type": "https://docs.platform.softwareone.com/developer-resources/rest-api/errors/billing#MPTBIL03-0078",
"traceId": "00-00000000000000000000000000000000-000000000000000-00",
"errors": [
{
"message": "Value of listing does not correspond to a valid listing",
"properties": [ "listing.id" ]
},
{
"message": "External ID is too long",
"properties": [ "externalId" ]
}
]
}List of object properties affected by the error.
Understand Marketplace API errors and status codes.
All errors reported by the REST API have an and follow the standard format.
When an error occurs, the response body usually contains a JSON object with the following fields:
type - [string] A URI reference that identifies the error type, providing a consistent way to categorize errors across different API implementations.
title - [string] A human-readable title or summary of the error.
detail - (Optional) [string] A detailed human-readable description of the error, providing additional information to help clients understand the issue.
instance - (Optional) [string] A URI reference that identifies the specific occurrence of the error, useful for debugging or tracing purposes.
traceId - (Optional) [string] A unique identifier to trace requests in logs.
errors - (Optional) [key-value] A collection of errors detected by validation logic.
The following table lists some of the common errors:
401 Unauthorized
The request lacks valid authentication credentials for the target resource. Check whether the Authorization header is present and contains a valid token value.
403 Forbidden
The server understands the request but refuses to authorize it.
404 Not Found
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "Bad Request",
"status": 400,
"detail": "One or more validation errors occurred.",
"traceId": "00-9e02a91b64ac56904703a3a69ea9101d-56be90a29d0b0b25-00",
"errors": {
"mistake": [
"Unknown expression group."
]
}
}The requested resource couldn't be found on the server.
409 Conflict
The request couldn't be completed due to a conflict with the current state of the resource.
415 Unsupported Media Type
The server refuses the request because the payload format isn't supported.
500 Internal Server Error
The server encountered an unexpected condition that prevented it from fulfilling the request.
501 Not Implemented
The server doesn't support the functionality required to fulfill the request.
504 Gateway Timeout
The server, while acting as a gateway or proxy, didn't receive a timely response from an upstream server.
The Message object indicates the error or the reason for the order failure. This object contains the following attributes:
id
string
(Optional) The message identifier to be used for the localization process.
message
string
The content of the message.
parameters
string
(Optional) Parameters used within the message.
{
"id": "E001234",
"message": "Agreement provisioning failed due to unavailability of the item"
}{
"id": "E001234",
"message": "Agreement provisioning failed due to unavailability of the item {{ item }}",
"parameters": {
"item": "ITM-1234-1234-1234"
}
}Learn how to map between Portal URLs and API endpoints for Marketplace Platform objects.
The Marketplace Platform provides two main entry points for interacting with your data:
Portal (Web UI) – https://portal.platform.softwareone.com/
API – https://api.platform.softwareone.com/public/v1/
While both the Portal and API operate on the same underlying objects, their URL structures differ slightly due to usability requirements. This topic explains how you can map between portal URLs and API endpoints to:
Generate deep links to specific objects in the portal.
Determine which API endpoint to call based on a portal URL.
Build integrations that navigate between UI and API resources.
Enable LLM agents to translate between human-readable links and API calls.
The base endpoint for the Marketplace Platform API is:
All API requests start from that base URL. For example, if you have an endpoint like:
The fully qualified URL that you need to use is:
Use this base endpoint with specific API paths to access the resources and services provided by the Marketplace Platform.
Every object in the Marketplace Platform has a unique identifier with a prefix that indicates the object type. For details on all such objects, see .
The following tables show how Portal URLs map to API endpoints for each category of objects.
The notifications module is primarily accessed through the API for webhook management and programmatic notification handling.
Where:
{module} is one of: administration/settings, commerce, billing, catalog, program
{resource} is the plural resource name (for example, agreements
The API follows the same structure, with /public/v1/ added after the base domain.
When you retrieve an object from the API, you can construct a Portal link using the object's id:
When you have a Portal URL and need to call the corresponding API:
You can determine the object type from the ID prefix:
When working with Marketplace Platform URLs, follow these guidelines:
Use the correct portal URL - Always use https://portal.platform.softwareone.com/ for Portal links. The legacy URL https://portal.softwareone.com/ is kept for backwards compatibility only and should not be used for new requests. Always route new links to portal.platform.softwareone.com.
ID recognition - Object IDs always follow the pattern {PREFIX}-{segments} where the prefix is 3 letters (for example, AGR, ORD
Sellers List
/administration/settings/sellers
GET /accounts/sellers
Seller Details
/administration/settings/sellers/{id}
GET /accounts/sellers/{id}
Licensees List
/administration/settings/licensees
GET /accounts/licensees
Licensee Details
/administration/settings/licensees/{id}
GET /accounts/licensees/{id}
Users List
/administration/settings/users
GET /accounts/users
User Details
/administration/settings/users/{id}
GET /accounts/users/{id}
User Groups List
/administration/settings/groups
GET /accounts/user-groups
User Group Details
/administration/settings/groups/{id}
GET /accounts/user-groups/{id}
API Tokens List
/administration/settings/api-tokens
GET /accounts/api-tokens
API Token Details
/administration/settings/api-tokens/{id}
GET /accounts/api-tokens/{id}
Assets List
/commerce/assets
GET /commerce/assets
Asset Details
/commerce/assets/{id}
GET /commerce/assets/{id}
Entitlements List
/commerce/entitlements
GET /commerce/lines
Entitlement Details
/catalog/items/{id}
GET /catalog/items/{id}
Orders List
/commerce/orders
GET /commerce/orders
Order Details
/commerce/orders/{id}
GET /commerce/orders/{id}
Subscriptions List
/commerce/subscriptions
GET /commerce/subscriptions
Subscription Details
/commerce/subscriptions/{id}
GET /commerce/subscriptions/{id}
Requests List
/commerce/requests
GET /commerce/requests
Request Details
/commerce/requests/{id}
GET /commerce/requests/{id}
Invoices List
/billing/invoices
GET /billing/invoices
Invoice Details
/billing/invoices/{id}
GET /billing/invoices/{id}
Credit Memos List
/billing/credit-memos
GET /billing/credit-memos
Credit Memo Details
/billing/credit-memos/{id}
GET /billing/credit-memos/{id}
Items List
/catalog/items
GET /catalog/items
Item Details
/catalog/items/{id}
GET /catalog/items/{id}
Price Lists
/catalog/price-lists
GET /catalog/price-lists
Price List Details
/catalog/price-lists/{id}
GET /catalog/price-lists/{id}
Listings
API only
GET /catalog/listings
Listing Details
API only
GET /catalog/listings/{id}
Authorizations
API only
GET /catalog/authorizations
Authorization Details
API only
GET /catalog/authorizations/{id}
Certificates List
/program/certificates
GET /program/certificates
Certificate Details
/program/certificates/{id}
GET /program/certificates/{id}
Enrollments List
/program/enrollments
GET /program/enrollments
Enrollment Details
/program/enrollments/{id}
GET /program/enrollments/{id}
Messages
API only
GET /notifications/messages
Message Details
API only
GET /notifications/messages/{id}
Contacts
API only
GET /notifications/contacts
Subscribers
API only
GET /notifications/subscribers
ordersinvoices{id} is the object identifier (optional, only for detail pages)
billing
billing
Direct mapping
catalog
catalog
Direct mapping
program
program
Direct mapping
N/A
notifications
API only
N/A
audit
API only
N/A
spotlight
API only
SUBURL translation - To convert a Portal URL to an API endpoint:
Replace portal.platform.softwareone.com with api.platform.softwareone.com/public/v1
Keep the path unchanged (for example, /commerce/orders/{id})
API to portal - To convert an API endpoint to a Portal URL:
Replace api.platform.softwareone.com/public/v1 with portal.platform.softwareone.com
Keep the path unchanged
Special cases -
The Portal home page (/home) has no API equivalent
Entitlement details pages redirect to /catalog/items/{id}
Portal uses /administration/settings/groups but API uses /accounts/user-groups
All accounts-related objects are under /administration/settings/ in Portal but /accounts/ in API
The API requires authentication via a Bearer token
Module detection - The first path segment after the base URL indicates the module:
Portal administration/settings = API accounts (Buyers, Sellers, Licensees, Users, User Groups, API Tokens)
commerce = Agreements, Assets, Orders, Subscriptions, Requests, Entitlements
billing = Statements, Invoices, Credit Memos
catalog = Products, Items, Price Lists, Listings, Authorizations
program = Programs, Certificates, Enrollments
notifications = Webhooks, Messages, Contacts, Subscribers (API only)
API-only resources - Some resources are only accessible via API and have no Portal equivalent:
Listings (LST-)
Authorizations (AUT-)
Webhooks (WBH-)
Notification Messages, Contacts, Subscribers
Legacy URL handling - If you encounter URLs using portal.softwareone.com, rewrite them to use portal.platform.softwareone.com before processing or generating links.
Buyers List
/administration/settings/buyers
GET /accounts/buyers
Buyer Details
/administration/settings/buyers/{id}
Agreements List
/commerce/agreements
GET /commerce/agreements
Agreement Details
/commerce/agreements/{id}
Statements List
/billing/statements
GET /billing/statements
Statement Details
/billing/statements/{id}
Products List
/catalog/products
GET /catalog/products
Product Details
/catalog/products/{id}
Programs List
/program/programs
GET /program/programs
Program Details
/program/programs/{id}
Webhooks
API only
GET /notifications/webhooks
Webhook Details
API only
administration/settings
accounts
Buyers, Sellers, Licensees, Users, Groups, API Tokens
commerce
commerce
GET /accounts/buyers/{id}
GET /commerce/agreements/{id}
GET /billing/statements/{id}
GET /catalog/products/{id}
GET /program/programs/{id}
GET /notifications/webhooks/{id}
Direct mapping
https://api.platform.softwareone.com/public/v1/accounts/buyershttps://api.platform.softwareone.com/public/v1/accounts/buyershttps://portal.platform.softwareone.com/{module}/{resource}/{id}https://api.platform.softwareone.com/public/v1/{module}/{resource}/{id}# Python example
def get_portal_url(api_response, resource_type):
base_url = "https://portal.platform.softwareone.com"
object_id = api_response["id"]
# Map resource types to Portal paths
resource_paths = {
# Accounts (under administration/settings)
"buyer": "administration/settings/buyers",
"seller": "administration/settings/sellers",
"licensee": "administration/settings/licensees",
"user": "administration/settings/users",
"user-group": "administration/settings/groups",
"api-token": "administration/settings/api-tokens",
# Commerce
"agreement": "commerce/agreements",
"order": "commerce/orders",
"subscription": "commerce/subscriptions",
"asset": "commerce/assets",
"request": "commerce/requests",
# Billing
"statement": "billing/statements",
"invoice": "billing/invoices",
"credit-memo": "billing/credit-memos",
# Catalog
"product": "catalog/products",
"item": "catalog/items",
"price-list": "catalog/price-lists",
# Program
"program": "program/programs",
"certificate": "program/certificates",
"enrollment": "program/enrollments",
}
path = resource_paths.get(resource_type)
if path is None:
return None # API-only resource
return f"{base_url}/{path}/{object_id}"
# Example usage
order = {"id": "ORD-8108-0372-6265", "status": "Completed"}
portal_link = get_portal_url(order, "order")
# Returns: https://portal.platform.softwareone.com/commerce/orders/ORD-8108-0372-6265# Python example
from urllib.parse import urlparse
def get_api_endpoint(portal_url):
base_api = "https://api.platform.softwareone.com/public/v1"
parsed = urlparse(portal_url)
path = parsed.path.strip("/")
# Skip 'home' as it has no API equivalent
if path == "home":
return None
return f"{base_api}/{path}"
# Example usage
portal_url = "https://portal.platform.softwareone.com/commerce/orders/ORD-8108-0372-6265"
api_endpoint = get_api_endpoint(portal_url)
# Returns: https://api.platform.softwareone.com/public/v1/commerce/orders/ORD-8108-0372-6265# Python example
def get_object_type(object_id):
prefix_map = {
# Accounts
"ACC": "account",
"BUY": "buyer",
"SEL": "seller",
"LCE": "licensee",
"USR": "user",
"UGR": "user-group",
"TKN": "api-token",
# Commerce
"AGR": "agreement",
"AST": "asset",
"ORD": "order",
"SUB": "subscription",
"REQ": "request",
# Billing
"SOM": "statement",
"INV": "invoice",
"CRD": "credit-memo",
# Catalog
"PRD": "product",
"ITM": "item",
"LST": "listing",
"AUT": "authorization",
"PRC": "price-list",
# Program
"PRG": "program",
"CER": "certificate",
"ENR": "enrollment",
# Notifications
"WBH": "webhook",
}
prefix = object_id.split("-")[0]
return prefix_map.get(prefix, "unknown")
# Example usage
object_type = get_object_type("ORD-8108-0372-6265")
# Returns: "order"The Price object is a sub-object that represents sales and purchase prices, markup, margin, and other relevant financial data. The visibility of the Price object is determined by the context in which it is included. However, certain fields are always hidden from specific users. For example, clients cannot see purchase prices.
PPxY
decimal
The yearly purchase price.
PPxM
decimal
The monthly purchase price.
PPx1
decimal
The one-time purchase price.
unitPP
decimal
The purchase price per unit in base object terms.
SPxY
decimal
The yearly sales price.
SPxM
decimal
The monthly sales price.
SPx1
decimal
The one-time sales price.
unitSP
decimal
The sales price per unit in base object terms.
markup
decimal
The markup for the base object, in percent (7.2%)
margin
decimal
The margin for base object, in percent (5.1%)
defaultMarkup
decimal
The default markup for base object (subscriptions only), in percent
currency
string
The currency of the price.
{
"PPxY": 150,
"PPxM": 12.50,
"PPx1": 290,
"SPxY": 165,
"SPxM": 13.75,
"SPx1": 300,
"markup": 10,
"margin": 9,
"currency": "USD"
}Advanced RQL patterns, pitfalls, and best practices from real-world API usage.
This page expands on the Resource Query Language with patterns and pitfalls learned from building integrations against the Marketplace Platform REST API. Use it when you need to write correct, efficient RQL and avoid common errors.
RQL filter and sort expressions only work with fields that exist on the resource. The API returns errors (for example, 'Unknown expression group' or 400 Bad Request) if you use a field name that does not exist or is not exposed for filtering.
Use the resource schema (OpenAPI or your API documentation) to see the exact property names and types for each resource.
Do not invent field names. For example, there is no generic subscriptionsCount field on agreements; the number of subscriptions is not a filterable RQL field. To get 'agreements with more than N subscriptions' you must either:
Query the child resource (for example, subscriptions) and filter by parent (for example, agreement.id).
Fetch agreements with select=+id,+name,+subscriptions.id,+subscriptions.name and compute or filter in your application.
A very common source of 400 errors is sending RQL as a single query parameter.
Many clients send this when given a params object like { "rql": "eq(status,Published)" }. The API typically responds with 400 Bad Request or 'Invalid equals shortcut expression' because it does not treat rql as a parameter whose value is the expression.
Append the RQL expression as the query string (or as the first part of it):
When you have both RQL and other parameters (like, limit, offset), combine them with &:
So in code: build the URL so that the RQL string is the first query segment; then append &limit=...&offset=... (and &select=..., &order=...) as needed. Do not put the whole RQL inside a single rql= parameter.
Wrong: rql="ilike(name,*Microsoft*) limit=20" or rql="eq(status,Active)&order=-created" — limit and order are not part of RQL; they are separate query parameters.
Correct: Send RQL as the filter only (example, ilike(name,*Microsoft*) or eq(status,Active)), and pass limit, offset, select, and order as separate parameters. The final URL will combine them: ?eq(status,Active)&limit=20&order=-audit.created.at.
ID values (such as, ACC-1234-5678, PRD-xxx, BUY-xxx, USR-xxx) must be in double quotes in RQL. Example: eq(client.id,"ACC-4402-5918"), eq(buyer.id,"BUY-1234-5678"). Unquoted IDs can return zero results.
Special characters (spaces, &, ?) in string values must be enclosed in double or single quotes: eq(firstName,"Buzz !!!").
To use a literal asterisk inside an ilike pattern, escape it: ilike(name,"The\**").
Date and audit metadata (created, updated) live under the audit object. The API behavior is:
Filtering or sorting by audit fields (such as audit.created.at, audit.updated.at) only works if the audit data is in scope for the response. That means you must include audit in the select parameter when you filter or sort by it.
If you omit select=audit (or equivalent), the API may ignore the filter or return 400.
Filter by creation date:
Sort by most recently updated:
Dates must be UTC with 3-digit millisecond precision: YYYY-MM-DDTHH:mm:ss.sssZ (for example, 2026-01-31T23:00:00.000Z). Prefer the full timestamp for precise filters; date-only (YYYY-MM-DD) may not behave as expected when comparing timestamps.
Other formats may not filter or sort correctly.
To get only the total count of resources matching a filter (such as, how many subscriptions does this agreement have?):
Call the child resource endpoint (for example, subscriptions).
Apply the filter (for example, by agreement ID via RQL or a direct filter like agreement.id=AGR-XXX if supported).
Set limit=0.
The response will have an empty data array but the correct total. This avoids transferring full payloads when you only need the number.
Example:
Response:
select=+id,+name,+status - Include only these fields in addition to the default set. Use this to keep payloads small when you know what you need.
Many resources omit large or sensitive fields by default. The response includes $meta.omitted listing properties that were not returned (for example, ["lines", "parameters", "subscriptions"]). To include one of them, add it with select=+field (for exampple, select=+lines,+parameters).
select=-metadata - Exclude a field.
Some integrations use select=-*,+id,+name,+field (exclude all, then add back only what is needed). Not all endpoints support the subtractive form; if you get 400, retry with additive only (for example, select=+id,+name,+field).
+subscriptions - Return the full nested representation of the collection.
+subscriptions.id,+subscriptions.name - Return only id and name for each nested item. Prefer this when you only need to list or count related items; it keeps responses smaller.
Many resources omit certain fields by default for performance.
They are listed in $meta.omitted in the response. Common examples: lines (order line items), parameters, subscriptions, assets, termsAndConditions, certificates, audit.
To include them, use select=+field (for example, select=+lines,+parameters).
Default limit - If you omit limit, the API may apply a large default (like, 1000). For most use cases, set an explicit limit (such as, 20–50) to avoid oversized responses and timeouts.
Maximum - The platform caps limit (often at 100). Values above the cap are treated as the cap.
Count-only - Use limit=0 to get only
When you need both the total count and a list of items, use a single request with a reasonable limit (for example, 20–50):
$meta.pagination.total gives the total count.
data gives the first page of items.
Avoid running a second request with limit=0 just to get the count if the first request already returns the total in metadata.
Sort order is specified as part of the query string, not as a separate body or header:
Ascending - order=+property or order=+audit.created.at
Descending - order=-property or order=-audit.updated.at
Example:
If you filter or sort by an audit field, include select=audit (see ).
Always use field names that exist on the resource (see section 1).
In the API, Buyer and Client have distinct meanings and ID formats:
Buyer - Legal entity; ID format BUY-xxxx-xxx. Core for billing and legal.
Client - One or more Buyers in the Client Portal; ID format ACC-xxxx-xxxx.
Filtering by Client or Buyer: To filter by Client (ACC- IDs), use client.id in RQL on resources that expose it (for example, commerce.orders, commerce.agreements): eq(client.id,"ACC-1234-5678"). To filter by Buyer (BUY- IDs), use buyer.id: eq(buyer.id,"BUY-1234-5678"). Check the resource schema to see which relationship field exists (client.id, buyer.id, etc.).
Many resources also expose externalIds (vendor, client, operations), identifiers from actors outside the marketplace. Use them to filter by external references (for example, eq(externalIds.vendor,"Microsoft-account-123") or eq(externalIds.client,"my-order-ref")) when the resource schema includes these fields. See for semantics and typical usage.
Price objects typically expose SPxM / SPxY (sales/sell price) and currency. Include currency when stating amounts. See for full field semantics and visibility rules.
For "expiring", "renewal", or "commitment end" questions, key fields are: commitmentDate (ISO 8601 UTC), terms.commitment (for example, 1y, 1m), terms.period (billing period), and autoRenew (boolean).
Filter by commitmentDate in RQL for date ranges; include select=+commitmentDate,+autoRenew,+terms (or +terms.commitment) when you need to interpret renewal vs expiry in the response.
Some resources have endpoints that require path parameters (for example, get product by id: /catalog/products/{id}).
RQL applies to list endpoints; when you need a single item by ID, use the appropriate by-id endpoint and supply the path parameter (e.g. id=PRD-1234-5678). The resource schema or API docs will indicate when path parameters are required.
If the API returns 400 or "Unknown expression" (or "Unknown expression group"):
Re-check the resource schema - The field path you used may not exist or may be nested differently (e.g. seller.country vs seller.address.country).
Quote ID values - use eq(client.id,"ACC-1234-5678") not eq(client.id,ACC-1234-5678).
Include select=audit
- Core operators and syntax.
- C# implementation reference.
$meta.pagination.total.$meta.pagination.totalPagination - Use limit and offset (or the equivalent page-based parameters if documented) to page through results.
audit.created.ataudit.updated.atUse full UTC date format - YYYY-MM-DDTHH:mm:ss.sssZ.
gt(subscriptionsCount,5) on agreements
Query subscriptions filtered by agreement.id, or fetch agreements with +subscriptions and count/filter in code.
Filtering by a field you assume exists
Check the resource schema first; use only documented fields.
order=created when the field is under audit
GET /public/v1/catalog/products?rql=eq(status,Published)GET /public/v1/catalog/products?eq(status,Published)GET /public/v1/catalog/products?eq(status,Published)&limit=20&offset=0GET /public/v1/commerce/orders?select=audit&and(gt(audit.created.at,"2024-12-01T00:00:00.000Z"),lt(audit.created.at,"2025-12-01T00:00:00.000Z"))&limit=20GET /public/v1/commerce/orders?select=+id,+name,audit&order=-audit.updated.at&limit=10GET /public/v1/commerce/subscriptions?eq(agreement.id,AGR-1234-5678)&limit=0{
"$meta": {
"pagination": {
"total": 42,
"limit": 0,
"offset": 0
}
},
"data": []
}GET /public/v1/catalog/products?order=-audit.created.at&limit=10Exact match
eq(status,Active)
Case-insensitive search
ilike(name,*Microsoft*)
Greater / less than
Use audit.created.at and include select=audit (see below).
gt(price.SPxM,100), lt(endDate,2026-12-31T23:59:59.999Z)
Multiple conditions
and(eq(status,Active),ilike(name,*Corp*))
Either condition
or(eq(type,A),eq(type,B))
In list
in(status,(Active,Updating))
Nested collection
any(groups,id=UGR-1234-5678)
Date range
and(gt(audit.created.at,"2024-01-01T00:00:00.000Z"),lt(audit.created.at,"2025-01-01T00:00:00.000Z"))
The Address object indicates a postal address. It contains the following fields:
addressLine1
string
The line 1 of the postal address.
addressLine2
string
The line 2 of the postal address.
postCode
string
The post code or ZIP code for the address.
city
string
The city or town name for the address.
state
string
The full name or abbreviation for the state.
country
string
The country code in the format.
{
"addressLine1": "123 Main Street",
"addressLine2": "Apt 4B",
"postCode": "12345",
"city": "Cityville",
"state": "S",
"country": "ST"
}Learn about Resource Query Language and how to use it.
Resource Query Language (RQL) is a query language used by the Marketplace Platform in its REST API. It's used for querying and manipulating resources in the Marketplace APIs.
With RQL, you can filter, sort, paginate, and project data. It's simple to use but flexible enough to handle complex scenarios.
RQL consists of a set of operators that can be classified into three main categories:
Comparison operators – These operators perform comparisons like equals, greater than, and so on.
Logical operators – These operators combine multiple conditions.
Algorithmic operators – These operators handle functionalities, like sorting and pagination.
Operators are formatted as operator(arg1,arg2,...). Complex expressions can be created by nesting these operators.
Let's say you want to list all users with a specific domain. Implementing filtering is essential, and this is where RQL comes in.
To display all users with the first name 'Buzz', your GET request will look like this:
The same expression can be written as:
To sort users based on their first name, your GET request will look like this:
To sort in the opposite direction, the '-' operator can be used:
To paginate your results with a limit of 10 users and to retrieve the third page (offset 20):
The first parameter limit=10 expresses the number of users to return.
The second parameter offset=20 offsets the starting position in the result set. The first 20 users will be skipped.
To request specific fields, such as firstName, lastName, and email to be included, the select=+ operator can be used:
To request certain fields to be excluded, the select=- operator can be used:
To search for all users with the first name starting with 'Bu', the following query can be used:
the operator ilike performs a case-insensitive search.
Logical operators can be used to combine multiple operators. For example, to filter users with first name 'Buzz' and last name 'Astral':
In simple cases, a combined expression can also be written in the following form:
To pass special characters (like &^$?) or whitespaces as values to RQL operators, enclose them in either double quotes (") or single quotes (') as shown in the following example:
If you need to include a quotation mark within the value, you can do so by enclosing it with a different type of quotation mark, as shown in the following example:
Allowing you to pass these special symbols as values.
The asterisk (*) character has a special meaning in the ilike operator, matching zero or more characters in its place from the parameter value. For example, the "*dog" pattern will match strings like "big dog" and "dog," but it will not match "big dog!" because of the exclamation mark.
If you need to use the asterisk (*) character itself in the pattern, you can escape it as '*', as shown in the following example:
The ilike operator in this case will be searching for the literal value “The*” at the beginning of the firstName property.
Before writing RQL, keep these in mind:
For more details and advanced patterns, see .
This section documents key findings and best practices for interacting with the SoftwareOne Platform API, derived from real-world integration and debugging experience.
The API supports standard Bearer token authentication.
Header: Authorization: Bearer <token>
One of the most critical findings is how RQL filters must be passed to the API.
Do not pass RQL as a query parameter value (like, ?rql=and(...)). This often results in 400 Bad Request , or an Invalid equals shortcut expression.
Append the RQL string directly to the URL query string.
Incorrect
Correct
You can mix RQL with standard parameters like limit and offset.
To get the count of related resources (example, "How many subscriptions does this agreement have?") without fetching all the data:
Query the Child Resource – Target the specific resource endpoint (example, /commerce/subscriptions).
Filter by Parent ID – Use a direct filter parameter if available, or RQL.
Finding: The API often accepts direct property filters like ?agreement.id=AGR-XXX.
Example Request
Response Structure
When requesting large datasets, such as full collections, the API might respond with a 302 Redirect to a file download URL (often for application/json format).
Finding – Clients must handle redirects and potentially download from a secondary URL, for example, AWS S3.
Header – Accept: application/jsonl is often used for these bulk operations.
You can filter by date ranges using ISO 8601 strings.
The any() operator is powerful for filtering based on properties of nested objects, such as, finding users in a specific group.
Be aware of metadata fields that affect data processing.
$meta.pagination.total – The total number of records matching the query (useful when limit=0).
$meta.omitted – A list of properties excluded from the response payload for security or performance reasons (like, ["credits"]).
Date fields like created and updated are typically nested within the audit object.
Finding – To filter by these dates OR see them in the response, you must explicitly select the audit object. The API will not filter by fields that are not selected/visible in the response context.
Example – ?select=audit&and(gt(audit.created.at,"2024-01-01..."))
In the API, Buyer and Client have distinct meanings and ID formats:
Buyer represents a legal entity on the platform. This is the core entity for billing and legal purposes.
ID Format – BUY-xxxx-xxx
Client represents one or multiple Buyers activated in the self-service part of the platform (Client Portal).
When filtering by Client (ACC- IDs), use client.id in RQL on resources that expose it (such as commerce.orders, commerce.agreements): eq(client.id,"ACC-1234-5678").
When filtering by Buyer (BUY- IDs), use buyer.id. Check the resource schema to see which relationship field exists.
For a C# reference implementation of RQL for .NET applications, see the GitHub repository at .
Minimize Payload – Set limit=0.
Finding: limit=0 is fully supported and recommended. It returns an empty data array but includes the correct count in $meta.pagination.total.
Read Metadata – Extract the count from the response metadata.
ID Format – ACC-1234-5678
GET /v1/accounts/users?firstName=BuzzGET /v1/accounts/users?eq(firstName,Buzz)GET /v1/accounts/users?order=firstNameGET /v1/accounts/users?order=-firstNameGET /v1/accounts/users?limit=10&offset=20GET /v1/accounts/users?select=+firstName,+lastName,+emailGET /v1/accounts/users?select=-firstName,-lastName,-emailGET /v1/accounts/users?ilike(firstName,Bu*)GET /v1/accounts/users?and(eq(firstName,Buzz),eq(lastName,Astral))GET /v1/accounts/users?firstName=Buzz&lastName=Astralor (<condition1>, <condition2>, ...)
Returns records that satisfy at least one of the specified conditions.
and (<condition1>, <condition2>, ...)
Returns records that satisfy all of the specified conditions.
GET /v1/accounts/users?firstName="Buzz !!!"GET /v1/accounts/users?firstName="Buzz with the ' Quote"GET /v1/accounts/users?ilike(firstName,"The\**")Field names
RQL filter and sort fields must exist on the resource. Do not invent field names (e.g. subscriptionsCount). Use the resource schema or API documentation to see exact field names and types.
Dates
Use UTC with 3-digit millisecond precision: YYYY-MM-DDTHH:mm:ss.sssZ (for example, 2026-01-31T23:00:00.000Z).
Audit fields
GET /resource?rql=and(eq(status,Active),ilike(name,*Microsoft*))GET /resource?and(eq(status,Active),ilike(name,*Microsoft*))GET /resource?and(eq(status,Active))&limit=100&offset=0GET /commerce/subscriptions?agreement.id=AGR-1234-5678&limit=0{
"$meta": {
"pagination": {
"total": 42, <-- The value you want
"limit": 0,
"offset": 0
}
},
"data": []
}GET /billing/invoices?select=audit&and(gt(audit.created.at,"2024-12-01T08:00:00.000Z"),lt(audit.created.at,"2026-01-01T08:00:00.000Z"))GET /accounts/account-users?any(groups,id=UGR-1234-5678)not (<condition>)
Returns records that do not satisfy the specified condition.
empty ( )
Constant that is used to represent an empty string. Example: /users?firstName=empty()
null ( )
Constant that is used to represent an unassigned ("null") value. Example: /users?firstName=null()
order = +<property1>,-<property2>, ...
Sorts the returned records by <property>. + represents the ascending order, while - represents the descending order.
select = +<property1>, -<property2>, ...
Used to add and remove certain objects from the representation.
offset = <value>
Offsets the starting position in the resulting set.
limit = <value>
Limits the number of returned records by the specified value.
eq (<property>, <value>)
Filters records where <property> exactly matches the <value>.
ne (<property>, <value>)
Filters records where <property> does not match the <value>.
gt (<property>, <value>)
Filters records where <property> is greater than the <value>.
ge (<property>, <value>)
Filters records where <property> is greater or equal to the <value>.
lt (<property>, <value>)
Filters records where <property> is less than the <value>.
le (<property>, <value>)
Filters records where <property> is less than or equal to the <value>.
ilike (<property>, <value>)
Filters records where <property> contains <value> as a substring, the comparison is case-insensitive.
in (<property>,(<value1>,<value2>,...))
Filters records where <property> matches any of the listed <value>s.
out (<property>,(<value1>,<value2>,...))
Filters records where <property> matches none of the listed <value>s.
any (<collection>, <condition>)
Filters records by applying <condition> to the nested <collection> .
all (<collection>, <condition>)
Filters records by applying <condition> to the nested <collection> .
When filtering or sorting by audit.created.at, audit.updated.at, etc., you must include audit in the select parameter (e.g. select=audit or select=+id,+name,audit). The API will not filter by fields that are not selected.
Counting
Use limit=0 to get only the count: the response has an empty data array and the total in $meta.pagination.total.
Limit
Prefer a reasonable limit (like, 20–50) for list queries. Maximum is 100 (values above 100 are capped). For count-only, use limit=0.
Select
Use select=+id,+name,+field to include only needed fields (smaller payloads). To include omitted fields (see $meta.omitted), use select=+field. For nested collections, +subscriptions.id,+subscriptions.name returns only id and name per item; +subscriptions returns the full nested representation.
Order in URL
Order is part of the query string: ?order=-audit.created.at&limit=10. Do not send RQL as a single query parameter (see below).
RQL vs parameters
Do not put limit or order inside the RQL string. RQL is only the filter expression; limit, offset, select, and order are separate query parameters.
IDs in RQL
When filtering by ID fields (like, client.id, buyer.id, agreement.id), use double-quoted values eq(client.id,"ACC-1234-5678"). Unquoted IDs can return no results.
This topic lists all business objects available in the SoftwareOne Marketplace REST API and the corresponding API collection endpoints used to access them.
Use this page as a centralized reference to identify the correct object types and endpoints when designing integrations or reviewing platform capabilities.
Every object in the Marketplace Platform has a unique identifier with a prefix that indicates the object type. Use these prefixes to quickly identify what kind of object you are working with:
ACC-
ACC-1234-5678
BUY-
BUY-5171-6994
CLT-
CLT-1976-5289
ERP-
ERP-1456-2363-9856
LCE-
LCE-8499-1473-5603
MOD-
MOD-1234
SEL-
SEL-6685-4945
USR-
USR-3758-7092
UGR-
UGR-0601-5102
TKN-
TKN-9299-7556
AET-
AET-8784-9237
AUD-
JOA-
JOA-4710-3489
CHG-
PRD-
PRD-2689-4589
AGR-
AGR-5896-1479-0269
ORD-
CUR-
CUR-1234-4678
FXP-
EXT-
EXT-5984-1232
EXC-
WBH-
WBH-5987-1258
NTC-
PRG-
PRG-7432-9033
PPG-
SPO-
SPO-<5694>-<8956>-<1010>-<3975>-<2134>
SPQ-
/public/v1/accounts/accounts
/public/v1/accounts/buyers
/public/v1/audit/event-types
/public/v1/audit/records
/public/v1/billing/credit-memos
/public/v1/billing/custom-ledgers
/public/v1/catalog/products
/public/v1/catalog/products/{id}/items
/public/v1/commerce/agreements
/public/v1/commerce/orders
/public/v1/integration/extensions
/public/v1/integration/categories
/public/v1/notifications/webhooks
/public/v1/notifications/categories
/public/v1/program/programs
/public/v1/program/programs/{id}/parameter-groups
/v1/spotlight/objects
AUD-5681-1729-3068-0895
CHG-5841-6913-2879-2010-9301
CRD
CRD-8280-7533-0235-8348
CRL-
CRL-5974-2302-1490-9437
CLE-
CLE-5974-2384
INV-
INV-2078-0901-9457-5058
INL-
INL-4836-8218-0290-3679
BJO-
BJO-7823-5971
BLE-
BLE-5694-5681
BOV-
BOV-5895-8712
SOM-
SOM-6005-1054-1535-5364
ITM-
ITM-2598-1496-3258
IGR-
IGR-5895-5343-9056
PGR-
PGR-3452-0864-2005
PAR-
PAR-6064-5794-1256
MED-
MED-8053-5894-1289
DOC-
DOC-5841-7434-9044
TCS-
TCS-1795-2689-9856
TPL-
TPL-0215-9943-4590
PRC-
PRC-8485-1289-3478
PRI-
PRI-5804-4357-0742-1065
LST-
LST-9635-2894
AUT-
AUT-8914-4365
UNT-
UNT-5892
PRP-
PRP-5634-4806-1075
PPA-
PPA-6324-1708-0298-3578
ORD-5879-2698-3893
SUB-
SUB-1548-1246-0954
REQ-
REQ-7319-1974-9054
ALI-
ALI-6199-1408-4789-1964
AST-
AST-5971-3179-2597
FXP-1234-4678
FXR-
FXR-1234-4678-0000-0001
EXC-7310
EDM-
EDM-9741-3001-2984
EXM-
EXM-5674-1974-2684
ETC-
ETC-2697-1456-9745
ETV-
ETV-2358-0125-3789-1158
INS-
INS-5684-3645-8945-2156
EXI-
EXI-8945-2589-6485
NTC-2987-6471
CTT-
CTT-8925-0193
MST-
MST-5874-3684-5986
MSG-
MSG-2589-4597-5689-2689
NTS-
NTS-5987-0126-9125
PPG-6456-5841-9785
PPM-
PPM-2589-6489-2587
PMD-
PMD-2486-8946-2547
PDM-
PDM-2686-7895-2389
PTC-
PTC-1478-6974-2569
PTV-
PTV-2599-3474-2579-2395
PTM-
PTM-5977-5689-4785
CER-
CER-9845-5647-2387
ENR-
ENR-3795-5796-1254
ENA-
ENA-9025-3547-8914-2368
SPQ-2565-5895
Not applicable
Not applicable
/public/v1/accounts/cloud-tenants
/public/v1/accounts/erp-links
/public/v1/accounts/licensees
/public/v1/modules
/public/v1/accounts/sellers
/public/v1/accounts/tokens
/public/v1/accounts/users
/public/v1/billing/invoices
/public/v1/billing/journals
/public/v1/billing/ledgers
/public/v1/billing/overrides
/public/v1/billing/statements
/public/v1/catalog/products/{id}/item-groups
/public/v1/catalog/products/{id}/parameter-groups
/public/v1/catalog/products/{id}/parameters
/public/v1/catalog/products/{id}/media
/public/v1/catalog/products/{id}/documents
/public/v1/catalog/products/{id}/terms
/public/v1/catalog/products/{id}/templates
/public/v1/catalog/items
/public/v1/catalog/price-lists
/public/v1/catalog/price-lists/{id}/items
/public/v1/catalog/listings
/public/v1/catalog/authorizations
/public/v1/catalog/units-of-measure
/public/v1/catalog/pricing-policies
/public/v1/commerce/subscriptions
/public/v1/commerce/requests
/public/v1/commerce/assets
/public/v1/integration/extensions/{id}/documents
/public/v1/integration/extensions/{id}/media
/public/v1/integration/extensions/{id}/terms
Hosting
/public/v1/integration/hosting
/public/v1/integration/instances/{eid}
/public/v1/integration/installations
/public/v1/notifications/contacts
/public/v1/notifications/batches
/public/v1/notifications/messages
/public/v1/notifications/subscribers
/public/v1/program/programs/{id}/parameters
/public/v1/program/programs/{id}/media
/public/v1/program/programs/{id}/documents
/public/v1/program/programs/{id}/terms
/public/v1/program/programs/{id}/templates
/public/v1/program/certificates
/public/v1/program/enrollments
Filter, sort, and paginate API responses.
Understand how API endpoints are structured.
Understand API errors and status codes.
Explore shared objects used across multiple APIs.
Browse business objects and their API collection endpoints.
Review shared object definitions used across Marketplace APIs.
The External IDs object contains a set of external identifiers.
External IDs are assigned during a PUT (update) or POST (create) request. Clients can update only their own external IDs, vendors can update only their own external IDs, and SoftwareOne Operations can update only the ID related to their specific operation.
Many resources (agreements, orders, subscriptions, etc.) expose a externalIds property. It stores key identifiers from actors that interact with the object but are not part of the marketplace (vendor, client, operations). Each actor can set and see only their own key; the meaning of each key depends on the resource and the actor.
externalIds.vendor - On agreements and related resources, the vendor often stores the external unique identifier of the contract in their system (for example, Microsoft account ID, Adobe client ID). Use it to correlate platform objects with vendor-side contracts or systems.
externalIds.client - The client can use this for programmatic access or to store a reference that matters on their side (for example, blanket order ID, open order ID, or an internal reference). Useful when looking up an order or agreement "by our reference" or "by our ID".
externalIds.operations
Which keys exist and who can read/write them depends on the resource and the caller; check the resource schema and visibility rules. To filter by an external ID in RQL, use the field path (for example) eq(externalIds.vendor,"ABC-123") or eq(externalIds.client,"my-ref-456")) when the resource exposes it.
externalIds.client
string
The client-specific external ID, visible to clients.
externalIds.operations
string
The operations-specific external Id, visible to operations.
externalIds.vendor
string
The vendor-specific external Id, visible for vendors.
{
"client": "12345678",
"operations": "07bf766b-c767-4293-9ab3",
"vendor": "ABC-2023-C07-dbeee0b302c0"
}The Parameter object contains the value of the given parameter along with additional information, such as constraints and validation errors.
id
string
(Read-only) Primary identifier for the parameter.
Parameter Constraints define the overridden behavior of a parameter.
Parameter Group is used to visually split different types of parameters.
View the state transition diagrams for various objects in the platform.
View state diagrams for Marketplace Platform objects.
These objects support workflows between , such as clients, partners, and vendors.
This page includes objects that move through statuses during their lifecycle. Objects without statuses, such as audit records and spotlight resources, are not included.
Open a section to view the available diagrams for each API.
required
bool
The parameter value is required.
unique
bool
The parameter value is unique.
name
string
(Read-only) Display name for the parameter.
externalId
string
(Read-only) The ID of the parameter within the external system.
value
string
(Optional) The parameter's value that can be updated.
displayValue
string
(Read-only) (Optional) Read-only value for the parameter.
constraints
object
(Optional) Represents the parameter constraints object.
If specified, the value represents overridden parameter constraints.
If unspecified, parameter constraints must be taken from the parameter definition.
error
object
(Optional) Represents the error object.
readonly
bool
The parameter can only be viewed.
hidden
bool
ordering
Parameter []
(Optional) Array of ordering parameters.
fulfillment
Parameter []
The parameter is hidden and must not be shown to the user.
(Optional) Array of fulfillment parameters.
{
"id": "PRM-1234-1234-1234-1234",
"name": "Tenant Id",
"externalId": "tenant_id",
"constraints": {
"readonly": false,
"hidden": true,
"required": true,
"unique": false
},
"value": "69b73824-ce76-4866-ad47-b615ae9d8998",
"error": {
"id": "E001234",
"message": "Incorrect parameter value"
}
}{
"readonly": false,
"hidden": true,
"required": true,
"unique": false
}{
"ordering": [...],
"fulfillment": [...]
}The Date Range Parameter Value is an object used in the Marketplace APIs to represent a range between two dates. This object has two fields.
start
string
The start date of the range.
end
string
The end date of the range.
{
"start": "2019-02-10",
"end": "2023-01-01"
}The Terms object represents billing terms for a subscription within the Marketplace. This object contains the following fields:
model
string
The billing model for the subscription. Allowed values are:
One-time
Usage
Quantity
period
string
The billing period applicable to the subscription. Allowed values are:
1m - indicates monthly billing.
1y - indicates annual billing.
one-time - indicates a one-time purchase.
commitment
string
The commitment or renewal period for the subscription.
<N>m - N months commitment
<N>y - N years commitment
{
"model": "quantity",
"period": "1m",
"commitment": "1y"
}The Audit object records events related to the object. Each event contains two key components: 'at,' which specifies the last time the event occurred, and 'by,' which indicates who performed the event.
Events do not represent the complete history of the object. They are a cache that retains only the most recent occurrence of each type of event. For example, if an order is updated multiple times, only the latest update will be reflected in the Audit object.
Events cannot be set directly through API calls, which means they are ignored in input during both creation (POST) and update (PUT) operations.
Events can be either common or specific to the object. In such cases, they should follow the state diagram of the object. The same operation can be reflected in multiple events if it is logically reasonable. For example, if an order is approved and some data within the order has changed in one operation, both the updated and approved events must be recorded.
<event>
object
(Read-only) (Optional) Indicates when the last event occurred and the event's initiator. If the event has not occurred yet, the entire object (along with its key) is omitted from the audit object.
<event>.at
dateTime
The date and time of the event in the ISO-8601 format.
<event>.by
object
(Optional) Represents the or the that initiated the action.
{
"audit": {
"created": {
"at": "2023-12-14T17:28:57Z",
"by": {
"id": "USR-1234-1234-1234",
"name": "John Smith",
"icon": "/static/users/UR-1234-1234-1234.icon.svg"
},
"of": {
"id": "ACC-1234-1234",
"href": "/accounts/accounts/ACC-1234-1234",
"name": "Microsoft",
"icon": "/static/ACC-1234-1234/account.png"
}
},
"updated": {
"at": "2023-12-14T17:28:57Z",
"by": {
"id": "UR-1234-1234-1234",
"name": "John Smith",
"icon": "/static/users/UR-1234-1234-1234.icon.svg"
},
"of": {
"id": "ACC-1234-1234",
"href": "/accounts/accounts/ACC-1234-1234",
"name": "Microsoft",
"icon": "/static/ACC-1234-1234/account.png"
}
}
}
}<event>.of
(Optional) Represents the account on behalf of which the action was executed.
The Single date parameter value object represents a date-based parameter value
date
date
The date value in ISO format (YYYY-MM-DD).
{
"date": "2019-02-10"
}