Errors
When something goes wrong, MarginFront returns an HTTP status code and a JSON body describing what happened. This doc translates the most common ones from developer-speak into plain English, plus how to fix each one.The shape of an error response
Every error looks roughly like this:message is usually the most helpful — it tells you exactly which field is wrong and why.
For server errors (500s), message is often a generic string; the actual problem is on MarginFront’s side and the response won’t tell you how to fix it (because it’s not your fault).
400 Bad Request
What happened: Something in your request is malformed. Usually a missing required field or a field with the wrong type.
Most common causes:
- You forgot a required field (check the resource’s doc for which fields are required)
- A UUID field isn’t a valid UUID format
- A date field isn’t valid ISO 8601
- An enum field has a value that isn’t in the allowed list
- An email field isn’t a valid email
message field — it usually names the specific field that’s wrong. Fix it and retry.
Example:
name, fix the agentId to be a valid UUID.
401 Unauthorized
What happened: Your API key is missing, malformed, or wrong.
Most common causes:
- You forgot the
x-api-keyheader entirely - The header name is wrong (e.g., using
Authorization: Bearer— that’s for JWT tokens, not API keys) - The API key is from a different environment (test vs live)
- The API key was revoked in the dashboard
- A typo when copy-pasting the key
- Double-check the header is exactly
x-api-key: mf_sk_... - Copy a fresh key from the dashboard
- Re-export it:
export MF_API_SECRET_KEY="..." - Try again
403 section below.
403 Forbidden
What happened: Your API key is valid, but you’re trying to do something it’s not allowed to do.
Most common causes:
- You used a publishable key (
mf_pk_*) on a write operation. Publishable keys are read-only by design — POST/PUT/PATCH/DELETE are rejected. Use a secret key (mf_sk_*) for writes. - You hit an endpoint that requires a human user session (not an API key). These include:
GET /v1/users/mePOST /v1/invitations/accept/:token- Team invitation endpoints
- A few org management actions
- If the response message mentions “publishable keys cannot perform write operations”, switch to a secret key. See authentication.md for the key type reference.
- If the endpoint is a “user-scoped” endpoint, you can’t use an API key — you need to be logged in as a human via the dashboard instead.
404 Not Found
What happened: The thing you’re trying to read/update/delete doesn’t exist.
Most common causes:
- Wrong UUID in the URL (typo, or using an old deleted record’s ID)
- The record exists but in a DIFFERENT org than yours
- You’re creating a subscription but the
customerId/agentId/planIdyou reference doesn’t exist - The URL itself is wrong (e.g., typo in the resource name)
- Double-check the ID by listing the resource first and finding the correct ID
- Verify the ID belongs to your org (if you’re using a different API key than usual, make sure it’s pointing at the same org)
- Check the URL for typos
409 Conflict
What happened: The thing you’re trying to create already exists, or your update would violate a uniqueness constraint.
Most common causes:
- Creating a customer with an
externalIdthat already exists in this org - Creating an agent with an
agentCodethat already exists in this org - Creating a signal with a name that already exists for that agent
- Deleting an agent/customer/plan that still has dependent records (e.g., deleting a customer that has an active subscription)
- For duplicate
externalId/agentCode/ name: either pick a different one, or update the existing record instead of creating a new one - For delete-with-dependents: delete or reassign the dependent records first, then retry the delete
422 Unprocessable Entity
What happened: Your request was structurally valid (valid JSON, required fields present), but the combination of values doesn’t make sense.
Most common causes:
- Creating a subscription with an
endDateearlier than thestartDate - Billing cycle math that doesn’t work (e.g.,
billingCycle: "custom"withoutcustomCycleDays) - An
agentIdthat belongs to a different org than the customer
message field carefully — it’ll describe the specific inconsistency.
429 Too Many Requests
What happened: You’re hitting the API faster than the rate limit allows.
How to fix:
- Slow down your request rate
- If logging usage events, batch them (up to 100 per call) instead of one per request
- Check response headers for
Retry-Afterto see how long to wait
500 Internal Server Error
What happened: Something broke on MarginFront’s side. This is NOT your fault.
Most common causes:
- A bug in MarginFront’s code
- A database connection issue
- An upstream service (Stripe, Resend, etc.) being unavailable
- Retry once after a few seconds — transient errors are common
- If it persists, email
team@marginfront.comwith:- The exact URL and method you called
- The request body (with any API keys redacted)
- The full error response body
- A timestamp (roughly when you saw the error)
502 / 503 / 504 — Gateway errors
What happened: MarginFront’s API is temporarily unreachable or down.
How to fix:
- Wait a minute and retry
- Check MarginFront’s status page if one exists
- If it’s sustained, email
team@marginfront.com
”I get a response but no body”
A few endpoints return an empty body on success (typicallyDELETE returning 204 No Content). That’s expected — the status code is the real signal, not the body.
If you expected a body and got nothing on a different status code, treat it as a bug and report it.
”The error message mentions a field I didn’t send”
This usually means a required field is missing, or a field you sent has the wrong type. The error’smessage array tells you exactly which field — read it carefully and cross-reference with the resource’s doc file (e.g., customers.md) for the required and optional fields.
Response-level error codes (inside a 200 OK)
Some endpoints — particularly POST /v1/usage/record — return 200 OK even when individual records in a batch fail. The failures appear in the results.failed[] array in the response body, each with a code and a stored flag.
The stored flag
Every failed record tells you whether the event was saved to the database:
stored: true— The event IS in the system (withcost: null). Do NOT retry — retrying will create a duplicate. Instead, fix the root cause (map the model in the dashboard) and the event will be backfilled automatically.stored: false— The event was NOT saved. Safe to retry after fixing the issue.
Error codes
| Code | Stored? | What happened | What to do |
|---|---|---|---|
NEEDS_COST_BACKFILL | Yes | The model + modelProvider combination isn’t in the pricing table. The event is saved with usageCost: null. | Go to the dashboard → Usage Events → “Needs attention” → map the model to a known one. Once mapped, cost is calculated retroactively and all future events with that model auto-resolve. |
INTERNAL_ERROR | No | Something unexpected broke on our side during event processing. | Safe to retry. If it keeps happening, contact support with the rawEventId from the response. |
VALIDATION_ERROR | No | A required field is missing or has the wrong type (e.g., modelProvider not provided, inputTokens is negative). | Read the error message to see which field failed. Fix the request and resend. |
Example: a batch with one success and one backfill
200 for both.
See usage-events.md for the full endpoint documentation and mapping workflow.
Still stuck?
If none of the above match what you’re seeing, emailteam@marginfront.com with:
- The exact curl command you ran (API key REDACTED)
- The full response status and body
- What you expected to happen

