Error messages and codes
Every error IDM returns carries a stable code (for example QUOTE_EXPIRED) and a request ID. People using the apps never see the code: they see the title and message in the table below. Developers receive the code, the HTTP status, an operator-facing message and the request_id.
Quote the request ID
When you report a problem, give the request ID shown with the error (or the X-Request-Id response header). Support can find exactly what happened from it. Never send passwords, secrets, full card details or one-time codes.
Signing in and access
INVALID_API_CREDENTIAL
| What people see | Not available: You do not have access to this. |
| Shown as | Message box |
| HTTP status | 401 |
| What it means | The API key ID is unknown, revoked or expired, the tenant is suspended, or a key was used in the wrong environment (a test key against production, a live key anywhere else). |
| What to do | Do not retry. Check which key and environment your integration uses; rotate the credential in IDM Admin if it was revoked. |
SIGNATURE_INVALID
| What people see | Not available: You do not have access to this. |
| Shown as | Message box |
| HTTP status | 401 |
| What it means | The request signature, its timestamp window or its nonce was rejected. detail.reason says which: signature, timestamp or nonce. |
| What to do | For timestamp, fix the clock (use NTP). For nonce, never reuse a nonce. For signature, check the canonical string: method, request URI, body, timestamp and nonce joined by new lines. |
TENANT_ACCESS_DENIED
| What people see | Not available: You do not have access to this. |
| Shown as | Message box |
| HTTP status | 403 |
| What it means | The resource belongs to another tenant, or the credential lacks the scope. IDM never says which, so the existence of other tenants' records is not disclosed. |
| What to do | Check the reference and the credential's scopes. Repeated denials from one credential are throttled. |
NOT_AUTHORISED
| What people see | Not available: You do not have access to this. |
| Shown as | Message box |
| HTTP status | 403 |
| What it means | The signed-in account does not hold the permission this action needs. |
| What to do | Ask an administrator who can grant the role. Hiding a menu item is never the control: the server checks every request. |
SCOPE_MISSING
| What people see | Not available: You do not have access to this. |
| Shown as | Message box |
| HTTP status | 403 |
| What it means | The credential or session is missing the operational scope this route needs. |
| What to do | Ask your tenant administrator to issue a credential with the scope (for example delivery.create). |
MFA_REQUIRED
| What people see | Verification required: Enter the code from your authenticator app to continue. |
| Shown as | Message box |
| HTTP status | 403 |
| What it means | The account must finish signing in with its authenticator app before it can act. |
| What to do | Enter the six-digit code from your authenticator app. If you lost the device, ask an administrator to reset your second factor. |
STEP_UP_REQUIRED
| What people see | Confirm it is you: Enter a fresh code from your authenticator app to continue. |
| Shown as | Message box |
| HTTP status | 403 |
| What it means | A sensitive action (pricing activation, emergency controls, credential issuance and similar) needs a fresh authenticator code. |
| What to do | Enter a fresh code from your authenticator app, then repeat the action. |
SESSION_EXPIRED
| What people see | Please sign in again: Your session has ended. Sign in to continue. |
| Shown as | Message box |
| HTTP status | 401 |
| What it means | The session ended: it was idle too long, reached its absolute lifetime or was revoked. |
| What to do | Sign in again. Nothing you had already saved is lost. |
AUTHENTICATION_FAILED
| What people see | Sign-in failed: The email or password is not right, or the account cannot sign in. Try again or contact your administrator. |
| Shown as | Under the field |
| HTTP status | 401 |
| What it means | The email and password did not match an account that can sign in. IDM gives the same answer for every failure on purpose. |
| What to do | Check the email and password. After several failures the account is locked for a while; ask your administrator if it stays locked. |
PARTNER_BLOCKED
| What people see | New deliveries are paused: Settle the outstanding platform fee to resume accepting work. Active deliveries are unaffected. |
| Shown as | Message box |
| HTTP status | 403 |
| What it means | The delivery company cannot take new work, usually because a platform fee is unpaid. Deliveries already under way continue. |
| What to do | Delivery companies: settle the outstanding fee in Platform fees. Tenants: choose another partner or wait for settlement. |
MODULE_DISABLED
| What people see | Not available right now: This option is currently switched off. |
| Shown as | Message box |
| HTTP status | 403 |
| What it means | The feature is switched off (for example Bulk Delivery, or a module under an emergency control). |
| What to do | Try again later or use the normal flow. Administrators can see why on the Emergency controls and System settings pages. |
RATE_LIMIT_EXCEEDED
| What people see | Too many requests: Please wait a moment and try again. |
| Shown as | Short notice |
| HTTP status | 429 |
| What it means | Too many requests from this tenant, credential, device or address in a short time. |
| What to do | Wait for the Retry-After seconds, then retry. Integrations should honour the RateLimit-* headers. |
REQUEST_EXPIRED
| What people see | Link expired: This delivery request has expired. |
| Shown as | Message box |
| HTTP status | 410 |
| What it means | The customer request, recipient link or tracking link has expired, was replaced or is not valid. Unknown and expired links get the same answer. |
| What to do | Ask the sender or delivery company for a new link. Senders can start a new request. |
Input, retries and duplicates
VALIDATION_FAILED
| What people see | Check the details: Some details are missing or not valid. |
| Shown as | Under the field |
| HTTP status | 400 |
| What it means | Some details are missing or not valid. detail names the fields. |
| What to do | Correct the highlighted fields and submit again. |
SERVER_CONTROLLED_FIELD
| What people see | Something went wrong: Something went wrong. Please try again. |
| Shown as | Message box |
| HTTP status | 422 |
| What it means | The request body contained a field only the server may set: fee, amount, distance, status, rider, assignment, zone, gateway, classification, tenant, delivery partner, pricing version or platform fee. |
| What to do | Remove the field. IDM calculates these values itself; sending them is an error so an integration never believes it set them. |
IDEMPOTENCY_KEY_REQUIRED
| What people see | Something went wrong: Something went wrong. Please try again. |
| Shown as | Message box |
| HTTP status | 400 |
| What it means | This action changes state and needs an Idempotency-Key header. |
| What to do | Send a new random key for each new intent, and the same key for every retry of that intent. |
IDEMPOTENCY_KEY_REUSED
| What people see | Something went wrong: Something went wrong. Please try again. |
| Shown as | Message box |
| HTTP status | 409 |
| What it means | The same idempotency key was sent with a different body. Nothing was executed. |
| What to do | Fix the client: one key per intent. Do not retry blindly. |
REQUEST_IN_FLIGHT
| What people see | Still working: Your request is being processed. |
| Shown as | Short notice |
| HTTP status | 409 |
| What it means | The first request with this idempotency key is still running. |
| What to do | Wait a second (Retry-After: 1) and retry with the same key; you will receive the original result. |
Locations and routes
LOCATION_NOT_SUPPORTED
| What people see | Location outside service area: This location is outside our service area. |
| Shown as | Message box |
| HTTP status | 422 |
| What it means | The location resolved, but it is outside every area IDM serves (or past the tenant's maximum distance). |
| What to do | Choose a location inside the service area. The delivery company can tell you where it delivers. |
LOCATION_NOT_CONFIRMED
| What people see | Location could not be confirmed: This location could not be confirmed. Please move the pin. |
| Shown as | Message box |
| HTTP status | 422 |
| What it means | The location is ambiguous: the pin sits on a boundary or the map data disagrees. |
| What to do | Move the pin a little, or pick the area again. |
LOCATION_VERIFICATION_FAILED
| What people see | Location verification failed: We could not confirm this location. Please try again. |
| Shown as | Message box |
| HTTP status | 422 |
| What it means | A technical failure stopped IDM checking the location (provider, database or timeout). |
| What to do | Try again in a moment. Nothing was saved. |
GEOGRAPHY_CONFLICT
| What people see | Boundary conflict: This boundary overlaps an active one. Review the boundary and try again. |
| Shown as | Message box |
| HTTP status | 409 |
| What it means | An administrator's boundary overlaps an active boundary. Overlaps are rejected when written, never repaired later. |
| What to do | Administrators: review the boundary in Geography and remove the overlap. |
ROUTING_UNAVAILABLE
| What people see | Route unavailable: We could not calculate the route right now. Please try again shortly. |
| Shown as | Message box |
| HTTP status | 503 |
| What it means | No approved routing provider could measure the road distance right now. |
| What to do | Try again shortly. Operators: see the Routing degraded runbook. |
Prices and quotes
QUOTE_EXPIRED
| What people see | Quote expired: This delivery quote has expired. Calculate a new quote. |
| Shown as | Message box · the screen reloads the latest state |
| HTTP status | 409 |
| What it means | The quote passed its expiry by the server's clock. An expired quote can never be confirmed. |
| What to do | Calculate a new quote. Never reuse the old fee. |
PRICING_UNAVAILABLE
| What people see | Pricing unavailable: We could not price this delivery right now. Please try again shortly. |
| Shown as | Message box |
| HTTP status | 503 |
| What it means | Pricing or routing failed and no approved fallback price applies. |
| What to do | Retry with backoff. Operators: check routing health and fallback prices. |
PRICING_CONFIGURATION_UNAVAILABLE
| What people see | Pricing unavailable: Pricing configuration unavailable for this delivery route. Please try again or contact the delivery company. |
| Shown as | Message box |
| HTTP status | 503 |
| What it means | No single valid distance multiplier is active for this route classification, so IDM refuses to price rather than guess. |
| What to do | Try again later or contact the delivery company. Administrators: check Distance multipliers for an active row covering now. |
PRICING_CONFIGURATION_CONFLICT
| What people see | Configuration conflict: This overlaps an active configuration. Review the dates and try again. |
| Shown as | Message box |
| HTTP status | 409 |
| What it means | A pricing or multiplier configuration overlaps one that is already active for the same scope and dates. |
| What to do | Administrators: adjust the effective dates or retire the active version first. |
VEHICLE_UNAVAILABLE
| What people see | Vehicle unavailable: This vehicle is currently unavailable for this delivery. |
| Shown as | Under the field · the screen reloads the latest state |
| HTTP status | 422 |
| What it means | This vehicle type cannot serve this delivery (company, area, load or status). |
| What to do | Choose another vehicle from the list the screen shows; the list is always live. |
Deliveries, offers and relays
INVALID_DELIVERY_STATE
| What people see | This has changed: This delivery has changed. Please review the latest details. |
| Shown as | Short notice · the screen reloads the latest state |
| HTTP status | 409 |
| What it means | The action is not allowed from the delivery's current state, usually because someone else changed it first. |
| What to do | Reload and look at the latest state before deciding again. |
DUPLICATE_JOB_INTENT
| What people see | This has changed: This delivery was already created. |
| Shown as | Short notice · the screen reloads the latest state |
| HTTP status | 409 |
| What it means | This delivery was already created from the same intent. |
| What to do | Use the existing delivery; no second one was made. |
EXTERNAL_REFERENCE_IN_USE
| What people see | Reference in use: This order reference is already linked to a delivery. |
| Shown as | Message box |
| HTTP status | 409 |
| What it means | Your external order reference is already linked to another delivery of your tenant. |
| What to do | Use a unique order reference, or look up the existing delivery. |
DELIVERY_ALREADY_ASSIGNED
| What people see | Delivery no longer available: This delivery has already been assigned. |
| Shown as | Screen refreshes · the screen reloads the latest state |
| HTTP status | 409 |
| What it means | Another rider accepted first. This is normal, not a fault. |
| What to do | Riders: nothing to do, the app returns to waiting for offers. |
OFFER_NO_LONGER_AVAILABLE
| What people see | Delivery no longer available: This delivery has already been assigned. |
| Shown as | Screen refreshes · the screen reloads the latest state |
| HTTP status | 409 |
| What it means | The offer expired by the server's clock or was replaced. |
| What to do | Riders: nothing to do, the app returns to waiting for offers. |
NO_ELIGIBLE_PARTNER
| What people see | No delivery partner available: No delivery partner can take this delivery right now. Please try again later. |
| Shown as | Message box |
| HTTP status | 422 |
| What it means | No delivery company satisfies coverage, vehicle, capacity and permission for this delivery right now. |
| What to do | Retry later. Tenants can widen their allowed partners; administrators can check partner status and coverage. |
RELAY_ALREADY_CLAIMED
| What people see | Relay already claimed: Another rider has taken this relay. |
| Shown as | Short notice · the screen reloads the latest state |
| HTTP status | 409 |
| What it means | Another rider took this relay first. |
| What to do | Riders: nothing to do, the app returns to idle. |
HANDOFF_VERIFICATION_FAILED
| What people see | Code did not match: Check the handoff code and try again. |
| Shown as | Under the field |
| HTTP status | 422 |
| What it means | The relay handoff code did not match. Repeated failures are limited and audited. |
| What to do | Check the code on the other rider's screen and try again, or ask them to show a new code. |
HDZE_ORDER_ALREADY_BATCHED
| What people see | This has changed: This delivery has changed. Please review the latest details. |
| Shown as | Short notice · the screen reloads the latest state |
| HTTP status | 409 |
| What it means | The delivery is already in a shared delivery route. |
| What to do | Reload to see the latest state. |
DUPLICATE_SEARCH
| What people see | This has changed: This delivery has changed. Please review the latest details. |
| Shown as | Short notice · the screen reloads the latest state |
| HTTP status | 409 |
| What it means | A rider search for this dispatch attempt already ran. |
| What to do | Reload to see the latest state. |
GPS_NOT_PERMITTED
| What people see | Location sharing stopped: Location is only shared during an active delivery. |
| Shown as | Screen refreshes |
| HTTP status | 403 |
| What it means | Location is accepted only while the rider holds an active delivery. |
| What to do | Nothing to do: the app stops sending location until the next delivery. |
Bulk Delivery
BULK_RECIPIENT_LIMIT
| What people see | Maximum of 5 recipients allowed: A Bulk Delivery includes two to five recipients. |
| Shown as | Message box |
| HTTP status | 422 |
| What it means | A Bulk Delivery has two to five recipients. Fewer or more are refused and nothing is created. |
| What to do | Send to between two and five people, or use a single delivery. |
BULK_RECIPIENTS_PENDING
| What people see | Waiting for recipients: Some recipients have not confirmed their delivery location yet. |
| Shown as | Message box |
| HTTP status | 409 |
| What it means | At least one recipient has not confirmed their delivery location. |
| What to do | Resend their link, wait, or remove them, then continue. |
BULK_QUOTE_CHANGED
| What people see | Quote updated: Your delivery quote has changed. Please review the updated quote before continuing. |
| Shown as | Message box · the screen reloads the latest state |
| HTTP status | 409 |
| What it means | A recipient's quote changed after you reviewed the total. |
| What to do | Review the updated quote, then confirm again. |
BULK_STATE_CHANGED
| What people see | Request changed: This delivery request has changed. Please refresh and try again. |
| Shown as | Message box · the screen reloads the latest state |
| HTTP status | 409 |
| What it means | The Bulk Delivery or one of its recipients changed since the screen last loaded. |
| What to do | Refresh and try again. |
BULK_CANCELLED
| What people see | Bulk Delivery cancelled: This Bulk Delivery has been cancelled. |
| Shown as | Message box · the screen reloads the latest state |
| HTTP status | 409 |
| What it means | The Bulk Delivery has been cancelled. |
| What to do | Start a new request if you still need the deliveries. |
BULK_CHILD_EXISTS
| What people see | This has changed: This delivery has changed. Please review the latest details. |
| Shown as | Short notice · the screen reloads the latest state |
| HTTP status | 409 |
| What it means | That recipient position already exists in this Bulk Delivery. |
| What to do | Reload to see the current recipients. |
Payments, fees and accounting
ACCOUNTING_PERIOD_EXISTS
| What people see | This has changed: This delivery has changed. Please review the latest details. |
| Shown as | Short notice · the screen reloads the latest state |
| HTTP status | 409 |
| What it means | The accounting period for that company and month already exists. |
| What to do | Reload; the period was created by an earlier run. |
ACCOUNTING_PERIOD_UNAVAILABLE
| What people see | Completion on hold: This delivery cannot be completed until the company account is checked. Contact IDM support. |
| Shown as | Message box |
| HTTP status | 503 |
| What it means | The company has no open accounting period to record the earning in, so completion is held rather than recorded wrongly. |
| What to do | Contact IDM support. Operators: see the Reconciliation finding runbook. |
PAYMENT_EVENT_ALREADY_SEEN
| What people see | This has changed: This delivery has changed. Please review the latest details. |
| Shown as | Short notice · the screen reloads the latest state |
| HTTP status | 409 |
| What it means | The payment provider event was already processed. |
| What to do | Nothing to do; the first delivery of the event counted. |
INVALID_PAYMENT_STATE
| What people see | This has changed: This delivery has changed. Please review the latest details. |
| Shown as | Short notice · the screen reloads the latest state |
| HTTP status | 409 |
| What it means | That payment change is not allowed from the payment's current state. |
| What to do | Reload to see the payment's latest state. |
PAYMENT_PROVIDER_UNAVAILABLE
| What people see | Payment not started: Paystack could not be reached, so nothing was charged. Please try again shortly. |
| Shown as | Message box |
| HTTP status | 503 |
| What it means | Paystack could not be reached, so no payment was started and nothing was charged. |
| What to do | Try again shortly. |
Platform and connection
NOT_FOUND
| What people see | Not found: This page or item could not be found. |
| Shown as | Message box |
| HTTP status | 404 |
| What it means | The page or item does not exist, or is not visible to you. |
| What to do | Check the link or reference. |
PAYLOAD_TOO_LARGE
| What people see | File too large: The upload is too large. Choose a smaller file. |
| Shown as | Under the field |
| HTTP status | 413 |
| What it means | The upload or request body is over the size limit. |
| What to do | Choose a smaller photo or file. |
REQUEST_TIMEOUT
| What people see | This is taking too long: Something went wrong. Please try again. |
| Shown as | Short notice |
| HTTP status | 503 |
| What it means | The request took longer than its time budget. |
| What to do | Try again. If it keeps happening, quote the request ID to support. |
RETRYABLE
| What people see | Please try again: Something went wrong. Please try again. |
| Shown as | Short notice |
| HTTP status | 503 |
| What it means | A short conflict inside the database (for example two changes at once). Nothing was half-done. |
| What to do | Retry once with the same idempotency key. |
INTERNAL_ERROR
| What people see | Something went wrong: Something went wrong. Please try again. |
| Shown as | Message box |
| HTTP status | 500 |
| What it means | An unexpected failure. The response holds only a request ID; details stay in IDM's logs. |
| What to do | Retry once. If it persists, report the request ID. |