Errors & Troubleshooting
Every response from the SMBcrm API uses a standard HTTP status code, and every error response adds a small JSON body describing what went wrong. This page lists the status codes you’ll see, the shape of that body, and the fix for the problems developers hit most often.
HTTP status codes
Section titled “HTTP status codes”| Status | Meaning | Typical cause |
|---|---|---|
200 OK / 201 Created |
Success | The request completed; 201 comes back when a resource was created. |
400 Bad Request |
Malformed request | Invalid JSON, a parameter of the wrong type, or a malformed query string. |
401 Unauthorized |
Not authenticated | Missing, invalid, or expired token, or a missing Version header. |
403 Forbidden |
Not authorized | The token is valid but doesn’t have the scope this endpoint requires. |
404 Not Found |
No such resource | The ID doesn’t exist, belongs to a different account/location, or was deleted. |
409 Conflict |
Conflicting state | The request conflicts with the resource’s current state, for example, a duplicate. |
422 Unprocessable Entity |
Validation error | The JSON is well-formed but fails validation: a required field is missing or invalid. |
429 Too Many Requests |
Rate limited | You’ve exceeded the account’s burst or daily rate limit. |
5xx |
Server error | Something went wrong on SMBcrm’s side. Safe to retry with backoff. |
The error response body
Section titled “The error response body”Error responses are JSON, with a status code, a human-readable message, and the standard HTTP error name:
{ "statusCode": 422, "message": "locationId is required", "error": "Unprocessable Entity"}Common problems and fixes
Section titled “Common problems and fixes”401 Unauthorized
Section titled “401 Unauthorized”Start with the two things every request needs:
- The
Authorizationheader is present and correctly formatted:Authorization: Bearer <token>, with a real token in place of the placeholder and no extra quotes or surrounding whitespace. - The
Versionheader is present:Version: v3. A request missing this header can be rejected before your token is even checked.
curl -i https://services.smbcrm.com/contacts/<contact_id> \ -H "Authorization: Bearer <token>" \ -H "Version: v3"If both headers are correct, the token itself is the problem.
403 Forbidden
Section titled “403 Forbidden”A 403 means authentication succeeded but authorization didn’t. The token is valid, but it
wasn’t issued with the scope this endpoint requires. Every endpoint in this reference lists
its required scope in the scope field of its endpoint block.
Fix it at the source of the token:
- Private Integration Token: generate a new one with the missing scope added.
- OAuth: re-run authorization requesting the additional scope; the user sees it on the consent screen.
See Scopes for the full list of scopes and what each one grants.
422 Unprocessable Entity
Section titled “422 Unprocessable Entity”The request reached the API and parsed as JSON, but failed validation. Read message first:
it names what’s wrong. The most common causes are:
- A required field is missing, most often
locationId. - A field has the wrong type or format, for example, a date that isn’t ISO 8601, or a phone number without a country code.
- A value doesn’t match what the endpoint expects, such as an invalid ID reference or an out-of-range option.
Compare your request body against the example on the endpoint’s own page and confirm every required field is present before you retry.
429 Too Many Requests
Section titled “429 Too Many Requests”You’ve exceeded the account’s rate limit. Back off before retrying: resending immediately just extends the throttling window.
Every response carries your current rate-limit status in its headers, so you can slow down
proactively instead of reacting after a 429. See
Base URL & Headers for the full list of rate-limit headers and how
to read them. Where an endpoint supports it, batch requests, cache values that rarely change,
and prefer webhooks over polling.
CORS errors in the browser
Section titled “CORS errors in the browser”If a request works from your server but fails from browser JavaScript with a CORS error (or no response at all), that’s the gateway’s cross-origin policy, not your token. Call the API from your server instead. This also keeps the token out of client-side code, which you should be doing regardless. See Token Safety.
Other statuses at a glance
Section titled “Other statuses at a glance”400 Bad Request: usually malformed JSON or a parameter of the wrong type; validate the request body before it’s sent.404 Not Found: double-check the ID in the path and confirm it belongs to the account/location your token is scoped to.409 Conflict: the request conflicts with the resource’s current state, for example creating a duplicate; re-fetch the resource and reconcile before retrying.5xx: transient; retry with backoff. If it persists, gather the details below before you reach out.
Debugging tips
Section titled “Debugging tips”When a request doesn’t behave the way you expect, capture these before you dig further:
- The response status and full body. The
messagefield almost always tells you exactly what’s wrong, so don’t rely on the status code alone. - Any request or trace identifier header on the response, if one is present. Include it if you need to escalate.
- The base URL and
Versionheader you actually sent. A surprising number of errors turn out to be a typo’d host or a missing header, not a real API problem.
curl -i https://services.smbcrm.com/contacts/<contact_id> \ -H "Authorization: Bearer <token>" \ -H "Version: v3"const res = await fetch('https://services.smbcrm.com/contacts/<contact_id>', { headers: { Authorization: `Bearer ${token}`, Version: 'v3', },});
const body = await res.json().catch(() => null);console.log(res.status, JSON.stringify(body));-i (cURL) and logging res.status next to the parsed body (Node.js) both surface the real
status line, even on responses your JSON client would otherwise swallow on error.
Related
Section titled “Related”- Base URL & Headers: required headers, versioning, and the full list of rate-limit response headers.
- Scopes: the scope each endpoint needs, and how to add one to an existing token.
- OAuth (account access): refresh an expired access token.
- Token Safety: call the API server-side instead of from the browser.
