Why Asymmetric Request Signing?

OpenFX moves millions of dollars through its API every day. A simple API key in a header is not sufficient for financial infrastructure at this scale. Every request to the OpenFX API requires three-part authentication that provides:
  • Caller identity — Who is making this request?
  • Request integrity — Has the request been tampered with in transit?
  • Replay protection — Is this a legitimate, fresh request or a replay of a captured one?
  • Non-repudiation — The caller cannot deny having made the request, because only they hold the private key.
Because OpenFX uses asymmetric signing (Ed25519), your private key never leaves your infrastructure. You sign requests locally, and OpenFX verifies them using your registered public key. The server never sees or stores your private key.
OpenFX’s authentication model replaced Hawk-style MAC signing to improve developer experience while maintaining the same security guarantees. Modern Ed25519 libraries are available in every major language.

Three Components, All Required

Every API request must include all three authentication components. They work together using AND semantics — if any one is missing or invalid, the request is rejected with a 401 status and error type authentication_error.
ComponentHeaderPurpose
Bearer TokenAuthorization: Bearer <api_key>Identifies the caller and determines organization scope.
Request SignatureX-Signature: <base64_signature>Ed25519 (or RSA-SHA256) signature over the request payload. Proves integrity and non-repudiation.
TimestampX-Timestamp: <unix_seconds>Unix timestamp of when the request was signed. Must be within 60 seconds of server time.
   Your Application                              OpenFX API
   ================                              ==========

   1. Build signing payload
      (verb + path + timestamp + body)

   2. Sign with Ed25519 private key

   3. Send request with all 3 headers:
      Authorization: Bearer <api_key>     --->    4. Validate API key (identity)
      X-Signature: <base64_signature>     --->    5. Verify signature (integrity)
      X-Timestamp: <unix_seconds>         --->    6. Check timestamp (replay)

                                                  7. All three pass? Execute request.
                                          <---    8. Return response.
All three headers must be present on every request. A valid API key alone is not sufficient. A valid signature without a timestamp will be rejected. There are no exceptions or bypass mechanisms.

Quick Example

Here is a complete authenticated request to list entities:
curl -X GET "https://sandbox.api.openfx.com/v1/entities?limit=10" \
  -H "Authorization: Bearer ofx_sk_sandbox_abc123def456" \
  -H "X-Signature: aG9sZGVyLXNpZ25hdHVyZS1leGFtcGxlLi4u..." \
  -H "X-Timestamp: 1740500000" \
  -H "Content-Type: application/json"
The X-Signature value is a Base64-encoded Ed25519 signature computed over:
GET\n/v1/entities?limit=10\n1740500000\n
For POST requests with a JSON body, the body is included as the fourth component of the signing payload. See Request Signing for the full step-by-step process with code examples.

Authorization Model

OpenFX uses a simple role-based authorization model derived from your API key credentials. There are no separate OAuth scopes, tokens, or permission grants to manage.
RolePermissionsUse Case
readGET operations on all resourcesDashboards, reporting, reconciliation
writeAll operations (GET, POST, PATCH, DELETE)Full API access for payment operations
Follow the principle of least privilege. If a service only needs to read data for reporting or reconciliation, issue it a read-only API key. Reserve write keys for services that create payments, entities, or other state-changing operations.
Your API key’s role is assigned when the key is created in the OpenFX Dashboard or via onboarding. The role cannot be changed after creation — to change permissions, create a new key and revoke the old one.

Error Responses

When authentication fails, OpenFX returns a 401 status with a structured error body:
{
  "error": {
    "type": "authentication_error",
    "code": "invalid_signature",
    "message": "The X-Signature header contains an invalid Ed25519 signature for the given request payload.",
    "status": 401,
    "requestId": "req_01953e1a5f4b7abc",
    "retryable": false
  }
}
Common authentication error codes:
CodeMeaning
missing_credentialsOne or more required authentication headers are absent.
invalid_api_keyThe API key in the Authorization header is not recognized or has been revoked.
invalid_signatureThe X-Signature does not match the expected signature for the request payload.
timestamp_out_of_rangeThe X-Timestamp is more than 60 seconds from server time.
key_revokedThe API key has been explicitly revoked.
If you receive timestamp_out_of_range errors, check that your server’s clock is synchronized via NTP. Clock drift is the most common cause of authentication failures in production.

Environments

OpenFX provides two fully isolated environments with separate credentials:
EnvironmentBase URLAPI Keys
Sandboxhttps://sandbox.api.openfx.com/v1Prefixed ofx_sk_sandbox_
Productionhttps://api.openfx.com/v1Prefixed ofx_sk_live_
Sandbox and production use different API keys and different Ed25519 key pairs. A sandbox key will not authenticate against production, and vice versa.
Before going to production, verify that your signing implementation works in sandbox first. The authentication mechanism is identical in both environments — only the credentials differ.

Next Steps