Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/pacifica-fi/docs-migrate/llms.txt

Use this file to discover all available pages before exploring further.

Pacifica’s API uses standard HTTP status codes for REST responses and a parallel numeric code system for WebSocket action results. Understanding the distinction between transport-level errors (HTTP status) and business-logic errors (422 with a code in the body) is the key to writing robust error-handling code.
When you receive a 422 Unprocessable Entity, always inspect the response body for the code field. That integer value tells you exactly which business rule was violated — far more precisely than the HTTP status alone.

HTTP Status Codes

These codes appear on every REST response. A 2xx response means the request was accepted and processed successfully.
CodeStatusMeaning
400Bad RequestThe request body is malformed, a required field is missing, or the signature is invalid.
403ForbiddenAccess denied — typically because the request originates from a restricted region.
404Not FoundThe requested resource or endpoint does not exist.
409ConflictThe request conflicts with the current state (e.g. duplicate order ID).
422Business Logic ErrorThe request is structurally valid but violates an exchange rule. See the business error codes below.
429Too Many RequestsCredit quota exhausted. Back off and retry. See Rate Limits.
500Internal Server ErrorUnexpected server-side error. Also returned when price or amount are not valid multiples of tick_size / lot_size.
503Service UnavailableServer is temporarily unable to handle requests.
504Gateway TimeoutThe upstream service did not respond in time.

Business Logic Errors (HTTP 422)

A 422 response body contains a numeric code that identifies the specific rule violation. These codes are stable across API versions and safe to match programmatically.
CodeNameDescription
0UNKNOWNAn unclassified business logic error.
1ACCOUNT_NOT_FOUNDThe specified account address does not exist on Pacifica.
2BOOK_NOT_FOUNDThe order book for the requested market symbol was not found. Check the symbol casing.
3INVALID_TICK_LEVELThe price is not a valid multiple of the market’s tick_size.
4INSUFFICIENT_BALANCEThe account does not have enough collateral to place this order or execute this withdrawal.
5ORDER_NOT_FOUNDThe referenced order ID does not exist or has already been filled/cancelled.
6OVER_WITHDRAWALThe withdrawal amount exceeds the available withdrawable balance.
7INVALID_LEVERAGEThe requested leverage is outside the allowed range for this market.
8CANNOT_UPDATE_MARGINThe margin mode cannot be changed while there is an open position in this market.
9POSITION_NOT_FOUNDNo open position exists for the specified account and market.
10POSITION_TPSL_LIMIT_EXCEEDEDThe number of TP/SL orders on this position has reached the maximum allowed.
A typical 422 response body looks like:
{
  "error": "Insufficient balance",
  "code": 4
}

WebSocket Error Codes

WebSocket action responses carry a numeric status code in the code field of the response envelope. A 200 indicates success; all other values signal a problem.
CodeNameDescription
200SUCCESS_CODEThe action was accepted and processed successfully.
400INVALID_REQUEST_CODEThe request message is malformed or missing required fields.
401INVALID_SIGNATURE_CODEThe signature attached to the action is invalid.
402INVALID_SIGNER_CODEThe signer (agent wallet or account) is not authorised for this action.
403UNAUTHORIZED_REQUEST_CODEThe account is not permitted to perform this action.
420ENGINE_ERROR_CODEThe matching engine encountered an error processing the action.
429RATE_LIMIT_EXCEEDED_CODECredit quota exhausted on this connection.
500UNKNOWN_ERROR_CODEAn unexpected error occurred.
A typical WebSocket error response looks like:
{
  "id": "req-001",
  "code": 401,
  "msg": "Invalid signature"
}

Handling Errors in Code

Wrap every API call in error handling that inspects both the HTTP status code and, for 422 responses, the body’s code field. The pattern below covers the most common cases:
import requests

def place_order(payload: dict, headers: dict) -> dict:
    response = requests.post(
        "https://api.pacifica.fi/api/v1/orders/create",
        json=payload,
        headers=headers,
    )

    if response.status_code == 200:
        return response.json()

    # Attempt to parse JSON error body
    try:
        body = response.json()
    except ValueError:
        body = {"error": response.text}

    if response.status_code == 400:
        raise ValueError(f"Bad request — check signature or payload: {body}")

    if response.status_code == 403:
        raise PermissionError(f"Forbidden — region may be restricted: {body}")

    if response.status_code == 422:
        code = body.get("code", 0)
        msg = body.get("error", "Business logic error")
        # Match on specific codes for structured handling
        if code == 4:
            raise RuntimeError(f"Insufficient balance: {msg}")
        if code == 5:
            raise RuntimeError(f"Order not found — already filled or cancelled: {msg}")
        if code == 3:
            raise ValueError(f"Invalid tick level — price is not a multiple of tick_size: {msg}")
        raise RuntimeError(f"Business logic error [{code}]: {msg}")

    if response.status_code == 429:
        # Caller should implement exponential back-off — see Rate Limits docs
        raise RuntimeError("Rate limit exceeded (429). Back off and retry.")

    if response.status_code >= 500:
        raise RuntimeError(f"Server error [{response.status_code}]: {body}")

    raise RuntimeError(f"Unexpected status {response.status_code}: {body}")
For WebSocket, inspect the code field in every action response envelope:
import json

def handle_ws_response(raw_message: str) -> None:
    msg = json.loads(raw_message)
    code = msg.get("code")

    if code == 200:
        print("Action succeeded:", msg)
        return

    if code == 401:
        raise ValueError("Invalid signature — re-check signing logic.")

    if code == 429:
        print("Rate limited over WebSocket — slow down.")
        return

    raise RuntimeError(f"WebSocket error [{code}]: {msg.get('msg', 'unknown error')}")

Signing-Specific 400 Errors

Malformed or expired signatures return HTTP 400 with one of these message strings in the body:
MessageCommon Causes
"Invalid signature"Not valid Base58; decoded bytes are not a valid Ed25519 signature
"Invalid message"Message has expired (timestamp + expiry_window < server_time); payload cannot be serialised to JSON
"Invalid public key"account field is not a valid Base58-encoded Ed25519 public key
"Verification failed"Signature is valid in form but does not match the message; wrong key was used, or the payload was modified after signing
The quickest way to eliminate signing errors is to use the Pacifica Python SDK, which handles key parsing, deterministic JSON serialisation, and Base58 encoding automatically. See Authentication for a full step-by-step breakdown of the manual signing process.

Build docs developers (and LLMs) love