The Nymble Commerce API is a REST API that accepts JSON request bodies and returns JSON responses. All endpoints require authentication except the login and public address lookup endpoints. You interact with the API by sending HTTP requests to a base URL and including your credentials in the request headers.
Base URLs
Use the production base URL for live traffic and the sandbox base URL for development and testing.
| Environment | Base URL |
|---|
| Production | https://api.achievemomentum.com |
| Sandbox | https://api-dev.achievemomentum.com |
Point your integration at the sandbox environment first. The sandbox is a full copy of the production API with isolated data, so you can test freely without affecting live records.
Authentication
The Nymble Commerce API supports two authentication methods. Use whichever method suits your integration.
Bearer token (JWT)
After you call POST /api/auth/login, you receive a JWT access token. Pass it in the Authorization header on every subsequent request:
curl https://api.achievemomentum.com/api/organization \
-H "Authorization: Bearer {your_access_token}"
API key
Some machine-to-machine integrations use a static API key instead of a short-lived JWT. Pass it in the x-api-key header:
curl https://api.achievemomentum.com/api/organization \
-H "x-api-key: {your_api_key}"
You can obtain an API key by calling POST /api/organizations/api-access from an Admin-scoped token. API keys do not expire but should be rotated periodically and stored securely — treat them like passwords.
Send all request bodies as JSON and set the Content-Type header accordingly:
curl -X POST https://api.achievemomentum.com/api/users \
-H "Authorization: Bearer {your_access_token}" \
-H "Content-Type: application/json" \
-d '{"FirstName": "Jane", "LastName": "Smith", "Email": "[email protected]"}'
Exceptions: File upload endpoints use multipart/form-data. The reference page for each such endpoint calls this out explicitly.
Successful responses use standard HTTP status codes:
| Code | Meaning |
|---|
200 OK | The request succeeded. The response body contains the result. |
201 Created | A new resource was created. The response body contains the created object. |
204 No Content | The request succeeded but there is no response body (e.g. a delete operation). |
Resource endpoints return the created or updated object directly. List endpoints return an array wrapped in a response envelope. A typical successful response looks like this:
{
"data": [...],
"totalCount": 42
}
A typical single-resource response:
{
"organizationId": "org_abc123",
"name": "Acme Corp",
"slug": "acme-corp"
}
Organization scoping
Nymble Commerce is a multi-tenant platform. Every request is automatically scoped to your organization via claims embedded in your JWT. You do not need to pass OrganizationId as an explicit body or query parameter on most endpoints — the API reads it directly from your token.
JWT claims (set automatically)
├── OrganizationId → scopes data to your org
├── PriceTier → applied to pricing lookups
├── CurrencyCode → applied to monetary values
└── CustomerNumber → linked customer account
Some admin-path endpoints include the organization identifier in the URL for clarity (e.g. GET /api/organization). In those cases the path parameter or query value must match the OrganizationId in your token, unless you hold a Super role.
List endpoints accept the following query parameters:
| Parameter | Type | Default | Description |
|---|
PageNumber | integer | 1 | Page number (1-indexed) |
PageSize | integer | 25 | Number of records per page |
The response includes the current page of records alongside a total count so you can calculate total pages client-side:
{
"Data": [
{ "...": "..." }
],
"TotalCount": 150,
"PageNumber": 1,
"PageSize": 25
}
To iterate all records, keep requesting the next page until the length of Data is less than PageSize.
Rate limits
| Endpoint | Limit |
|---|
POST /api/auth/login | 10 requests / minute per ClientId |
Public endpoints (e.g. GET /api/users/exists) | 10 requests / minute per IP |
| All other authenticated endpoints | No hard limit (fair use applies) |
When you exceed a rate limit the API returns 429 Too Many Requests. Retry after the interval indicated in the Retry-After response header.
Cache your access token and reuse it until it expires rather than authenticating on every request. Repeated login calls using the same ClientId are throttled aggressively.
Idempotency
For bulk-create endpoints, passing an ExternalId field makes the operation idempotent. If you send the same ExternalId more than once, the API updates the existing record rather than creating a duplicate:
{
"ExternalId": "your-system-id-9001",
"CustomerNumber": "C-10042",
"UserId": "kp_abc123"
}
This lets you safely retry failed requests without worrying about creating duplicate records.
Error handling
When a request fails, the API returns a problem details object following RFC 9457. See the Error Reference page for the full list of error codes and guidance on handling each one.
A typical error response:
{
"type": "https://httpstatuses.com/400",
"title": "Bad Request",
"status": 400,
"errors": [
{
"name": "Email",
"reason": "'Email' must not be empty."
}
]
}
| Field | Description |
|---|
status | The HTTP status code |
title | A short human-readable summary of the error |
errors | Array of field-level validation failures, when applicable |