Creates a new Multitenant Mobile App Identifier with an initial version.
POST /api/configuration/multitenant-mobile-app-identifier
Success: 201 Created
- Products: Gladstone Admin Areas (
ADMIN) - Features: not restricted by feature
Overview
Registers a multi-tenant mobile app — one app binary in the App Store or Play Store that many Gladstone operators share — and creates its first version in the same call. Each version is issued a secret that the app uses to sign requests, so this call is how an app build gets the credential it needs before it can look up which operator's environment a user belongs to.
Two records are created together, all-or-nothing: the identifier, keyed on the app's bundle id, and one version under it holding the version string and a generated appSecret. If either cannot be saved, neither is kept and you get a 500 — there is no partially created identifier to clean up.
You do not choose either identifier. The response is 201 Created carrying the identifier id, the values you sent, and a one-element versions array containing the new version's id and its appSecret. There is no usable Location header; read the ids from the body.
appBundleId is unique across the whole system, compared case-insensitively. A second call with the same bundle id — in any casing — returns 409 Conflict rather than creating a duplicate or overwriting the first, so a blind retry after a timeout is safe but tells you nothing about whether the original succeeded. Confirm with Retrieve all multitenant mobile app identifiers, which also returns the secrets, so a secret lost in a dropped response can be recovered rather than rotated.
Note what this call does not do. It creates the app registration only; it does not connect it to any operator environment — for that, use Update an environment's multitenant mobile app identifier versions. Adding a second version to an existing identifier is a different endpoint (POST /api/configuration/multitenant-mobile-app-identifier/{id}/version) that accepts only the api scope, so partner integrations can create identifiers and read them back but cannot add versions to, update or delete them afterwards.
Endpoint
POST {base_url}/api/configuration/multitenant-mobile-app-identifier
{base_url} is the environment URL issued to your integration. See Authenticating with Gladstone APIs.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
appBundleId | string | Yes | The mobile app's platform bundle identifier — the iOS bundle id or Android application id, such as com.example.leisure. This is the natural key: it is what a running app sends when it asks which environment a PIN or company name belongs to, and how the platform finds the secrets to check the signature. Maximum 255 characters, must not be blank (AppBundleId is required.) and must contain no whitespace anywhere (AppBundleId cannot contain whitespace.). Unique across all identifiers, compared case-insensitively, so com.example.app clashes with COM.EXAMPLE.APP. The casing you send is the casing stored. |
oneSignalAppId | string | Yes | The app's OneSignal application id, used to address push notifications to installs of this app. Required — there is no way to register an identifier without one — and maximum 50 characters. Stored and returned as sent; not validated against OneSignal, so a typo surfaces only when notifications fail to arrive. |
appVersion | string | Yes | The version string of the first app build being registered, in dotted numeric form: major.minor, optionally with .build and .revision, for example 1.0 or 2.4.1.3. Numeric parts only — anything else, including v1.0, 1.0.0-beta and a bare 1, fails with AppVersion must be in a valid format (major.minor[.build[.revision]]). Provided: {value}. Maximum 50 characters, must not be blank and must contain no whitespace. This matters beyond bookkeeping: when an app signs a request it sends its own version, and the platform accepts signatures made with the secret of any registered version less than or equal to that version — so older builds keep working while newer ones get their own secret. Register each shipped build as its own version. |
Sample request
curl -X POST '{base_url}/api/configuration/multitenant-mobile-app-identifier' \
-H 'Authorization: Bearer {accessToken}' \
-H 'X-Use-SSO: true' \
-H 'Content-Type: application/json' \
-d '{
"appBundleId": "com.example.leisure",
"oneSignalAppId": "b2f7f966-d8cc-11e4-bed1-df8f05be55ba",
"appVersion": "1.0"
}'Response fields
| Field | Type | Description |
|---|---|---|
id | integer (int32) | The identifier's system-generated id. Use it in the per-identifier routes — adding a version, updating and deleting all address the identifier as {id}, not by bundle id. |
appBundleId | string | The bundle id as stored, echoed back unchanged from the request. |
oneSignalAppId | string | The OneSignal application id as stored, echoed back unchanged from the request. |
versions | array of object | The identifier's versions. On this call it always contains exactly one entry — the initial version built from appVersion. Later calls to the add-version endpoint extend it, and Retrieve all multitenant mobile app identifiers returns the full set when asked with includeVersions=true. |
versions[].id | integer (int32) | The version's system-generated id, separate from the identifier's id. It is the {id} used by the version update and delete routes. |
versions[].appVersion | string | The version string as stored, echoed back unchanged from the request. |
versions[].appSecret | string | The HMAC signing secret generated for this version — 256 cryptographically random characters drawn from A–Z, a–z, 0–9, - and _. You cannot supply or choose it, and there is no rotate operation: to change it, delete the version and create it again. Embed it in the matching app build; the app signs the raw JSON body of an environment-search request with HMAC-SHA256 and sends the result Base64-encoded in the X-HMAC-Signature header. Treat it as a credential — it is returned in full by the identifier GET endpoints, so anyone who can call those can sign as the app. |
Sample response
{
"id": 12,
"appBundleId": "com.example.leisure",
"oneSignalAppId": "b2f7f966-d8cc-11e4-bed1-df8f05be55ba",
"versions": [
{
"id": 34,
"appVersion": "1.0",
"appSecret": "qX3n_Tk9…"
}
]
}Errors
Checks run in a fixed order: request validation, then the whitespace checks, then the duplicate bundle id check, and only then the version format check. A request that is both a duplicate and badly versioned therefore returns 409, not 400.
| Status | Meaning | When |
|---|---|---|
400 | Required field missing | AppBundleId is required., OneSignalAppId is required. or AppVersion is required.. A missing or null field is caught by request validation and returned as a validation problem document (application/problem+json) with an errors map keyed by field name, before any other check. |
400 | Field too long | AppBundleId cannot exceed 255 characters., OneSignalAppId cannot exceed 50 characters. or AppVersion cannot exceed 50 characters.. Also returned as a validation problem document. |
400 | Whitespace in appBundleId | AppBundleId cannot contain whitespace. — any whitespace character anywhere in the value, not just leading or trailing. The value is not trimmed for you. |
400 | Whitespace in appVersion | AppVersion cannot contain whitespace. — same rule as above. |
400 | Version string not parseable | AppVersion must be in a valid format (major.minor[.build[.revision]]). Provided: {value} — the value is not a dotted numeric version. A bare major number such as 1 fails this check. |
409 | Bundle id already registered | An identifier already exists with AppBundleId '{value}'. — matched case-insensitively against every existing identifier. Fetch the existing record instead of retrying. |
403 | Forbidden | The access token does not satisfy this endpoint's requirements — the ADMIN product and the cr.co permission — or its scope is neither api nor partner. |
500 | Internal server error | The identifier and its first version could not be saved, so nothing was created; or another unexpected server-side failure. The response body is empty. |