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.
| Component | Header | Purpose |
|---|
| Bearer Token | Authorization: Bearer <api_key> | Identifies the caller and determines organization scope. |
| Request Signature | X-Signature: <base64_signature> | Ed25519 (or RSA-SHA256) signature over the request payload. Proves integrity and non-repudiation. |
| Timestamp | X-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.
| Role | Permissions | Use Case |
|---|
| read | GET operations on all resources | Dashboards, reporting, reconciliation |
| write | All 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:
| Code | Meaning |
|---|
missing_credentials | One or more required authentication headers are absent. |
invalid_api_key | The API key in the Authorization header is not recognized or has been revoked. |
invalid_signature | The X-Signature does not match the expected signature for the request payload. |
timestamp_out_of_range | The X-Timestamp is more than 60 seconds from server time. |
key_revoked | The 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:
| Environment | Base URL | API Keys |
|---|
| Sandbox | https://sandbox.api.openfx.com/v1 | Prefixed ofx_sk_sandbox_ |
| Production | https://api.openfx.com/v1 | Prefixed 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